从FBX文件中加载皮肤信息

11

我正在尝试编写一个解析FBX文件并将其转换为我的自定义模型格式的解析器,以便在我的游戏引擎中使用,但我目前卡在提取每个骨骼所需的矩阵上。我认为我可能也迷失在蒙皮理论中了...

我已经成功地提取了网格的骨骼层次结构,并将变形集群的权重和索引附加到我的顶点上。现在我需要提取我在引擎中进行蒙皮所需的(两个?)矩阵。

基本上,在我的格式中,我希望它看起来像这样:

//骨骼ID

//父骨骼ID

//矩阵1

//矩阵2

现在是关于矩阵的问题... 我是否可以假设它们中至少有一个应该是“绑定姿势矩阵”,即我的骨架的默认位置?我如何从FBX中提取此矩阵?此矩阵对整个网格均匀吗?

至于第二个矩阵,我不太清楚,我尝试查看ViewScene和ImportScene示例,但我不理解。我读到了一些关于“本地空间矩阵”的内容,我猜这是每个骨骼的单独位置、旋转和缩放?

任何帮助或建议都将不胜感激,我现在很茫然,可能是因为一直盯着这个问题看而导致的。我快要放弃FBX,改用COLLADA了。

编辑1:引擎还没有绘图功能,因为我想先把这个搞定再做下一步。我找到了一个我认为我理解的例子,也许这里有人可以确认它是否正确。

//TEST CODE
        //This lFbxLinkMatrix is the skeleton's transform when the binding happened. 
        //It is the same as the matrix in bindpose if the bindpose is complete.
        // Multiply lClusterGlobalInitPosition by Geometric Transformation
        FbxAMatrix clusterGlobalInitPosition;
        cluster->GetTransformLinkMatrix(clusterGlobalInitPosition);

        FbxAMatrix clusterGeometry = GetGeometry(cluster->GetLink());
        clusterGlobalInitPosition *= clusterGeometry;

        skeleton->at(boneListPosition).bindMatrix = clusterGlobalInitPosition;

        // Compute the shift of the link relative to the reference.
        //lVertexTransformMatrix = RGCP.Inverse() * CGCP * CGIP.Inverse() * RGIP * RG;
        // CGCP = position of bone
        // RGCP = mesh position
        FbxAMatrix offsetMatrix;
        FbxNode* boneNode = cluster->GetLink();

        FbxAMatrix CGIP, RGIP, vertexTransformMatrix;

        cluster->GetTransformLinkMatrix(CGIP);
        cluster->GetTransformMatrix(RGIP);

        vertexTransformMatrix = CGIP.Inverse() * RGIP;

        skeleton->at(boneListPosition).localBoneMatrix = vertexTransformMatrix;

基本上,当我想计算我的动画时,我会获取网格世界矩阵的逆矩阵,将其乘以表示我的动画帧的矩阵,再乘以我的绑定矩阵的逆矩阵、该骨骼的父级绑定矩阵和最终父级变换矩阵。

1个回答

10
首先,您需要知道网格的原始顶点位置不在世界空间中。(例如:您会发现在3ds max中您的角色站立,但如果直接导出网格数据,则其处于躺下状态。)
骨架树的所有变换节点也是如此。这意味着,即使只有一个恒等矩阵的骨骼,网格也需要通过FBX场景的根节点进行变换,然后通过骨骼节点的本地矩阵。(因为根节点还是骨骼节点的父节点)
顺便说一句,如果您使用了函数FbxAxisSystem :: ConvertScene() 来转换网格的坐标轴系统,那么该操作仅应用于根节点的变换矩阵,而不是网格的顶点。
要正确计算顶点的位置,您需要找到网格所属的FbxNode,然后调用其EvaluateGlobalTransform()函数来获取全局变换矩阵,并将其用于变换网格顶点的位置。(法线需要求逆转置矩阵。)
我不知道您在代码中的GetGeometry()函数中具体做了什么: FbxAMatrix clusterGeometry = GetGeometry(cluster->GetLink()); 但这是我获取骨骼绑定姿势矩阵的方法: FbxAMatrix BoneBindPoseMatrix; pCluster->GetTransformLinkMatrix(BoneBindPoseMatrix). 为了检索骨骼节点,我还使用FbxNode * pBoneNode = pCluster-> GetLink(),并调用pBoneNode- & gt; EvaluateLocalTransform(CurrentTime)来获取当前时间的骨骼的本地变换矩阵。但有一件特殊的事情:记得我通过根节点的全局变换矩阵将网格转换了吗?因此对于骨架的根节点,我需要通过调用FbxAMatrix BoneInitPoseGlobalTransform = pBoneRootNode- & gt; EvaluateGlobalTransform()来获取其全局变换矩阵。然后反转它。我的根骨骼的本地变换矩阵将会是:BoneLocalTransform = InvBoneInitPoseGlobalTransform * BoneLocalTransform; 我们只需要对骨骼的根节点进行操作。

当动画皮肤时,我遍历整个骨架树,对于每个骨骼节点,我通过以下方式计算它的全局变换矩阵:BoneGlobalTransform = BoneLocalTransform * ParentBoneGlobalTransform; 但在将该矩阵传递到着色器之前,我需要执行以下操作:BlendMatrix = Bone.InvBindPoseMatrix * BoneGlobalTransform; 别忘了我已经通过根节点转换了顶点的位置。

这就是全部内容,以上代码在D3D和OpenGL下都可以正常工作。希望它可以帮到你。:D


1
虽然这个回答非常有用,但它并没有回答如何提取原始的变换信息的问题。调用EvaluateLocalTransform(currentTime)需要使用FBX SDK,但作者想知道是否可以检索到原始的“皮肤”信息,以便能够编写自己的EvaluateLocalTransform函数。您知道是否可以通过FBX SDK实现这一点吗? - Caleb Gray
2
抱歉,我可能误解了问题。是的,你可以自己计算本地变换,但这相当复杂。首先,你需要检索与节点属性绑定的所有动画曲线,包括:LclTranslation、LclRotation、PreRotation、PostRotation、RotationPivot、RotationOffset、LclScaling、ScalingPivot、ScalingOffset。 - SeaStar
2
然后您需要将它们转换为矩阵,并按顺序相乘:InvScalPivot * Scal * ScalPivot * ScalOffset * InvRotaPivot * PostRota * Rota * PreRota * RotaPivot * RotaOffset * Translation。您可以搜索类FbxProperty和FbxAnimCurve以获取更多信息。 - SeaStar
这个答案对我帮助很大(我在搜索轴转换时找到的),fbx文档真的很糟糕!找到正确的方法做某事真是一种痛苦。 - Felix K.
@SeaStar 看起来你在描述 Maya 风格的 FBX 矩阵 ( [Sp]x[S]x[Sh]x[Sp]x[St]x[Rp]x[Ro]x[R]x[Rp]x[Rt]x[T] ),但在其他 3D 建模工具中,如 3DS Max,世界变换只有 (ParentWorldTransform * T * R * S * OT * OR * OS)。 - diego.martinez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接