我正在构建一个小游戏引擎,并使用fbx sdk来ipmort fbx网格和动画,这意味着我想在自己的类中存储动画。现在,有两种方法可以实现这一点:
1.第一种方法是只存储关键帧。如果我只存储关键帧,我将在fbx文件中拥有 raw 动画数据,并且我可以随时操纵或调整动画。
1.第二种方法是以固定的速率采样帧。而不是存储关键帧,我从fbx文件中获取一些我需要的帧并存储它们。这样,我可能会丢失 raw 动画数据,因为当我采样帧时,所选的帧可能不是关键帧,导致细节的轻微丢失。
从我的Angular 来看,第一种方式是最好的方式,但互联网上的大多数教程都使用第二种方式。例如,here。下面是它的一个片段:
for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i)
{
FbxTime currTime;
currTime.SetFrame(i, FbxTime::eFrames24);
*currAnim = new Keyframe();
(*currAnim)->mFrameNum = i;
FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(currTime) * geometryTransform;
(*currAnim)->mGlobalTransform = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);
currAnim = &((*currAnim)->mNext);
}
字符串
请注意,函数 EvaluateGlobalTransform(..) 是一个fbxsdk函数,它似乎是我们和fbx动画之间唯一可以依赖的安全接口。此外,第二种方式(使用 EvaluateGlobalTransform 以特定速率采样)似乎是标准和普遍接受的工作方式。there是一个解释说:
“FBX SDK为您提供了多种获取所需数据的方法。不幸的是,由于DCC工具不同,(Max/Maya/etc)您可能无法获得所需的确切数据。例如,假设你找到了根骨,并且它在动画中有平移。你可以通过多种方式访问变换。你可以使用LclTransform属性,并在不同的位置请求FbxAMatrix。times。或者你可以用time来调用求值函数来获得矩阵。或者你可以使用求值器的EvaluateNode函数来一次计算节点。最后,最复杂的版本是你可以从属性中获得曲线节点,然后查看曲线的键。
考虑到所有这些选项,您可能会认为获取曲线是正确的方法。不幸的是,例如Maya将动画数据烘焙到一组与Maya中实际设置的关键点无关的关键点。原因是Maya使用的曲线与FBX支持的曲线不同。因此,即使您直接获取曲线,它们可能有几百把钥匙,因为它们可能是烤出来的。
这意味着,除非Max支持FBX的曲线,否则它可能会烘焙它们,而你无法找到原始的两个姿势。一般来说,你会穿越时间并以固定的速率对场景进行采样。是的,这有点糟糕,通常你会想在采样后简化数据。”
总结如下:
1.第一种方式:
优点:易于操作和调整,精确的细节,更少的内存消耗(如果你在运行中生成你的顶点变换矩阵)
缺点:难以获得这些关键帧,不适用于某些fbx文件
1.第二种方式:
优点:易于选择帧,适用于所有fbx文件
缺点:难以更改动画,内存消耗大,细节不准确
我的问题是:
1.第二种方法真的是这样做的常见方法吗?
1.著名的游戏引擎,如Unreal和Unity,使用哪种方式?
1.如果我想使用第一种方法,即使它在某些情况下可能不起作用,我如何才能从fbx文件中只获取关键帧(即不使用EvaluateGlobalTransform,而是使用FbxAnimStack,FbxAnimLayer,FbxAnimCurveNode,FbxAnimCurve,FbxAnimCurveKey)?
1条答案
按热度按时间46scxncf1#
你可以深入研究像assimp这样的行业使用的库,并且可能以类似于
aiAnimation
结构的方式实现你自己的存储类。它将具有Map到你的骨骼层次结构的通道,并且将有任何转换数组,存储在矩阵结构中。您将不得不编写一些线性插值逻辑来填充播放动画的两个关键帧之间的中间帧。