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: 

How do you manage FBX animation data in your Application?

1 REPLY 1
Reply
Message 1 of 2
donggas90
1032 Views, 1 Reply

How do you manage FBX animation data in your Application?

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.

 

cap0.PNG

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

cap1.PNG

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

1 REPLY 1
Message 2 of 2
donggas90
in reply to: donggas90

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.

Post to forums  

Autodesk Design & Make Report