Jump to content
  • Advertisement
Sign in to follow this  

FbxSdk: Bone rotations differ from source file

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

If you intended to correct an error in the post then please contact us.

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 transformLinkMatrix;
FbxAMatrix globalBindPoseInverseMatrix;
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++)
		XMMATRIX transformation = XMLoadFloat4x4(&BoneList[b]->BindPoseInverseMatrix);
		ModelAnim_Bone *pBone = BoneList[b];
		INT boneIndex = b;
		while (pBone)
			transformation = XMMatrixMultiply(transformation, XMLoadFloat4x4(&animdata->TransformationMatrix[boneIndex]));
			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);
	FbxAnimCurveNode *pCurveNode = lBoneNode->LclRotation.GetCurveNode(pAnimStack);
	if (pCurveNode)		// Rotation
		FbxTimeSpan 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));
	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 this post

Link to post
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 this post

Link to post
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 this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!