How can I import FBX animations using the FBX SDK?

I got the meshes loaded in correctly with all of their vertices, indices, UV's, and normals. I am just now trying to get the Animations working correctly. I have looked at the FBX SDK documentation with little help. If someone could just help me get started or point me in the right direction I would greatly appreciate it. I added some code so you can kinda get an idea of what I am doing. I should be able to place that code anywhere in the load FBX function and have it work.

//GETTING ANIMAION DATA
for(int i = 0; i < scene->GetSrcObjectCount<FbxAnimStack>(); ++i)
{
FbxAnimStack* lAnimStack = scene->GetSrcObject<FbxAnimStack>(i);

FbxString stackName = "Animation Stack Name: ";
stackName += lAnimStack->GetName();
string sStackName = stackName;

int numLayers = lAnimStack->GetMemberCount<FbxAnimLayer>();
for(int j = 0; j < numLayers; ++j)
{
FbxAnimLayer* lAnimLayer = lAnimStack->GetMember<FbxAnimLayer>(j);

FbxString layerName = "Animation Stack Name: ";
layerName += lAnimLayer->GetName();
string sLayerName = layerName;

queue<FbxNode*> nodes;

FbxNode* tempNode = scene->GetRootNode();

while(tempNode != NULL)
{
FbxAnimCurve* lAnimCurve = tempNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X);

if(lAnimCurve != NULL)
{
//I know something needs to be done here but I dont know what.
}

for(int i = 0; i < tempNode->GetChildCount(false); ++i)
{
nodes.push(tempNode->GetChild(i));
}

if(nodes.size() > 0)
{
tempNode = nodes.front();
nodes.pop();
}
else
{
tempNode = NULL;
}
}
}
}


Here is the full function

bool FBXLoader::LoadFBX(ParentMeshObject* _parentMesh, char* _filePath, bool _hasTexture)
{
FbxManager* fbxManager = FbxManager::Create();
if(!fbxManager)
{
printf( "ERROR %s : %d failed creating FBX Manager!\n", __FILE__, __LINE__ );
}

FbxIOSettings* ioSettings = FbxIOSettings::Create(fbxManager, IOSROOT);
fbxManager->SetIOSettings(ioSettings);

FbxString filePath = FbxGetApplicationDirectory();

FbxScene* scene = FbxScene::Create(fbxManager, "");

int fileMinor, fileRevision;
int sdkMajor, sdkMinor, sdkRevision;
int fileFormat;

FbxManager::GetFileFormatVersion(sdkMajor, sdkMinor, sdkRevision);
FbxImporter* importer = FbxImporter::Create(fbxManager, "");

{
//Unrecognizable file format. Try to fall back on FbxImorter::eFBX_BINARY
}

bool importStatus = importer->Initialize(_filePath, fileFormat, fbxManager->GetIOSettings());
importer->GetFileVersion(fileMinor, fileMinor, fileRevision);

if(!importStatus)
{
printf( "ERROR %s : %d FbxImporter Initialize failed!\n", __FILE__, __LINE__ );
return false;
}

importStatus = importer->Import(scene);

if(!importStatus)
{
printf( "ERROR %s : %d FbxImporter failed to import the file to the scene!\n", __FILE__, __LINE__ );
return false;
}

FbxAxisSystem sceneAxisSystem = scene->GetGlobalSettings().GetAxisSystem();
FbxAxisSystem axisSystem( FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eLeftHanded );

if(sceneAxisSystem != axisSystem)
{
axisSystem.ConvertScene(scene);
}

TriangulateRecursive(scene->GetRootNode());

FbxArray<FbxMesh*> meshes;
FillMeshArray(scene, meshes);

unsigned short vertexCount = 0;
unsigned short triangleCount = 0;
unsigned short faceCount = 0;
unsigned short materialCount = 0;

int numberOfVertices = 0;
for(int i = 0; i < meshes.GetCount(); ++i)
{
numberOfVertices += meshes[i]->GetPolygonVertexCount();
}

Face face;
vector<Face> faces;
int indicesCount = 0;

int ptrMove = 0;

float wValue = 0.0f;

if(!_hasTexture)
{
wValue = 1.0f;
}

for(int i = 0; i < meshes.GetCount(); ++i)
{
int vertexCount = 0;
vertexCount = meshes[i]->GetControlPointsCount();
if(vertexCount == 0)
continue;

VertexType* vertices;
vertices = new VertexType[vertexCount];

int triangleCount = meshes[i]->GetPolygonVertexCount() / 3;
indicesCount = meshes[i]->GetPolygonVertexCount();

FbxVector4* fbxVerts = new FbxVector4[vertexCount];
int arrayIndex = 0;
memcpy(fbxVerts, meshes[i]->GetControlPoints(), vertexCount * sizeof(FbxVector4));

for(int j = 0; j < triangleCount; ++j)
{
int index = 0;
FbxVector4 fbxNorm(0, 0, 0, 0);
FbxVector2 fbxUV(0, 0);
bool texCoordFound = false;
face.indices[0] = index = meshes[i]->GetPolygonVertex(j, 0);
vertices[index].position.x = (float)fbxVerts[index][0];
vertices[index].position.y = (float)fbxVerts[index][1];
vertices[index].position.z = (float)fbxVerts[index][2];
vertices[index].position.w = wValue;
meshes[i]->GetPolygonVertexNormal(j, 0, fbxNorm);
vertices[index].normal.x = (float)fbxNorm[0];
vertices[index].normal.y = (float)fbxNorm[1];
vertices[index].normal.z = (float)fbxNorm[2];
texCoordFound = meshes[i]->GetPolygonVertexUV(j, 0, "map1", fbxUV);
vertices[index].texture.x = (float)fbxUV[0];
vertices[index].texture.y = (float)fbxUV[1];

face.indices[1] = index = meshes[i]->GetPolygonVertex(j, 1);
vertices[index].position.x = (float)fbxVerts[index][0];
vertices[index].position.y = (float)fbxVerts[index][1];
vertices[index].position.z = (float)fbxVerts[index][2];
vertices[index].position.w = wValue;
meshes[i]->GetPolygonVertexNormal(j, 1, fbxNorm);
vertices[index].normal.x = (float)fbxNorm[0];
vertices[index].normal.y = (float)fbxNorm[1];
vertices[index].normal.z = (float)fbxNorm[2];
texCoordFound = meshes[i]->GetPolygonVertexUV(j, 1, "map1", fbxUV);
vertices[index].texture.x = (float)fbxUV[0];
vertices[index].texture.y = (float)fbxUV[1];

face.indices[2] = index = meshes[i]->GetPolygonVertex(j, 2);
vertices[index].position.x = (float)fbxVerts[index][0];
vertices[index].position.y = (float)fbxVerts[index][1];
vertices[index].position.z = (float)fbxVerts[index][2];
vertices[index].position.w = wValue;
meshes[i]->GetPolygonVertexNormal(j, 2, fbxNorm);
vertices[index].normal.x = (float)fbxNorm[0];
vertices[index].normal.y = (float)fbxNorm[1];
vertices[index].normal.z = (float)fbxNorm[2];
texCoordFound = meshes[i]->GetPolygonVertexUV(j, 2, "map1", fbxUV);
vertices[index].texture.x = (float)fbxUV[0];
vertices[index].texture.y = (float)fbxUV[1];

faces.push_back(face);
}

meshes[i]->Destroy();
meshes[i] = NULL;

int indexCount = faces.size() * 3;
unsigned long* indices = new unsigned long[faces.size() * 3];
int indicie = 0;
for(unsigned int i = 0; i < faces.size(); ++i)
{
indices[indicie++] = faces[i].indices[0];
indices[indicie++] = faces[i].indices[1];
indices[indicie++] = faces[i].indices[2];
}
faces.clear();
}

return true;
}

• Take a look at the ViewScene SDK example - it has the code for loading and playing animations. – Jovan Jul 19 '13 at 15:24

The FBX documentation is painful at times, and this is definitely one of them.

There are two ways I've used to access animation data. The first is used in the ImportScene sample that comes with the SDK, and it's the way you seem to be trying to do things. In your sample, now that you have a valid lAnimCurve, you would need to query the number of keyframes that are stored in that curve, and then access them one at a time. It's a fairly complex process, I would refer you to the DisplayAnimation.cxx file in the ImportScene sample to see how they do it.

The problem with this is that you then will need to go through and determine any missing information. In the animation I'm working with, I have keyframe data for frame 0, 35, and 70. So now I would need to determine if the interpolation is linear or cubic, which involves more complicated and error-prone programming.

I also don't know at this point how fast the animation runs - 30fps, 24fps, 60fps, or some custom number - so even though I know I have 70 frames, I don't actually know how long the animation is supposed to last.

Instead, I would suggest digging into the KFbxAnimEvaluator class. This makes life much easier, because it will figure out all sorts of animation stuff for you. Really, that's the SDK page to keep an eye on.

So here's some sample code for how I break the times down. Assume lAnimStackCount is the number of animation stacks my file has.

for(i = 0; i < lAnimStackCount; i++) {
KFbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo();

KTime start = lTakeInfo->mLocalTimeSpan.GetStart();
KTime end = lTakeInfo->mLocalTimeSpan.GetStop();

// now you know how many seconds the animation runs, and can figure out how many
// keyframes you need. I usually export animations as 30fps
}


From here, you can use the GetNodeLocalTransform() function in KFbxAnimEvaluator to get the transform matrix at specific times. It will give you a final answer matrix that you can pull the TRS info out of.

I know that's vague, but my specific code is not on this computer. Hopefully it's high-level enough to help though.