我正在尝试将FBX文件的解析器编写为可以在我的游戏引擎中使用的自定义模型格式,但是我目前一直在提取每个骨骼所需的矩阵。我想我也可能会迷失于蒙皮理论...
我设法提取了网格的骨骼层次,并将变形簇的权重和索引附加到了我的顶点上。现在,我需要提取需要在引擎中进行蒙皮处理的(两个?)矩阵。
基本上,以我的格式,我也希望它看起来像这样:
//BoneID
//ParentBoneID
//矩阵1
//Matrix2
现在,到矩阵...
我是否应该假设其中至少一个应该是“绑定(bind)姿势矩阵”,即骨骼的默认位置,对吗?如何从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;
所以基本上,当我想计算动画时,我得到了网格世界矩阵的逆矩阵,将其与代表动画帧的矩阵相乘,再乘以我的绑定(bind)矩阵的逆矩阵,即骨骼的父绑定(bind)矩阵和最终的父变换矩阵?
最佳答案
首先,您需要知道网格的原始顶点位置不在世界空间中。 (例如:您将看到角色在3ds max中站立,但是如果直接导出网格数据,则它处于躺下状态。)
骨架树的所有转换节点也发生相同的情况。这意味着,即使只有一个具有单位矩阵的骨骼,也需要通过FBX场景的根节点,然后是骨骼节点的局部矩阵来转换网格。 (因为根节点也是骨骼节点的父节点),
顺便说一句,如果您使用函数FbxAxisSystem::ConvertScene()转换网格的轴系,则该操作也仅应用于根节点的转换矩阵,而不应用于网格的顶点。
为了正确计算顶点的位置,您需要找到网格所属的FbxNode,然后调用其EvaluateGlobalTransform()函数以获取全局转换矩阵,并使用它来转换网格顶点的位置。 (法线的逆转置矩阵。)
我不知道您在代码的功能GetGeometry()中到底做了什么:FbxAMatrix clusterGeometry = GetGeometry(cluster->GetLink());
但这是我获取骨骼的绑定(bind)姿势矩阵的方式: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;
不要忘记我已经转换了根节点的顶点位置。
就是这样,上面的代码在D3D和OpenGL下都可以正常工作。希望它能对您有所帮助。 :D