I'm trying to implement skeletal animation using FBX SDK and OpenGL(with glm).
First of all, let me show results.
Above is original mesh, without animation.
And this is the result.
My method to generate matrices is:
// joint is ordered by id, root id is 0
for (u8 i = 0; i < jointCount; ++i) {
auto track = mCurrAnimation->track(i); // track is a list of key frames, which contains translation(vec3) and rotation(quat)
auto& currKey = track->keys[mCurrKeyIndex]; // get current key frame
auto& nextKey = track->keys[mNextKeyIndex]; // get next key frame
auto& joint = mSkeleton->joints[i]; // get joint by id
auto t = glm::mix(currKey.t, nextKey.t, alpha); // lerp translation
auto q = glm::slerp(currKey.q, nextKey.q, alpha); // slerp rotation
auto skinTransform = glm::translate(glm::mat4{1.0f}, t);
skinTransform = skinTransform * glm::mat4_cast(q);
glm::mat4 parentSkinTransform{1.0};
if (joint.parentId > 0) { // if not root
parentSkinTransform = mJointMatrices[joint.parentId];
}
mJointMatrices[i] = parentSkinTransform * skinTransform; // to parent space
mSkinMatrices[i] = mJointMatrices[i] * joint.invBindPose; // inverse bind pose
}
I'm really struggling with this problem. As you can see, also left side of mesh is slightly distorted.
For more detail, these are how I got inverse bind pose and key frames from FBX.
// get joint inverse bind pose
if (const auto attrib = node->GetNodeAttribute();
attrib) {
const auto attribType = attrib->GetAttributeType();
if (attribType == FbxNodeAttribute::eSkeleton) {
CvtJoint cvtJoint{node->GetName(), id, parentId};
cvtJoint.invBindPose = makeMat4(node->EvaluateGlobalTransform().Inverse());
mCvtJointList.emplace_back(cvtJoint);
}
}
// get key frames
for (auto frameIndex = startCount; frameIndex < stopCount; ++frameIndex) {
FbxTime time{};
time.SetFrame(frameIndex, timeMode);
cvtAnimKey.time = static_cast<f32>(time.GetSecondDouble()); // get time of frame
auto transform = node->EvaluateGlobalTransform(time); // get global transform at time
if (const auto parent = node->GetParent(); // if node has parent
parent) {
auto parentTransform = parent->EvaluateGlobalTransform(time); // get parent global transform at time
transform = parentTransform.Inverse() * transform; // to local space
}
cvtAnimKey.t = makeVec3(transform.GetT()); // FbxVector4 -> glm::vec3
cvtAnimKey.q = makeQuat(transform.GetQ()); // FbxQuaternion -> glm::quat
cvtAnimTrack.keys.emplace_back(cvtAnimKey); // add key to track
}
Any suggestion or advice is really appreciated...