从 FBX 加载蒙皮信息

Posted

技术标签:

【中文标题】从 FBX 加载蒙皮信息【英文标题】:Loading skinning information from FBX 【发布时间】:2012-11-14 00:48:29 【问题描述】:

我正在尝试将 FBX 文件的解析器编写为可在我的游戏引擎中使用的自定义模型格式,但我目前正忙于提取每个骨骼所需的矩阵。我想我也可能迷失在剥皮理论中......

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

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

//骨骼ID

//ParentBoneID

//矩阵1

//矩阵2

现在,到矩阵... 我是否正确假设其中至少一个应该是“绑定姿势矩阵”,即我的骨架的默认位置?如何从 FBX 中提取它?这个矩阵对于整个网格是否均匀?

至于第二个,我真的不知道,我试过查看 ViewScene 和 ImportScene 示例,但我不明白。我读了一些关于“局部空间矩阵”的东西,我猜这是每个骨骼的单独位置、旋转和缩放?

感谢任何帮助或建议,我现在不知所措,可能是因为我对此视而不见。几乎到了放弃 FBX 转而支持 COLLADA 的地步。

Edit1:引擎还没有绘图功能,因为我想在继续之前完成这项工作。我找到了一个我认为我理解的例子,也许这里有人可以确认它是否正确。

//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】:

首先,你需要知道mesh的原始顶点位置不在世界空间中。 (例如:你会看到你的角色在 3ds max 中站起来,但如果你直接导出网格数据,它会躺下。)

同样的事情也发生在骨架树的所有变换节点上。这意味着,即使只有一个具有单位矩阵的骨骼,网格也需要通过 FBX 场景的根节点进行变换,然后是骨骼节点的局部矩阵。 (因为根节点也是骨骼节点的父节点),

顺便说一句,如果您使用函数 FbxAxisSystem::ConvertScene() 来转换网格的轴系,那么该操作也仅适用于根节点的变换矩阵,而不适用于网格的顶点。

要正确计算顶点的位置,需要找到网格所属的FbxNode,然后调用其EvaluateGlobalTransform()函数得到全局变换矩阵,并用它来变换网格顶点的位置。 (法线的逆转置矩阵。)

我不知道您在代码的函数 GetGeometry() 中究竟做了什么: FbxAMatrix clusterGeometry = GetGeometry(cluster->GetLink());

但这是我获取骨骼绑定姿势矩阵的方法: FbxAMatrix BoneBindPoseMatrix; pCluster->GetTransformLinkMatrix(BoneBindPoseMatrix).

为了获取骨骼的节点,我也使用FbxNode* pBoneNode = pCluster->GetLink(),调用pBoneNode->EvaluateLocalTransform( CurrentTime )获取骨骼当前时间的局部变换矩阵。但是我做了一件特别的事情:记得我是通过根节点的全局变换矩阵来转换网格的吧?所以对于骨架的根节点,我需要通过调用得到它的全局变换矩阵 FbxAMatrix BoneInitPoseGlobalTransform = pBoneRootNode->EvaluateGlobalTransform(), 然后反转它。而我的根骨骼的局部变换矩阵将是:BoneLocalTransform = InvBoneInitPoseGlobalTransform * BoneLocalTransform; 我们只需要对骨骼的根节点进行处理即可。

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

就是这样,上面的代码在 D3D 和 OpenGL 下都运行良好。我希望它可以帮助你。 :D

【讨论】:

虽然这个答案非常有用;它没有回答提取原始转换信息的问题。调用 EvaluateLocalTransform(currentTime) 需要 FBX SDK,但作者想知道是否可以检索原始“皮肤”信息,以便他们能够编写自己的 EvaluateLocalTransform 函数。您知道 FBX SDK 是否可以做到这一点? 对不起,我可能误解了这个问题。是的,您可以自己计算局部变换,但这非常复杂。首先,您需要检索与下列节点属性绑定的所有动画曲线:LclTranslation、LclRotation、PreRotation、PostRotation、RotationPivot、RotationOffset、LclScaling、ScalingPivot、ScalingOffset。 然后你需要把它们变成矩阵,并乘以它们的顺序:InvScalPivot * Scal * ScalPivot * ScalOffset * InvRotaPivot * PostRota * Rota * PreRota * RotaPivot * RotaOffset * Translation。您可以搜索类 FbxProperty 和 FbxAnimCurve 了解更多信息。 这个答案对我帮助很大(搜索轴转换),fbx 的文档记录真的很糟糕!找到做某事的正确方法很痛苦。 @SeaStar 似乎您正在描述 Maya 风格的 FBX 矩阵( [Sp]x[S]x[Sh]x[Sp]x[St]x[Rp]x[Ro]x[R ]x[Rp]x[Rt]x[T] ),但在 3DS Max 等其他 3d 建模工具中,世界变换只有 (ParentWorldTransform * T * R * S * OT * OR * OS)。

以上是关于从 FBX 加载蒙皮信息的主要内容,如果未能解决你的问题,请参考以下文章

在网格加载和处理期间如何转换蒙皮网格?

Vue2+ThreeJS踩坑记录fbx蒙皮网格模型挂载ShaderMaterial材质之后,挂载动画无效的解决办法

Vue2+ThreeJS踩坑记录fbx蒙皮网格模型挂载ShaderMaterial材质之后,挂载动画无效的解决办法

Unity3d VFX 采用skinned mesh sampling(蒙皮采样)发射粒子效果时fbx模型是否优化(Optimized)带来的问题记录

从 FBX 文件中提取顶点数据?

Autodesk Maya fbx 文件导出