# FbxSdk: Bone rotations differ from source file

This topic is 1035 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey guys,

I've spent a few days messing about with FBXSDK, here's where I'm at currently:

Got the meshes loaded (sorted into submeshes per material) with bone weights and indexes.

Bone hierarchy is also imported properly.

I calculate the inverse bindpose matrix by doing this:

FbxAMatrix transformMatrix;
FbxAMatrix globalBindPoseInverseMatrix;
lCluster->GetTransformMatrix(transformMatrix);
globalBindPoseInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix; // *matrixGeo;


When computing bone matrix to send to vertex shader, I do the following:

VOID Model::CalculateCombinedMatrix(Model_Animation *animdata)
{
for (INT b = 0; b < BoneListCount; b++)
{
ModelAnim_Bone *pBone = BoneList[b];
INT boneIndex = b;
while (pBone)
{
boneIndex = pBone->ParentIndex;
pBone = pBone->Parent;
}
XMStoreFloat4x4(&animdata->FinalMatrix[b], transformation);
}
}


(The "animdata" is a datablock for holding bone transformations and final matrices (I do this seperately from my Model class to allow single models to be used for multiple different "entities").

The Transform matrix computed like this:

...

if (ChannelList[channel]->Type == MDL_ANIMCHANNELTYPE_TRANSLATION)
vectorT = XMVectorLerp(vector0, vector1, i);
else if (ChannelList[channel]->Type == MDL_ANIMCHANNELTYPE_ROTATION)
vectorR = XMQuaternionSlerp(vector0, vector1, i);
//		vectorR = XMQuaternionNormalize(XMVectorLerp(vector0, vector1, i));
else if (ChannelList[channel]->Type == MDL_ANIMCHANNELTYPE_SCALING)
vectorS = XMVectorLerp(vector0, vector1, i);
}
return XMMatrixMultiply(XMMatrixMultiply(XMMatrixScalingFromVector(vectorS), XMMatrixRotationQuaternion(vectorR)), XMMatrixTranslationFromVector(vectorT));


My animation channel vector (vector0, vector1 is for the two keyframes to interpolate in between) is where I think it all goes wrong.

I'm doing it by resampling the FBX bone node using EvaluateLocalTransform(), and multiple animations (stacks) I handle by calling lScene->SetCurrentAnimationStack(pAnimStack) before evaluating the FbxAnimCurveNode.

INT numStacks = lScene->GetSrcObjectCount<FbxAnimStack>();
INT animationindex = 0;
for (INT stack = 0; stack < numStacks; stack++)
{
FbxAnimStack* pAnimStack = lScene->GetSrcObject<FbxAnimStack>(stack);
lScene->SetCurrentAnimationStack(pAnimStack);
FbxAnimCurveNode *pCurveNode = lBoneNode->LclRotation.GetCurveNode(pAnimStack);
if (pCurveNode)		// Rotation
{
FbxTimeSpan timespan;
pCurveNode->GetAnimationInterval(timespan);
FbxTime fbxduration = timespan.GetStop() - timespan.GetStart();
FLOAT duration = fbxduration.GetMilliSeconds() / 1000.0f;

...

// Sample the curve every 1/60th second
INT nkeys = (INT)(duration * 1000.0f / 60.0f);

...

FbxQuaternion lastlocalQ;
for (INT key = 0; key < nkeys; key++)
{
FLOAT keytime = ((FLOAT)key / (FLOAT)(nkeys - 1)) * duration;
FbxTime fbxkeytime;
fbxkeytime.SetMilliSeconds((FbxLongLong)(keytime * 1000.0f));
// IS THIS WRONG?
FbxAMatrix localtransform = lBoneNode->EvaluateLocalTransform(fbxkeytime);
FbxQuaternion localQ = localtransform.GetQ();
if (key > 0)
{
if (localQ.DotProduct(lastlocalQ) < 0)
localQ *= -1.0;
}
lastlocalQ = localQ;
pKeyList[key].Time = keytime;
pKeyList[key].Vector.x = (FLOAT)localQ.GetAt(0);
pKeyList[key].Vector.y = (FLOAT)localQ.GetAt(1);
pKeyList[key].Vector.z = (FLOAT)localQ.GetAt(2);
pKeyList[key].Vector.w = (FLOAT)localQ.GetAt(3);
}


The end result seems to look allright, except that my model (a simple snowman waving his arm) exaggerates the rotation so the arm bends all the way into his head. When I test my model in FBXViewer it's displayed properly, but the author's code is spaghetti code mixed with a grenade (totally unreadable for me, can't find where he does what as he's got many weirdly named functions etc.) so I cannot figure out where it goes wrong in my code. Plus FbxViewer and most other examples uses the FBXSDK functions and homemade quaternion functions etc. for alot of things, and I'm doing things manually using XMMath.

Snowman model if it's needed: https://dl.dropboxusercontent.com/u/9361906/snowman.7z

Here's how it looks (disregard half of the snowmen, they play a "bow" animation which seems to correspond to what I see in Blender when I'm modelling), you can see the arm intersecting the head:

##### Share on other sites

Ok I think I got it working as far as the rotation is concerned, but now the root bone offset translation is the problem...

How it looks in Blender (notice the offset stippled line going from the (0, 0, 0) origin to bone root):

And my result:

How can I move my root bone to reflect that?

Edit: Here's the matrix I use for the whole model as worldmatrix input to my vertex shader:

FbxNode *lNode = lMesh->GetNode();
FbxAMatrix globalMatrix = lNode->EvaluateGlobalTransform();

Edited by vinterberg

##### Share on other sites

Edit: Here's the matrix I use for the whole model as worldmatrix input to my vertex shader:

There isn’t a single matrix for the entire model. Every mesh instance has its own world matrix.

L. Spiro

##### Share on other sites

Yes, meant the matrix for my mesh of course - was tired and frustrated :D

1. 1
2. 2
3. 3
Rutin
19
4. 4
khawk
14
5. 5

• 9
• 11
• 11
• 23
• 12
• ### Forum Statistics

• Total Topics
633655
• Total Posts
3013187
×