http://forums.autodesk.com/t5/FBX-SDK/Useful-things-you-might-want-to-know-about-FBXSDK/td-p/4821177
Now I can playing bone animation in my application that using DX11.
However FbxAnimEvaluator->EvaluateAnimation() is too slow.
And method and operation of FbxAMatrix as well.
BTW DX Math library is using SSE instruction set, so it perform nice speed.
So I tried to convert FBX data to DX data in several days.
But I can't solve correctly.
First, DX Matrix can't decompose rotation in Euler angles but only quaternion.
BTW quaternion is not fully match with Euler angles.
(sine and cosine function is not one-to-one function)
So lerp result of two quaternion that can different with lerp of Euler angles.
(If lerp Ratio is 0.5,
Euler angles: [0~720] is 360 but
Quaternion: convert [0~720] to Quaternion that being [0~360] so result is 180.)
In addition to, DX Math cannot perform negate rotation to already combined matrix.
Therefore this code cannot convert to DX Math.
FbxAMatrix inverseGlobalBindpose = transformLinkMatrix.Inverse() * transformMatrix; finalTransform = currentTransformAtT * inverseGlobalBindpose; lT = finalTransform.GetT(); lR = finalTransform.GetR(); lS = finalTransform.GetS(); lT[0] *= -1; lR[1] *= -1; lR[2] *= -1; finalTransform.SetTRS(lT, lR, lS);
Then I tried to lerp with two keyframes' bone palette matrix but it seems little bit wrong.
(FPS is about 1000)
I think this problem came from rotation.
FbxAMatrix lFinalTransform = lTransformMatrix * lInverseGlobalBindpose; FbxVector4 lT, lR, lS; lT = lFinalTransform.GetT(); lR = lFinalTransform.GetR(); lS = lFinalTransform.GetS(); lT[0] *= -1; lR[1] *= -1; lR[2] *= -1; lFinalTransform.SetTRS(lT, lR, lS); lFinalTransform = lsAdjustment * lFinalTransform; XMVECTOR lFinalT, lFinalR, lFinalS; lFinalT = CFbx::ToXm(lFinalTransform.GetT()); lFinalR = CFbx::ToXm(lFinalTransform.GetR()); lFinalS = CFbx::ToXm(lFinalTransform.GetS()); CFbxAffineMatrix& lCurrentKeyTransform = lCurrentKey.mTransform; lCurrentKeyTransform.StoreTranslation(lFinalT); lCurrentKeyTransform.StoreRotationDegrees(lFinalR); lCurrentKeyTransform.StoreScaling(lFinalS);
CFbxAffineMatrix is my own matrix that using DX Math.
Then lerp with two instance like below.
static CFbxAffineMatrix Interpolate(const CFbxAffineMatrix& pFront, const CFbxAffineMatrix& pBack, const F32 pRatio) { XMVECTOR lFront = pFront.LoadTranslation(); XMVECTOR lBack = pBack.LoadTranslation(); XMVECTOR lT = XMVectorLerp(lFront, lBack, pRatio); lFront = pFront.LoadRotationRadians(); lBack = pBack.LoadRotationRadians(); XMVECTOR lR = XMVectorLerp(lFront, lBack, pRatio); lFront = pFront.LoadScaling(); lBack = pBack.LoadScaling(); XMVECTOR lS = XMVectorLerp(lFront, lBack, pRatio); CFbxAffineMatrix lResult; lResult.StoreTransformation(lT, lR, lS); return lResult; }
I'm already known about how to combine transformation matrix in FBX.
Additionally, using FbxAMatrix and FbxAnimEvaluator result is below.
(It seems no problem but FPS is about 80. very very slow)
So I'm really wonder, how do you manage your animation data?
And How can I convert FBX animation data to DX effectively?
Thanks.
Here is entire codes of bone animation data.
void Import(SBone& pBone, SAnimLayer& pAnimData, FbxAnimationClip& pAnimation) { FLOOD_ASSERT(nullptr != mManager); FLOOD_ASSERT(nullptr != pBone.mSkeleton); FbxNode* lNode = pBone.mSkeleton->GetNode(); FbxTakeInfo* lCurrentTakeInfo = mSceneBuffer->GetTakeInfo(pAnimData.mStack->GetName()); FbxTime lStartTime; FbxTime lStopTime; FLOOD_ASSERT(nullptr != lCurrentTakeInfo); lStartTime = lCurrentTakeInfo->mLocalTimeSpan.GetStart(); lStopTime = lCurrentTakeInfo->mLocalTimeSpan.GetStop(); CList<FbxTime> lKeyTimes; { FbxAnimCurve* lCurveX = lNode->LclTranslation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_X); if (nullptr != lCurveX) { const S32 lCount = lCurveX->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveX->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveY = lNode->LclTranslation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (nullptr != lCurveY) { const S32 lCount = lCurveY->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveY->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveZ = lNode->LclTranslation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (nullptr != lCurveZ) { const S32 lCount = lCurveZ->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveZ->KeyGetTime(lIndex), lStartTime, lStopTime); } } } { FbxAnimCurve* lCurveX = lNode->LclRotation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_X); if (nullptr != lCurveX) { const S32 lCount = lCurveX->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveX->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveY = lNode->LclRotation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (nullptr != lCurveY) { const S32 lCount = lCurveY->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveY->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveZ = lNode->LclRotation.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (nullptr != lCurveZ) { const S32 lCount = lCurveZ->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveZ->KeyGetTime(lIndex), lStartTime, lStopTime); } } } { FbxAnimCurve* lCurveX = lNode->LclScaling.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_X); if (nullptr != lCurveX) { const S32 lCount = lCurveX->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveX->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveY = lNode->LclScaling.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (nullptr != lCurveY) { const S32 lCount = lCurveY->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveY->KeyGetTime(lIndex), lStartTime, lStopTime); } } FbxAnimCurve* lCurveZ = lNode->LclScaling.GetCurve(pAnimData.mLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (nullptr != lCurveZ) { const S32 lCount = lCurveZ->KeyGetCount(); for (S32 lIndex = 0; lIndex < lCount; lIndex++) { EmbarkKeyTime(lKeyTimes, lCurveZ->KeyGetTime(lIndex), lStartTime, lStopTime); } } } if (!lKeyTimes.Contains(lStartTime)) { lKeyTimes.Add(lStartTime); } if (!lKeyTimes.Contains(lStopTime)) { lKeyTimes.Add(lStopTime); } CSort<FbxTime>::Bubble(lKeyTimes.GetInnerArray(), lKeyTimes.GetCount()); if (0 >= lKeyTimes.GetCount()) { lKeyTimes.Add(FbxTime(0)); } pAnimation.SetKeyCount(lKeyTimes.GetCount()); static FbxAMatrix lsAdjustment(FbxVector4(), FbxVector4(0, 180, 0), FbxVector4(1, 1, 1)); FbxAMatrix& lInverseGlobalBindpose = pBone.mInverseGlobalBindpose; for (S32 i = 0; i < lKeyTimes.GetCount(); i++) { FbxAnimationClip::SKey& lCurrentKey = pAnimation[i]; const FbxTime& lCurrentTime = lKeyTimes[i]; lCurrentKey.mFrame = static_cast<S32>(lCurrentTime.GetFrameCount()); const FbxAMatrix& lTransformMatrix = lNode->EvaluateGlobalTransform(lCurrentTime); FbxAMatrix lFinalTransform = lTransformMatrix * lInverseGlobalBindpose; FbxVector4 lT, lR, lS; lT = lFinalTransform.GetT(); lR = lFinalTransform.GetR(); lS = lFinalTransform.GetS(); lT[0] *= -1; lR[1] *= -1; lR[2] *= -1; lFinalTransform.SetTRS(lT, lR, lS); lFinalTransform = lsAdjustment * lFinalTransform; XMVECTOR lFinalT, lFinalR, lFinalS; lFinalT = CFbx::ToXm(lFinalTransform.GetT()); lFinalR = CFbx::ToXm(lFinalTransform.GetR()); lFinalS = CFbx::ToXm(lFinalTransform.GetS()); CFbxAffineMatrix& lCurrentKeyTransform = lCurrentKey.mTransform; lCurrentKeyTransform.StoreTranslation(lFinalT); lCurrentKeyTransform.StoreRotationDegrees(lFinalR); lCurrentKeyTransform.StoreScaling(lFinalS); } pAnimation.Finalize(); }
SBone is FbxSkeleton and BindPose pair.
SAnimLayer is FbxAnimStack and FbxAnimLayer pair.
FbxAnimationClip is my own animation data class that has keyframe list.
Can't find what you're looking for? Ask the community or share your knowledge.