Inside Sabertooth
Learn how Sabertooth uses 3ds Max to create 3D interactive projects, including HBO Go’s Game of Thrones interactive experience
  • 1/3
You are here: Forum Home / Autodesk® FBX® / FBX SDK / Still can't get skeleton's bind pose
  RSS 2.0 ATOM  
2 pages: 1.2 first

Still can't get skeleton's bind pose
Rate this thread
 
49501
 
Permlink of this thread  
avatar
  • TravF
  • Posted: 17 November 2010 01:24 PM

This is why I think KFbxSkin doesn’t contain enough information for a bindpose.  For example, take humanoid.fbx:

It has:
1 skin - 60 clusters
85 total nodes

A skin only contains links to nodes that influence the mesh.  For a complete bindpose, you need transforms
for all nodes, right?  The skin for humanoid.fbx only has 60 clusters.  That means 80-65 = 15 transforms are missing.

How are you going to transform nodes that don’t influence the mesh?  They won’t be listed.

I think maybe this is the purpose of KFbxPose.  Someone would have to explicitly write out the mesh bindpose
as a KFbxPose.  But, humanoid.fbx has no KFbxPoses.  So, I don’t think it’s possible with only KFbxSkin data.



Replies: 0
avatar

Howdy,

But wait, there has to be a bind pose for each cluster in the calculations from that function, or else it wouldn’t be able to deform the bind mesh from the t-pose to the default pose without a starting bind pose, right?

Adios,
Cactus Dan



Replies: 1
/img/forum/dark/default_avatar.png

In KFbxSkin, there’s a transform for each KFbxCluster, which contains a list of vertex weights.  But,
this is only enough information to transform vertices to skeleton, not the other way around. KFbxSkin
doesn’t contain links to nodes that don’t influence the mesh, and this is why I think a reverse
transformation attempt (skeleton to mesh) will fail.

Author: TravF

Replied: 19 November 2010 09:29 AM  
avatar
  • TravF
  • Posted: 19 November 2010 10:32 AM

I understand what you want.  You want a T-pose for the skeleton, just like the mesh.  I want a
T-pose too, but I haven’t figured out how to get it. :)

Ideally, a modeller setups their mesh/skeleton in T-pose, so the joints only have position,
no rotation.  With the intention that, if you set all joints to zero rotation, that will give
them a full range of motion when animation is playing.  And helps to avoid bad rotations,
like gimbal locking, strange pops and flips, and so forth.

So, you would think, I’ll just zero out the rotation for all nodes to get my T-pose.  But, that
probably won’t work half the time, as it depends on the how the skeleton was initially rigged
by the modeller.



Replies: 0
avatar

Howdy,

Well, I seem to be making some progress:
FBXBindPose3.jpg

… it’s the correct joint skeleton T-Pose, but I don’t know why it’s rotated -90º to the mesh.

The problem I was having before was in assuming that cycling through the clusters would be in the same order as cycling through the joints, so it was setting the global matrix of the foot before setting the global matrix of the leg, and so on. DOH!

So now here’s what I’m doing:

First I added a couple of more members to my structure:

struct JointNode
{
 BaseObject 
*joint// CD Joint
 
KFbxNode *node;
 
KFbxXMatrix matrix;
 
Bool cluster;
 
 
JointNode(BaseObject *jKFbxNode *nKFbxXMatrix kM)
 
{
 joint 
j;
 
node n;
 
matrix kM;
 
cluster FALSE;
 
}
}
;

… then in my routine to build the joint skeleton from the eSKELETON nodes, I go ahead and set the global matrix for them from the default take as they’re stored in the vector list:

KFbxXMatrix kM pNode->GetGlobalFromDefaultTake();
jointList.push_back(new JointNode(jnt,pNode,kM));
 
Matrix opM KFbxXMatrixToMatrix(kM);
jnt->SetMg(opM); // set joint's global matrix

… then I rewrote my extract bind pose function like this:

void CDImportFBXCommand::ExtractBindPoseFromSkinDeformer(KFbxNode *pNode)
{
 KFbxMesh 
*pMesh = (KFbxMesh*)pNode->GetNodeAttribute();

 
KFbxSkinlSkinDeformer reinterpret_cast<KFbxSkin*>(pMesh->GetDeformer(0KFbxDeformer::eSKIN));
 
 
int lClusterCount lSkinDeformer->GetClusterCount();
 for( 
int ilClusterCount++ )
 
{
 KFbxCluster
pCluster lSkinDeformer->GetCluster(i);
 
KFbxNodelLinkNode pCluster->GetLink();
 if(
lLinkNode)
 
{
 KFbxXMatrix lClusterGlobalInitPosition
;
 
pCluster->GetTransformLinkMatrixlClusterGlobalInitPosition );

 for(
vector<JointNode*>::iterator it=jointList.begin(); it != jointList.end(); it++)
 
{
 JointNode 
*jn = (*it);
 if(
lLinkNode == jn->node)
 
{
 jn
->cluster TRUE;
 
jn->matrix lClusterGlobalInitPosition// store cluster bind pose matrix
 
 
break;
 
}
 }
 }
 }
 
 
for(vector<JointNode*>::iterator it=jointList.begin(); it != jointList.end(); it++)
 
{
 JointNode 
*jn = (*it);
 
BaseObject *joint jn->joint;
 if(
jn->cluster)
 
{
 Matrix jntM 
KFbxXMatrixToMatrix(jn->matrix);
 
joint->SetMg(jntM); // set joint's global matrix
 
}
 }
}

Now all I need to find out is why the bind pose of the skeleton is rotated.

Any ideas?

Adios,
Cactus Dan



Replies: 1
/img/forum/dark/default_avatar.png

GetAxisSystem() reports that humanoid.fbx has been saved as KFbxAxisSystem::MayaZUp,
which may explain why the skeleton is aligned with your blue Z-axis.

And BTW, this may only work for humanoid.fbx, because of its unique skeleton structure.

Another skeleton from another file could have NULL or dummy nodes within the skeleton hierarchy,
(zero influence, no transforms listed) and this will mess up your bindpose.

Author: TravF

Replied: 19 November 2010 12:53 PM  
avatar

Howdy,

Hmmmm, here it’s printing out:
eUp = YAxis
upSign = 1
Right Handed

Here’s my code:

KFbxAxisSystem fbxAxis pScene->GetGlobalSettings().GetAxisSystem()// axis system of fbx scene
 
int upSign;
 
KFbxAxisSystem::eUpVector eUp fbxAxis.GetUpVector(upSign);
 switch (
eUp)
 
{
 
case KFbxAxisSystem::XAxis:
 
GePrint("eUp = XAxis; upSign = "+LongToString(upSign));
 break;
 case 
KFbxAxisSystem::YAxis:
 
GePrint("eUp = YAxis; upSign = "+LongToString(upSign));
 break;
 case 
KFbxAxisSystem::ZAxis:
 
GePrint("eUp = ZAxis; upSign = "+LongToString(upSign));
 break;
 
}
 
if(fbxAxis.GetCoorSystem() == KFbxAxisSystem::LeftHandedGePrint("Left Handed");
 else 
GePrint("Right Handed");

Adios,
Cactus Dan



Replies: 0
avatar

Howdy,

Aha! I think I may have something here:
FBXBindPose4.jpg

After taking another look at the View Scene example, I printed out some matrix values and noticed that the lReferenceGlobalInitPosition matrix always printed this:

{2.544,0,0,0}
{0
,0,2.544,0}
{0
,-2.544,0,0}
{0
,0,0,1}

... for every cluster.

I also printed out the result of GetGlobalFromDefaultTake() from the mesh node and it prints this:

{2.544,0,0,0}
{0
,2.544,0,0}
{0
,0,2.544,0}
{0
,0,0,1}

So, my conclusion was that the lReferenceGlobalInitPosition was the mesh’s bind matrix, which seems to be rotated -90º, and if I multiplied its inverse by the cluster’s bind matrix ( lClusterGlobalInitPosition ), I would get the cluster’s correct bind matrix in relation to mesh.

jn->matrix meshBindMatrix.Inverse() * clusterBindMatrix// store cluster bind matrix

Then since that would put the skeleton in the meshes coordinate space, for the mesh, instead of setting its matrix with GetGlobalFromDefaultTake(), I set it’s matrix with GetGeometry(pNode) so that its global scale is 1,1,1.

TravF

Another skeleton from another file could have NULL or dummy nodes within the skeleton hierarchy,
(zero influence, no transforms listed) and this will mess up your bindpose.

Actually, the humanoid.fbx file’s skeleton does have NULL and dummy nodes. So, what I did first, was to set all of the skeleton nodes to the default pose from the default take, so that each node was in its proper position relative to its parent node. Then cycled through the clusters and set the bind pose for those skeleton nodes that were linked to a cluster. It seems to work for several other fbx files as well. Maybe not every file will be correct, but I think I’m heading in the right direction.

Adios,
Cactus Dan



Replies: 0
avatar
  • TravF
  • Posted: 20 November 2010 10:59 AM

Looks good!

eUp = YAxis

Sorry, that’s correct.  I had a copy-paste typo in my debug output.  Working now.

Actually, the humanoid.fbx file’s skeleton does have NULL and dummy nodes.

It does have NULL nodes, but it doesn’t have any NULL nodes that have SKELETON-type nodes
as a parent, which is why I think you got lucky with humanoid.fbx.

If you have a skeleton like this:
SKELETON -> SKELETON -> NULL -> SKELETON

with a NULL node having a SKELETON parent, then your KFbxSkin bindpose may not work out correctly.



Replies: 0
2 pages: 1.2 first