|
Tell us what you think of the site.
|
Autodesk Media & Entertainment User Community
|
Autodesk® 3ds Max®
|
|
Autodesk® Maya®
|
|
Autodesk® Softimage®
|
|
Autodesk® MotionBuilder®
|
|
Autodesk® Mudbox™
|
|
Autodesk® ImageModeler™
|
|
Autodesk® Sketchbook® Pro
|
|
Autodesk® Smoke on Mac®
|
| Still can't get skeleton's bind pose
|
|
|
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.
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
Howdy,
Well, I seem to be making some progress:

… 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 *j, KFbxNode *n, KFbxXMatrix 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();
KFbxSkin* lSkinDeformer = reinterpret_cast<KFbxSkin*>(pMesh->GetDeformer(0, KFbxDeformer::eSKIN));
int lClusterCount = lSkinDeformer->GetClusterCount();
for( int i= 0 ; i < lClusterCount; i ++ )
{
KFbxCluster* pCluster = lSkinDeformer->GetCluster(i);
KFbxNode* lLinkNode = pCluster->GetLink();
if(lLinkNode)
{
KFbxXMatrix lClusterGlobalInitPosition;
pCluster->GetTransformLinkMatrix( lClusterGlobalInitPosition );
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
|
|
|
|
|
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
|
|
|
|
|
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::LeftHanded) GePrint("Left Handed");
else GePrint("Right Handed");
Adios,
Cactus Dan
|
|
|
|
Howdy,
Aha! I think I may have something here:

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
|
|
|
|
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.
|
|
|
|