## FBX SDK

Topic Options

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page

# Skinned animation rotated 90 degrees

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

191 Views, 4 Replies

04-17-2012 03:50 AM

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:

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:

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:

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

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:

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

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

# Re: Skinned animation rotated 90 degrees

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

04-17-2012 04:56 AM in reply to:
GoGo-Robot

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?

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?

# Re: Skinned animation rotated 90 degrees

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

04-17-2012 06:21 AM in reply to:
GoGo-Robot

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

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

# Re: Skinned animation rotated 90 degrees

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

04-17-2012 08:01 AM in reply to:
GoGo-Robot

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));

}

# Re: Skinned animation rotated 90 degrees

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

04-17-2012 12:38 PM in reply to:
GoGo-Robot

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.

Thanks for your help.