DirectX Part 4: Loading FBX Models

“Hey Ben”, you say, “these articles on DirectX are great!” (I know.) “But when you talked about vertices in your previous post, you had us hard-code an array of vertex information. I’m working with snooty artists who want to to use a graphical user interface to place thousands of triangles. Can I import a mesh from Maya?”

Fiiiiiiiiiiiiiiiiiiine.

Some AAA shit right here

Some AAA shit right here

Chances are, your artists save out to .FBX files. FBX is a proprietary format, owned by Autodesk (the guys who make Maya and Max — the tools 90% of game artists use to generate content). If you don’t have any tools/skills to create FBXes, you can download a shitty FBX of a squashed bell that I made (see a screenshot of bell in Maya viewport on the right).

Anyhow, so Autodesk are assholes, but they aren’t stupid, and they know nobody will use their formats if their formats aren’t easy for people to do stuff with. So they created an SDK for loading FBX files and giving you all the sexy data however you want it. You can download the SDK here and you can read the documentation here. It will give you libraries to compile against (probably located in C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\lib\vs2012\x64\release, with headers in C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\include) that parse FBXes into data. It’s free and you can use it in commercial products.

To get the FBX SDK set up in Visual Studio:

  • Download and install the SDK
  • In Visual Studio, right-click on your project > Properties > Configuration Properties > VC++ Directories > Include Directories, and add C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\include . Make sure you do it across debug+release configurations.
  • Right-click on your project > Properties > Configuration Properties > Linker > General > Additional Library Directories, and add C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\lib\vs2012\[x86/x64]\debug for debug configuration, C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\lib\vs2012\[x86/x64]\release for release configuration
  • Right-click on your project > Properties > Configuration Properties > Linker > Input, and add libfbxsdk.lib under “Additional Dependencies” (across debug+release!)
  • Copy C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\lib\vs2012\[x86/x64]\[debug/release]\libfbxsdk.dll into your project’s output directory for the appropriate x86/x64 and debug/release build.
  • You’ll probably want to add a reference to the .pdb containing debug information for the FBX SDK, C:\Program Files\Autodesk\FBX\FBX SDK\2014.1\lib\vs2012\x64\debug\libfbxsdk.pdb, via Tools > Options > Debugging > Symbols

Now that you’ve got access to the FBX SDK, you’re gonna write some code that looks like this:


#include <fbxsdk.h>
#include <vector>

struct MyVertex
{
   float pos[3];
};

FbxManager* g_pFbxSdkManager = nullptr;

HRESULT LoadFBX(std::vector* pOutVertexVector)
{
   if(g_pFbxSdkManager == nullptr)
   {
      g_pFbxSdkManager = FbxManager::Create();

      FbxIOSettings* pIOsettings = FbxIOSettings::Create(g_pFbxSdkManager, IOSROOT );
      g_pFbxSdkManager->SetIOSettings(pIOsettings);
   }

   FbxImporter* pImporter = FbxImporter::Create(g_pFbxSdkManager,"");
   FbxScene* pFbxScene = FbxScene::Create(g_pFbxSdkManager,"");

   bool bSuccess = pImporter->Initialize("C:\\MyPath\\MyModel.fbx", -1, g_pFbxSdkManager->GetIOSettings() );
   if(!bSuccess) return E_FAIL;

   bSuccess = pImporter->Import(pFbxScene);
   if(!bSuccess) return E_FAIL;

   pImporter->Destroy();

   FbxNode* pFbxRootNode = pFbxScene->GetRootNode();

   if(pFbxRootNode)
   {
      for(int i = 0; i < pFbxRootNode->GetChildCount(); i++)
      {
         FbxNode* pFbxChildNode = pFbxRootNode->GetChild(i);

         if(pFbxChildNode->GetNodeAttribute() == NULL)
            continue;

         FbxNodeAttribute::EType AttributeType = pFbxChildNode->GetNodeAttribute()->GetAttributeType();

         if(AttributeType != FbxNodeAttribute::eMesh)
            continue;

         FbxMesh* pMesh = (FbxMesh*) pFbxChildNode->GetNodeAttribute();

         FbxVector4* pVertices = pMesh->GetControlPoints();

         for (int j = 0; j < pMesh->GetPolygonCount(); j++)
         {
            int iNumVertices = pMesh->GetPolygonSize(j);
            assert( iNumVertices == 3 );

            for (int k = 0; k < iNumVertices; k++)             {                int iControlPointIndex = pMesh->GetPolygonVertex(j, k);

               MyVertex vertex;
               vertex.pos[0] = (float)pVertices[iControlPointIndex].mData[0];
               vertex.pos[1] = (float)pVertices[iControlPointIndex].mData[1];
               vertex.pos[2] = (float)pVertices[iControlPointIndex].mData[2];
               pOutVertexVector->push_back( vertex );
            }
         }

      }

   }
   return S_OK;
}

Although a lot of code, it’s not that bad! Here’s what it does:

  • Initialize the FBX loader and tell it what types of data to load (this is the FbxIOSettings, and you can use it to specifically load only meshes, only meshes + materials, etc.)
  • Load the file at C:\MyPath\MyModel.fbx and grab its root node (the “handle” to the FBX contents)
  • Go through each item in the FBX, and ignore any items that aren’t meshes
  • Make sure that every polygon in the mesh is a triangle! This is important because DirectX only draws triangles. Tell your artists to triangulate their meshes (or write something that auto-triangulates meshes here).
  • Copy over the data for the 3 vertices that make up the triangle into your pOutVertexVector

And once it’s all done, you can call LoadFBX(...), pass in a pointer to an empty vector, and you’ll come out with a vector of vertex positions!

Now, I’m leaving it to you to hook everything up. No code samples. It’s your chance to fly solo. Just remember these things!

  • Since you stored your vertex data in a std::vector, everything is contiguous memory. If you copy in myVertexVector.size() * sizeof(MyVertex) bytes starting from &myVertexVector[0] to the GPU, you’ll have a perfect array of positions!
  • Right now, your array holds nothing but vertex positions. Modify your pVertexLayout to match, or add the COLOR and SOME_MORE_DATA attributes from the previous example into your MyVertex and give them reasonable values.
  • And in your Render() loop, make sure that m_pDeviceContext->Draw(...) is told the correct amount of vertices to draw.
  • Don’t forget to change your vertex shader if you make any changes to the vertex layout!

Finally, if you don’t use the shitty-bell FBX attached up at the top of this post, take note. In its default state, DirectX will only draw polygons with an [X,Y] from [-1,-1] to [1,1] and with a Z from 0 to 1. Look through the vertices in your FBX and make sure everything is in that range!

And by the end of it all, here’s what you’ll see:

Wow, this image of a janky purple bell was worth all the hours I have spent following your tutorials, Ben!

Wow, Ben, this image of a janky purple bell was worth all the hours I have spent following your tutorials!

10 thoughts on “DirectX Part 4: Loading FBX Models

  1. Paul

    Thanks for the tutorial. the Autodesk FBX SDK doesn’t even explain how to use it remote well on even the basic level on how to load a model into a scene. Please continue with the tutorial series as there is a serious lack of information in this area especially in terms of loading and animating a model.

    Reply
  2. Drew

    This is what people really need,how to load .fbx models exported from maya and 3dsmax to DirectX,is it true fbx only exports 1 animation,if so how would you handle multiple animations?

    Reply
  3. Yannick

    Hii,

    This is really the tutorial I need for my project, but I just can’t figure this out. Could you email me the full source code? That would be really helpfull!

    Keep up the good work!

    Thanks in advance,

    Yannick

    Reply
  4. Mason

    thanks for that im currently working on finishing up a directx9 game for the masses and begining work on a more high end version for windows store and loading our assets in the windowsrt environment has been a hurdle but im sure with this we can move forward.

    Reply
  5. Thomas

    So how do you actually copy the vector to the vertex buffer? I lock it, then do memcpy(vertexLock, &myvertices[0], myvertices.size() * sizeof(Vertex)); And it still throws an error saying I have an access violation.

    Reply
    1. Thomas

      Fixed the above problem, stupid mistake. Having a problem now where it loads everything into the vertex buffer but nothing renders (or does but I can’t see it). What are you using for your view and projection transforms?

      Reply
  6. CrusaderJC

    I appreciate the help. I followed the instructions from Autodesk to the letter and it kept returning a corrupt file error. These instructions cleared that up.

    Reply
  7. JustinWeq

    @Drew
    is it true fbx only exports 1 animation

    No this is not true, I can say from experience that modern day .FBX formats support more then one animation.

    Reply

Leave a Reply to Paul Cancel reply

Your email address will not be published.