理解glTF jointMatrix
Understand glTF jointMatrix
我阅读了 glTF github tutorial 中的皮肤部分,但未能理解 jointMatrix
的工作原理。
教程中定义为
jointMatrix(j) =
globalTransformOfNodeThatTheMeshIsAttachedTo^-1 *
globalTransformOfJointNode(j) *
inverseBindMatrixForJoint(j);
我对 globalTransform
和取消感到困惑。在我看来,jointMatrix
类似于
jointMatrix(j) =
jointSpaceToModelSpace(j) *
jointTransform(j) *
modelSpaceToJointSpace(j);
并且在顶点着色器中
// assume 'joint' is a matrix computed from weighted aggregation of all jointMatrix(j)
vertex_world_space = model-view-proj * joint * vertex_model_space;
我的问题是
- 为什么
jointMatrix
是这样定义的?
- 我的版本有什么问题?
要记住的一件事是顶点着色器是在蒙皮网格节点的上下文中执行的,而不是骨架根或关节。这意味着模型视图矩阵可能处于“无意义”的位置:这个蒙皮节点可能已经进行了变换,但它不会受此影响,因为它的所有顶点都由关节控制。如果蒙皮节点不是根节点,glTF 验证器甚至会发出警告,因为这个原因,因为应用于蒙皮本身的变换是空操作。
因此,皮肤中任何特定顶点所需的步骤是:
- 撤消皮肤的世界到节点转换(如果有)。
- 应用关节的世界到关节转换。
- 取消关节的“静止”位置。
这三个步骤与您在教程中列出的三个步骤相对应。
说说第三个吧。每个关节都有一个“休息”位置。例如,手臂骨骼可能静止在皮肤原始形状(绑定姿势)的左臂中,而腿骨可能位于右腿中。这些骨骼不位于原点,它们散布在模型周围。但是我们不希望它们在静止位置时拉动顶点,例如,手臂骨骼可能在原点的上方和左侧,但在静止时不应将任何顶点拉动到左上方。
所以每个关节都有一个“反向绑定矩阵”,可以消除关节在其自身静止位置自然产生的影响。当关节移动时,它会相对于其自身的静止位置移动,而该增量(步骤 2 和步骤 3 之间的差异)将应用于目标顶点。
如果皮肤本身试图移动,则什么也不会发生。这样的变换在教程着色器的末尾应用于 u_modelViewMatrix
,并且在步骤 1 中应用了该变换的逆,因此它们相互抵消。如果您想移动整个蒙皮网格,当然正确的方法是重新定位整个骨架,而不是蒙皮节点。移动根关节会在步骤 2 中对网格中的所有顶点应用新的变换。
我阅读了 glTF github tutorial 中的皮肤部分,但未能理解 jointMatrix
的工作原理。
教程中定义为
jointMatrix(j) =
globalTransformOfNodeThatTheMeshIsAttachedTo^-1 *
globalTransformOfJointNode(j) *
inverseBindMatrixForJoint(j);
我对 globalTransform
和取消感到困惑。在我看来,jointMatrix
类似于
jointMatrix(j) =
jointSpaceToModelSpace(j) *
jointTransform(j) *
modelSpaceToJointSpace(j);
并且在顶点着色器中
// assume 'joint' is a matrix computed from weighted aggregation of all jointMatrix(j)
vertex_world_space = model-view-proj * joint * vertex_model_space;
我的问题是
- 为什么
jointMatrix
是这样定义的? - 我的版本有什么问题?
要记住的一件事是顶点着色器是在蒙皮网格节点的上下文中执行的,而不是骨架根或关节。这意味着模型视图矩阵可能处于“无意义”的位置:这个蒙皮节点可能已经进行了变换,但它不会受此影响,因为它的所有顶点都由关节控制。如果蒙皮节点不是根节点,glTF 验证器甚至会发出警告,因为这个原因,因为应用于蒙皮本身的变换是空操作。
因此,皮肤中任何特定顶点所需的步骤是:
- 撤消皮肤的世界到节点转换(如果有)。
- 应用关节的世界到关节转换。
- 取消关节的“静止”位置。
这三个步骤与您在教程中列出的三个步骤相对应。
说说第三个吧。每个关节都有一个“休息”位置。例如,手臂骨骼可能静止在皮肤原始形状(绑定姿势)的左臂中,而腿骨可能位于右腿中。这些骨骼不位于原点,它们散布在模型周围。但是我们不希望它们在静止位置时拉动顶点,例如,手臂骨骼可能在原点的上方和左侧,但在静止时不应将任何顶点拉动到左上方。
所以每个关节都有一个“反向绑定矩阵”,可以消除关节在其自身静止位置自然产生的影响。当关节移动时,它会相对于其自身的静止位置移动,而该增量(步骤 2 和步骤 3 之间的差异)将应用于目标顶点。
如果皮肤本身试图移动,则什么也不会发生。这样的变换在教程着色器的末尾应用于 u_modelViewMatrix
,并且在步骤 1 中应用了该变换的逆,因此它们相互抵消。如果您想移动整个蒙皮网格,当然正确的方法是重新定位整个骨架,而不是蒙皮节点。移动根关节会在步骤 2 中对网格中的所有顶点应用新的变换。