如何计算 COLLADA 文件的父子联合变换?
Posted
技术标签:
【中文标题】如何计算 COLLADA 文件的父子联合变换?【英文标题】:How do I calculate a COLLADA file's parent and children joint transforms? 【发布时间】:2020-11-08 06:52:03 【问题描述】:尝试实现绑定:
使用 Blender 创建了一个简单的操纵蛇测试并导出了一个 COLLADA 文件。 我已正确加载顶点位置、权重和关节 ID。 我已经为每个骨骼加载了骨架关节层次结构和这些变换(我加载了将所有浮点数转换为浮点数的矩阵[16],然后我使用 glm::make_mat4(tmpFloatArray),然后我转置它,不确定这是否正确): <visual_scene id="Scene" name="Scene">
<node id="Armature" name="Armature" type="NODE">
<matrix sid="transform">1 0 0 0 0 0 1 0 0 -1 0 0 0 0 0 1</matrix>
<node id="Armature_Bone" name="Bone" sid="Bone" type="JOINT">
<matrix sid="transform">0.3299372 0.944003 -1.78814e-7 0 -4.76837e-7 0 -1 0 -0.944003 0.3299374 3.8743e-7 0 0 0 0 1</matrix>
<node id="Armature_Bone_001" name="Bone.001" sid="Bone_001" type="JOINT">
<matrix sid="transform">0.886344 -0.4630275 3.31894e-7 2.98023e-8 0.4630274 0.886344 -1.86307e-7 1.239941 -2.07907e-7 3.18808e-7 1 -2.84217e-14 0 0 0 1</matrix>
<node id="Armature_Bone_002" name="Bone.002" sid="Bone_002" type="JOINT">
<matrix sid="transform">0.9669114 0.2551119 -1.83038e-7 -1.19209e-7 -0.2551119 0.9669115 1.29195e-7 1.219687 2.09941e-7 -7.82246e-8 1 0 0 0 0 1</matrix>
<node id="Armature_Bone_003" name="Bone.003" sid="Bone_003" type="JOINT">
<matrix sid="transform">0.8538353 0.5205433 1.0139e-7 -1.19209e-7 -0.5205433 0.8538353 2.4693e-7 1.815649 4.19671e-8 -2.63615e-7 1 5.68434e-14 0 0 0 1</matrix>
现在,如果我将每个骨骼的矩阵设置为 glm::mat4(1),我会得到:
但是,如果我尝试乘以关节父变换,例如在薄矩阵装配教程中,我会得到非常奇怪的结果:
void SkelManager::setTposeTransforms(std::vector<Joint>& _reference)
for (int child = 0; child < _reference.size(); child++)
if (_reference[child].parent == -1)
//_reference[child].tPose = glm::mat4(1);
_reference[child].tPose = _reference[child].transform;
for (int parent = 0; parent < _reference.size(); parent++)
if (_reference[child].parent == parent)
//_reference[child].tPose = glm::mat4(1);
_reference[child].tPose = _reference[parent].tPose * _reference[child].transform;
请帮忙,我已经坚持了几个星期,但我没有成功,无论我多么努力地搜索网络,我都找不到任何有用的东西,任何关于我可以做什么的想法做错了吗?
【问题讨论】:
【参考方案1】:我用glm::make_mat4(tmpFloatArray),然后转置,不确定 如果这是正确的方法):
参见 COLLADA 规范中关于矩阵的说明:
COLLADA 中的矩阵是数学意义上的列矩阵。 这些矩阵是按行主要顺序编写的,以帮助人类 读者。请参阅示例。
是的,你需要转置它。
加载 COLLADA 的骨骼动画并不难。请按以下步骤操作:
进口方:
-
加载所有关节节点层次结构,将关节变换与父节点相乘,直到根节点,就像对普通/其他节点(场景图)所做的那样。当每一帧的变换都改变时,最好做乘法...
使用关节 ID、权重...以及 bind_shape_matrix 和 加载 Controller->Skin 元素强>INV_BIND_MATRIX
加载动画对象以动画关节
加载instance_controller,它存储材质和
渲染面:
如果需要,为每一帧准备所有关节变换。与父项乘以联合变换
为每个关节创建这个矩阵:
FinalJointTrans4x4 = JointTransform * InvBindPose * BindShapeMatrix
JointTransform 是与父级相乘的变换...
InvBindPose(或 InvBindMatrix)是您从 skin->joints->INV_BIND_MATRIX 读取每个关节的变换
BindShapeMatrix 是您从 skin->bind_shape_matrix
读取的变换将这些 FinalJointTrans4x4 矩阵和权重发送到着色器(统一的缓冲区可以很好地存储矩阵)
在着色器中使用这些信息,渲染它。
也许(来自http://github.com/recp/gk):
...
mat4 skinMat;
skinMat = uJoints[JOINTS.x] * WEIGHTS.x
+ uJoints[JOINTS.y] * WEIGHTS.y
+ uJoints[JOINTS.z] * WEIGHTS.z
+ uJoints[JOINTS.w] * WEIGHTS.w;
pos4 = skinMat * pos4;
norm4 = skinMat * norm4;
...
#ifdef JOINT_COUNT
gl_Position = VP * pos4;
#else
gl_Position = MVP * pos4;
#endif
...
我可能会忘记提及其他细节(我可能稍后会编辑答案),但这一定很有帮助。
PS:有一个名为 AssetKit (http://github.com/recp/assetkit) 的库,您可以根据需要使用它来加载 COLLADA 文件。
【讨论】:
非常感谢您的回答!我正在尝试慢慢做事情,现在,我正在寻找默认姿势,我猜我需要为每个关节获取一个没有旋转或平移但有偏移的矩阵,对吧?当我变换关节矩阵之一时,孩子们正确地移动它,但它在错误的点上旋转。也找不到INV_BIND_MATRIX,而且无论我读了多少遍,我都没有得到它,因为所有这些新术语。但是非常感谢您的回答!如果您可以指定如何计算偏移量,我想我可以管理其余的 .Thx!。 您必须能够以<input semantic="INV_BIND_MATRIX" source="..." />
找到INV_BIND_MATRIX
。它是必需的,因为您需要将网格从对象空间转换为骨骼空间。然后,如果您变换骨骼/关节,则网格将随之而来。按照上面的步骤,创建FinalJointTrans4x4
矩阵,就像我提到的那样
一个你可以关注的教程wazim.com/Collada_Tutorial_1.htm
recp,我阅读了你说的 100% 详细的教程,现在效果更好,但仍然不是 100% 好,如果你有时间,你能解释一下,就好像我是一个猴子,比如:在初始化时,从 collada 文件中取这个,然后乘以 collada 文件的其他东西,然后在更新中做这个和这个,拜托,它会很有帮助,我一直被困在这里这么久:((((而且这个东西只有极少数人知道以上是关于如何计算 COLLADA 文件的父子联合变换?的主要内容,如果未能解决你的问题,请参考以下文章
将 Collada dae 文件加载到 SceneKit 以进行联合操作
Blender 如何解释 Collada 文件 (.dae) 以进行装配?
如何在 Three.js 中克隆包含多个网格的 Collada 对象