* “土豆”指的是偶像大师百万现场剧场时光(ミリシタ/MLTD)
有了前两篇文章打下的基础,终于到了最重要的一个部分,就是动作数据在两套骨骼之间的变换。
这里要特别感谢丧丝,他在转换烧笋(CGSS)到 PES(实况足球)的时候想出了这个方法的大概,不过“还是很模糊,不知道是怎么做出来的”。我不过是将其证明了而已。方法的核心也是非常之简单。
后面讲土豆骨骼和 MMD 骨骼的异同,以及如何(与 TDA 式)做到较好的兼容。这部分其实不看也行,如果你比较熟悉 MMD 的话。比如标准 T-pose 变换为其他样式的初始姿态(比如 TDA 的±34°),这一步也可以通过 PMX Editor 搞定,不过我还是想程序一步到位。反正我不熟,所以大致地讲一些经验,能有原理就最好。
对了,还有 IK。
这个方法的核心思路如下。
首先考虑两副关节初始姿态不同,而外形完全一致的骨骼。什么意思呢?就是每个关节的世界坐标都一样,但是关节自身的变换可能不同。此处记为 $$\mathbf{M_{aw}}(0)$$ 和 $$\mathbf{M_{bw}}(0)$$。接着考虑模型上的一个点,其初始位置为(向量)$$\mathbf{P}(0)$$,在动画过程中的某个姿势下,经过骨骼变换之后变换到了 $$\mathbf{P}(t)$$。那么这个变换就是 $$\mathbf{P}(t) = \mathbf{M}(t) \times \mathbf{P}(0)$$,其中 $$\mathbf{M}(t)$$ 是总的变换矩阵。
变换过程是怎么样的呢?比如受到 $$\mathbf{M_{a}}$$ 影响的点,新的局部变换矩阵为 $$\mathbf{M_{a}}(t)$$,其亲变换矩阵(亲关节到世界)为 $$\mathbf{M_{ap}}(t)$$,那么就可以知道 $$\mathbf{M}(t) = \mathbf{M_{ap}}(t) \times \mathbf{M_{a}}(t) \times \mathbf{M_{aw}}(0)^{-1}$$。它的意义很好理解:首先将静态模型上的点通过 $$\mathbf{M_{aw}}(0)$$ 的逆矩阵变换到该关节的初始局部坐标系,然后应用局部坐标系的变化(注意此时坐标系就到了亲关节的坐标系了),最后从当前亲关节的坐标系变换到世界坐标系。
同理,对于 $$\mathbf{M_{b}}$$ 也有 $$\mathbf{M}(t) = \mathbf{M_{bp}}(t) \times \mathbf{M_{b}}(t) \times \mathbf{M_{bw}}(0)^{-1}$$。注意到这是对同一个点的变换,原位置($$\mathbf{P}(0)$$)和新位置($$\mathbf{P}(t)$$)都相同。从而我们可以知道,这两个变换矩阵是完全相同的。所以就有 $$\mathbf{M_{ap}}(t) \times \mathbf{M_{a}}(t) \times \mathbf{M_{aw}}(0)^{-1} = \mathbf{M_{bp}}(t) \times \mathbf{M_{b}}(t) \times \mathbf{M_{bw}}(0)^{-1}$$。
现在来整理一下已知量和未知量。假设 A 系列是土豆自己的骨骼和动画信息,而 B 系列是 MMD 的骨骼和动画信息。显然 $$\mathbf{M_{aw}}(0)$$ 、$$\mathbf{M_{a}}(t)$$ 和 $$\mathbf{M_{ap}}(t)$$ 都是已知的。MMD 的所有关节初始变换都是默认值,也就是位移 $$\mathbf{t} = (0,0,0)$$,旋转 $$\mathbf{q} = (0,0,0,1)$$,缩放 $$\mathbf{s} = (1,1,1)$$。所以 $$\mathbf{M_{bw}}(0)$$ 也是已知的($$= \mathbf{I}$$)。同时,如果逐级求解,求解一个关节时其亲关节的变换一定已经计算完成,所以 $$\mathbf{M_{bp}}(t)$$ 也是已知的。那么我们要求的就是 $$\mathbf{M_{b}}(t)$$,这正好是 VMD 中必需的信息,同时也是未知量。
\mathbf{M_{b}}(t)$$ 很容易就能解出:移项可得 $$\mathbf{M_{b}}(t) = \mathbf{M_{bp}}(t)^{-1} \times \mathbf{M_{ap}}(t) \times \mathbf{M_{a}}(t) \times \mathbf{M_{aw}}(0)^{-1} \times \mathbf{M_{bw}}(0)$$。 看,这个方法(丧丝称之为“求解逆变换”)的数学原理就是这么简单。它适用于一套动作数据在任何两副初始姿态不同而外形一致的骨骼之间的变换。当然,动画数据要适合其中一副骨骼。 ------ 土豆的骨骼层级(hierarchy)和 MMD 常用的骨骼不太一样。同时,它们的关节作用也不太一样。这就导致二者之间兼容是比较困难的。在 MMD 中,模型的移动方式是控制“センター ”的位置;在土豆中,是控制“MODEL_00”的位置。但如果以此为基准,下面就对不上号了,因为 MMD 的旋转以“腰”为基准点,而土豆是“MODEL_00/BODY_SCALE/BASE”。从层级上来看,它们之间产生了错位。所以只好采用不同的映射,并自动生成 MMD 的几个关节。我将两个映射表都放入了[代码](https://github.com/OpenMLTD/MLTDTools/blob/f0f7ee8d7f9e91d2f85f8e43fb26ad7b29aafd0e/src/MillionDance/Utilities/BoneUtils.cs#L282-L404)中。 还有一个问题是二者的初始姿态不同。土豆的动画是以双手平举为基准的,而 TDA 式是以向斜下(34°)为基准的。这也体现在二者的默认骨骼和刚体上,打开 PMXEditor 就能看得很清楚。动画错误的话,差异还是比较明显的,可以比较索引中的 IK 测试和动作修正两个视频。所以为了让土豆的模型使用 MMD 的动作,必须要调整手臂的旋转。这一步我目前是用代码完成的,不过手工也比较简单,在 PMXEditor 中修改保存即可。 最后,MMD 中大量使用了 IK,而土豆的模型是没有 IK 关节的。怎么办呢?生成呗。原理还是很简单的,对着模型照猫画虎,找规律就行了。