COLLADA:反向绑定姿势在错误的空间?
Posted
技术标签:
【中文标题】COLLADA:反向绑定姿势在错误的空间?【英文标题】:COLLADA: Inverse bind pose in the wrong space? 【发布时间】:2011-11-27 14:25:16 【问题描述】:我正在编写自己的 COLLADA 导入器。我已经走了很远,加载网格和材料等。但我在动画方面遇到了障碍,特别是:关节旋转。
我用于为网格蒙皮的公式很简单:
weighted;
for (i = 0; i < joint_influences; i++)
weighted +=
joint[joint_index[i]]->parent->local_matrix *
joint[joint_index[i]]->local_matrix *
skin->inverse_bind_pose[joint_index[i]] *
position *
skin->weight[j];
position = weighted;
就文献而言,这是正确的公式。现在,COLLADA 为关节指定了两种类型的旋转:局部和全局。您必须将旋转连接在一起才能获得关节的局部变换。
COLLADA 文档没有区分关节的局部旋转和关节的全局旋转。但在我见过的大多数模型中,旋转的 id 可以是rotate
(全局)或jointOrient
(本地)。
当我忽略全局旋转而只使用局部旋转时,我得到了模型的绑定姿势。但是当我将全局旋转添加到关节的局部变换中时,奇怪的事情开始发生。
这是不使用全局旋转:
这是全局旋转:
在两个屏幕截图中,我都使用线条来绘制骨架,但在第一个屏幕截图中它是不可见的,因为关节位于网格内部。在第二个屏幕截图中,顶点到处都是!
为了比较,这是第二张截图应该的样子:
很难看到,但您可以在第二张屏幕截图中看到关节处于正确位置。
但是现在奇怪的事情。如果我忽略 COLLADA 指定的反向绑定姿势,而是取关节的父局部变换乘以关节的局部变换的倒数,我会得到以下结果:
在这个屏幕截图中,我从每个顶点到有影响的关节画了一条线。我得到绑定姿势这一事实并不奇怪,因为现在公式变为:
world_matrix * inverse_world_matrix * position * weight
但这让我怀疑 COLLADA 的反向绑定姿势在错误的空间中。
所以我的问题是:COLLADA 在什么空间指定它的反向绑定姿势?以及如何将反向绑定姿势转换为我需要的空间?
【问题讨论】:
您是否阅读了 1.4.1 规范中的“在 COLLADA 中为骨架蒙皮”部分?你的公式看起来不对 【参考方案1】:我首先将我的值与我从 Assimp(一个开源模型加载器)读取的值进行比较。通过代码,我查看了他们构建绑定矩阵和逆绑定矩阵的位置。
最终我进入了SceneAnimator::GetBoneMatrices
,其中包含以下内容:
// Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose
// Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform
for( size_t a = 0; a < mesh->mNumBones; ++a)
const aiBone* bone = mesh->mBones[a];
const aiMatrix4x4& currentGlobalTransform
= GetGlobalTransform( mBoneNodesByName[ bone->mName.data ]);
mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix;
globalInverseMeshTransform
始终是身份,因为网格不会转换任何东西。 currentGlobalTransform
是绑定矩阵,关节的父级局部矩阵与关节的局部矩阵连接。而mOffsetMatrix
是逆绑定矩阵,直接来自皮肤。
我将这些矩阵的值与我自己的值进行了对比(哦,是的,我在观察窗口中比较了它们),它们完全一样,相差可能 0.0001%,但这微不足道。那么为什么 Assimp 的版本有效,而我的却没有,即使公式相同?
这是我得到的:
当 Assimp 最终将矩阵上传到蒙皮着色器时,它们会执行以下操作:
helper->piEffect->SetMatrixTransposeArray( "gBoneMatrix", (D3DXMATRIX*)matrices, 60);
等一下。他们上传它们转置?不可能那么容易。没办法。
是的。
我做错了什么:我在应用蒙皮矩阵之前将坐标转换为正确的系统(厘米到米)。这会导致模型完全失真,因为矩阵是为原始坐标系设计的。
未来的谷歌用户
按照收到的顺序读取所有节点变换(旋转、平移、缩放等)。 将它们连接到关节的局部矩阵。 获取关节的父节点并将其与局部矩阵相乘。 将其存储为绑定矩阵。 读取皮肤信息。 存储关节的逆绑定姿势矩阵。 存储每个顶点的关节权重。 将绑定矩阵与反向绑定姿势矩阵相乘并转置,称之为蒙皮矩阵 . 将蒙皮矩阵乘以位置乘以关节权重并将其添加到加权位置。 使用加权位置进行渲染。完成!
【讨论】:
老问题但很有帮助!非常感谢!【参考方案2】:顺便说一句,如果您在加载矩阵时转置矩阵而不是在最后转置矩阵(在制作动画时可能会出现问题),您希望以不同的方式执行乘法(您上面使用的方法似乎是在 DirectX 中使用蒙皮使用 OpenGL 友好矩阵时 - 进行转置。)
在 DirectX 中,我在从文件加载矩阵时转置矩阵,然后使用(在下面的示例中,为了简单起见,我只是应用绑定姿势):
XMMATRIX l_oWorldMatrix = XMMatrixMultiply(l_oBindPose, in_oParentWorldMatrix);
XMMATRIX l_oMatrixPallette = XMMatrixMultiply( l_oInverseBindPose, l_oWorldMatrix );
XMMATRIX l_oFinalMatrix = XMMatrixMultiply(l_oBindShapeMatrix, l_oMatrixPallette);
【讨论】:
以上是关于COLLADA:反向绑定姿势在错误的空间?的主要内容,如果未能解决你的问题,请参考以下文章
Blender 如何解释 Collada 文件 (.dae) 以进行装配?