FBX SDK: How to get Bind Pose

Started by
6 comments, last by texel3d 15 years, 4 months ago
Hi, i try to convert skinned mesh models from .fbx files to my own file format using the FBX SDK. I have a test file made with Maya: http://texel3d.free.fr/bugs/ReverseSkinMeshCyl.fbx it's just 3 bones ( +1 because maya add an additionnal bone, i don't know why) which turn at 90 degree. See the great picture below: http://texel3d.free.fr/bugs/fbx_bindpos.jpg I know how to get vertices, skeleton hierarchy and orientations of bones in the animated sequence (for each key) but my problem is that i don't know how to get Bind Pose of bones. The animation of this .fbx file work very well with the ViewScene example program of the SDK and i use the ImportScene example program to view where i can find the bind pose info. Somewhere i should find something like: 0 0 0 for joint1 0 0 90 for joint2 0 0 90 for joint3 But where ? Thanks.
Advertisement
Quote:Original post by texel3d
Somewhere i should find something like:
0 0 0 for joint1
0 0 90 for joint2
0 0 90 for joint3
But where ?


Nowhere. What you'd *like* to have from fbx is very different from what you actually get! IIRC, the bind pose is stored as a pose clip (or something like that), and it actually contains the inverse world matrices of all the joints. This means you are completely out of luck if you're after rotation information. You can extract the rotation, but be sure to remove the pre and post rotations from the matrix before converting to a quat.

The extraction of the bind poses is handled by the ViewScene demo, so it's worth digging through that source code to find it - but you are basically hunting for a single matrix per bone - which IIRC is applied when it calculate the matrices for rendering the skinned mesh data. It's been a while though....

I've not at my usual PC at the moment, otherwise I'd go and find some more useful info for you. Hope the above helps get you going anyway. (p.s. every so often, you'll find an fbx file that doesn't have a bind pose in it at all. At that point you just have to 'invent' a bind pose and hope for the best - the first keyframe is usually a good bet).
i am lost :(

i have read examples of the SDK and all data i get as a possible bind pose seem to be "wrong" (different from what i expect).
Do you have any ideas ?
Quote:Original post by texel3d
i am lost :(

i have read examples of the SDK and all data i get as a possible bind pose seem to be "wrong" (different from what i expect).
Do you have any ideas ?


The bind poses are stored as inverse world space transform matrices.
Invert them, and you'll have world space TM's.
Multiply by the parents inverse TM's and you'll get the local space matrices.
Extract the translation direct from the matrix.
Extract the scale by getting the length of each axis. You can skip this if you aren't animating scale.
Convert the matrix to a quaternion, and you'll get the combined PreRotate * Rotate * PostRotate.
Pre and Post multiply the inverse Pre/Post rotate quats you get from the FBX sdk and you'll be able to extract the actual rotation values.

After all of that, you might start thinking that Fbx can be a pain in the arse, and i might agree with you.....
Thanks. I will do some tests.
Do you get the Bind pose of bones from the mesh using:
lCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
I can't find the solution. I have used a new file with 4 bones instead of 3.
You can see the bind Pose of it on this picture:
http://texel3d.free.fr/bugs/Bone.JPG

In Maya, bones rotate around X axis for joint2 and joint3, and around Z axis for joint3
Bones rotate in order to align all bones.
In animation keys of the fbx file: all rotation are around the Z axis. I think it's because of Pre rotation.

PreRotation (found in the FBX file):
joint1: 0,0,0
joint2: 0,0,90
joint3: -180,-90,90
joint4: 0,0,-90
joint5: 0.868,90,90 (not visible. Added by Maya)

I get Pre Rotation from Skeleton nodes:
bone.vec4PreRotation = i_Node->GetPreRotation(KFbxNode::eSOURCE_SET);

I get Bind Matrices from cluster stored in mesh nodes:
cluster->GetTransformLinkMatrix(bone.bindMatrix);

To get the local bind matrix i compute it using inverse matrices as you tell me:
m_vBones[bone]->MatrixBindLocal = m_vBones[bone]->MatrixBind.Inverse() * m_vBones[bone]->Parent->MatrixBind.Inverse();

After i compute the final Bind-Pose and i transform a point at coord (0,1,0) to test this matix:

GLGXMATRIX matrixPreRotation;
GLGXQUATERNION quat;
GLGXQuaternionRotationYawPitchRoll(&quat,
GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[1]),
GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[0]),
GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[2]));
GLGXMatrixRotationQuaternion(&matrixPreRotation,&quat);

GLGXVECTOR3 vec3Source(0.0f,1.0f,0.0f);
GLGXVECTOR3 vec3Dest;
GLGXMatrixMultiply(&matrix,&m_vBones[BoneID]->MatrixBindLocal,&matrixPreRotation);
GLGXVec3TransformCoord(&vec3Dest,&vec3Source,&matrix);

For joint1,joint2,joint3,joint4 it seems to work because i get:
joint1: (0,1,0)
joint2: (1,0,0)
joint3: (0,-1,0)
joint4: (0,1,0)

And should find:
joint1: (0,1,0)
joint2: (0,0,1)
joint3: (0,-1,0)
joint4: (1,0,0)

I don't use Post Rotation in my computation because it is always at zero.
What is wrong ?

Note: I don't use translation and scale for the time beeing.
Quote:In animation keys of the fbx file: all rotation are around the Z axis. I think it's because of Pre rotation.


In Maya it's called jointOrient, but yes it will be because of that. In DCC packages it ensures that the rotation axes are nicely aligned down the joints.

Quote:I get Pre Rotation from Skeleton nodes:
bone.vec4PreRotation = i_Node->GetPreRotation(KFbxNode::eSOURCE_SET);


Spot on. You might also want to get the post rotation which can be applied occasionally in maya files (it's the RotateAxes attribute in maya xforms). It's not that common though. You can get away with an assert on the values to ensure it is always 0. It'll probably assert in a year or two's time....

Quote:To get the local bind matrix i compute it using inverse matrices as you tell me:

Which is not quite what i told you ;)

m_vBones[bone]->MatrixBindLocal = m_vBones[bone]->MatrixBind.Inverse() * m_vBones[bone]->Parent->MatrixBind();


BTW, Where did you get the YXZ rotation order from?
GLGXQuaternionRotationYawPitchRoll(&quat,	GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[1]),	GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[0]),	GLGXToRadian(m_vBones[BoneID]->vec4PreRotation.mData[2]));

Quote:
m_vBones[bone]->MatrixBindLocal = m_vBones[bone]->MatrixBind.Inverse() * m_vBones[bone]->Parent->MatrixBind();

I will try that tomorrow (i have not my PC)

Quote:
BTW, Where did you get the YXZ rotation order from?

I get Y,X,Z value from the vector4 PreRotation.
I use Y,X,Z order because my function need Yaw,Pitch,and Roll

GLGXQUATERNION * GLGXQuaternionRotationYawPitchRoll(GLGXQUATERNION * out,float yaw,float pitch,float roll){	GLGXVECTOR3 vx = GLGXVECTOR3(1.0f,0.0f,0.0f);	GLGXVECTOR3 vy = GLGXVECTOR3(0.0f,1.0f,0.0f);	GLGXVECTOR3 vz = GLGXVECTOR3(0.0f,0.0f,1.0f);	GLGXQUATERNION qx, qy, qz;	GLGXQuaternionRotationAxis(&qx,&vx,pitch);	GLGXQuaternionRotationAxis(&qy,&vy,yaw);	GLGXQuaternionRotationAxis(&qz,&vz,roll);	GLGXQuaternionMultiply(out,&qx,&qy);	GLGXQuaternionMultiply(out,out,&qz);	return out;}


Sorry if my english is not perfect.

I also make a mistake in my previous post. When i transform my vector (0,1,0) I should find:
joint1: (0,1,0)
joint2: (0,0,1)
joint3: (0,0,1)
joint4: (1,0,0)


This topic is closed to new replies.

Advertisement