我阅读了glTF的github教程中的皮肤部分,但未能理解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中为网格中的所有顶点应用新的变换。