Community
FBX Forum
Welcome to Autodesk’s FBX Forums. Share your knowledge, ask questions, and explore popular FBX topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Skinned animation rotated 90 degrees

4 REPLIES 4
Reply
Message 1 of 5
Anonymous
929 Views, 4 Replies

Skinned animation rotated 90 degrees

We're having some problems getting our skinned mesh animation to work correctly when converting an FBX to our own format. Whenever animation is applied, the model seems to rotate 90 degrees about the X axis. I'm sure it has to be something to do with either the PreRotation or the coordinate system conversion, but I'm not sure exactly what. The steps we go through are:

The FBX is saved out with Y-Up from 3DS Max. It contains a mesh which is skinned using CAT.

Each node has its original transformation stored as Translation, Rotation Quaternion and Scale, using the following code:

KTime kTime;
kTime.SetSecondDouble(0);
FbxAMatrix Transform = Node->EvaluateLocalTransform(kTime);
FbxVector4 Translation = Transform.GetT();
FbxQuaternion QuatRotation = Transform.GetQ();
FbxVector4 Angles = Transform.GetR();
FbxVector4 Scale = Transform.GetS();
NewNode->Translation = Translation;
NewNode->Translation = Translation;
NewNode->Translation = Translation;

NewNode->Rotation = QuatRotation;
NewNode->Rotation = QuatRotation;
NewNode->Rotation = QuatRotation;
NewNode->Rotation = QuatRotation;

NewNode->Scale = Scale;
NewNode->Scale = Scale;
NewNode->Scale = Scale;


So the transformations for each node are stored relative to the parent.

When evaluating the transformations for each node for the animations, we do the following:

// Evaluate the node at the given time
KTime kTime;
kTime.SetSecondDouble(Time);
FbxAMatrix Transform = m_pFBXNode->EvaluateLocalTransform(kTime);
FbxVector4 Translation = Transform.GetT();
FbxQuaternion QuatRotation = Transform.GetQ();
FbxVector4 Scale = Transform.GetS();

// Make the values relative to time of 0
kTime.SetSecondDouble(0);
FbxAMatrix Frame0Transform = m_pFBXNode->EvaluateLocalTransform(kTime);
FbxVector4 Frame0Translation = Frame0Transform.GetT();
FbxQuaternion Frame0QuatRotation = Frame0Transform.GetQ();
FbxVector4 Frame0Scale = Frame0Transform.GetS();

FbxAMatrix InverseFrame0Transform = Frame0Transform.Inverse();

FbxAMatrix RelativeTransform = InverseFrame0Transform * Transform;
Translation = RelativeTransform.GetT();
QuatRotation = RelativeTransform.GetQ();
Scale = Transform.GetS() - Frame0Scale;

Keyframe = (float)Translation;
Keyframe = (float)Translation;
Keyframe = (float)Translation;

Keyframe = (float)QuatRotation;
Keyframe = (float)QuatRotation;
Keyframe = (float)QuatRotation;
Keyframe = (float)QuatRotation;

Keyframe = (float)Scale;
Keyframe = (float)Scale;
Keyframe = (float)Scale;


This gets us the relative transformation from the frame 0 one. We do this so we can use additive blending on multiple animations.

We also store the inverse bind pose matrices for the bones as follows:


// Store the inverse bind pose matrix
FbxAMatrix globalMatrix;
Cluster->GetTransformMatrix(globalMatrix);

const FbxVector4 GeomTranslation = Mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot);
const FbxVector4 GeomRotation = Mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot);
const FbxVector4 GeomScaling = Mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot);
FbxAMatrix geomMatrix = FbxAMatrix(GeomTranslation, GeomRotation, GeomScaling);
globalMatrix *= geomMatrix;

FbxAMatrix bindPoseMatrix;
Cluster->GetTransformLinkMatrix(bindPoseMatrix);
bindPoseMatrix = bindPoseMatrix.Inverse() * globalMatrix;

// We need to transpose the matrix to get it into engine format
FbxMatrix tempMatrix(bindPoseMatrix);
FbxMatrix transposedBindPoseMatrix = tempMatrix.Transpose();

double* bindPoseMatrixData = (double*)transposedBindPoseMatrix;
array<float>^ invBindPoseMatrix = gcnew array<float>(16);
for(int arrayIndex = 0; arrayIndex < 16; ++arrayIndex)
{
invBindPoseMatrix = (float)bindPoseMatrixData;
}
NewBoneData->SetInvBindPoseMatrix(invBindPoseMatrix);


Then when we are rendering, we calculate the skinning matrices like so:

// Get the transformation for the bone
const MathsNS::Matrix4x4& boneTransform = pNodeInstance->GetTransform();

// Get the inverse transform for the original bone node
const MathsNS::Matrix4x4& invBoneTransform = CurrentMesh->m_BoneInvBindPoseMatrices;

// Set the shader parameter for this bone
boneMatrices.push_back(boneTransform * invBoneTransform);


Like I mentioned, the whole thing seems to work fine, and animates OK, but the mesh is rotated 90 degrees on the X axis. If we replace the last line with:


boneMatrices.push_back(Matrix4x4::Identity);


The mesh faces the correct way, so my thinking is that the inverse bind pose matrices and everything are OK, but the animation transformations or maybe the default pose transformations are not retrieved properly. When rendering, all mesh / bone node transformations are calculated by constructing the matrix from the transforms retrieved in the first code segment and multiplying by the relative transformation matrices constructed from the data in the second code segment.

Does anyone have any idea what we're doing wrong, or why we might be seeing this 90 degree rotation? I thought using EvaluateLocalTransform was supposed to take all of the Pre/Post rotation stuff into consideration. Maybe there's a step we've missed or something?

Thanks
4 REPLIES 4
Message 2 of 5
jiayang.xu
in reply to: Anonymous

There are two things looks suspicious:
1. "The FBX is saved out with Y-Up from 3DS Max." The default setting of 3DS Max is Z-up, so save it out with Y-up will introduce a 90 degree rotation on X axis, does that one considered properly?
2. "all mesh / bone node transformations are calculated by constructing the matrix from the transforms retrieved in the first code segment". Here the code calls EvaluateLocalTransform, then extract TRSQ from the matrix, and then combine them back to a matrix later when necessary. This matrix extraction and combination process looks vulnerable. Can you use the matrix from EvaluateLocalTransform directly?
Message 3 of 5
Anonymous
in reply to: Anonymous

I thought the FBX SDK was supposed to take the whole Y-Up / Z-Up conversion into account when using EvaluateLocalTransform. Does it not do this? It does seem to rotate everything when we export using Z-Up

I'll try using the matrix directly, but that will take a bit of time to modify the pipeline. If anyone has any other ideas, please let me know.

Cheers
Message 4 of 5
Anonymous
in reply to: Anonymous

I've tried exporting the matrix directly, and it still applies the 90 degree rotation, so I don't think it's that. The code is now:


// Evaluate the node at the given time
KTime kTime;
kTime.SetSecondDouble(Time);
FbxAMatrix Transform = m_pFBXNode->EvaluateLocalTransform(kTime);

for(int componentIndex = 0; componentIndex < 16; ++componentIndex)
{
Keyframe = (float)(((FbxDouble*)Transform));
}
Message 5 of 5
Anonymous
in reply to: Anonymous

I think I've found the problem. The engine was multiplying by the nodes transformation matrix as well as the skinning matrices. We needed to ignore the transformations on the mesh nodes that were skinned.

Thanks for your help.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report