Direct X 12 – Character Animation 角色动画

在本章节中,我们将学习如何实现复杂的角色动画,例如人类或者动画。角色动画更为复杂是因为当他们在移动时,其身体的部件也将会运动。假设一个人在奔跑——那么他身上的每一根骨骼都在运动。而创建这一类型的复杂动画,一般需要借助专业的模型与动画工具。假设我们已经拥有了角色模型与相对应的动画数据,本章节中我们将学习如何使用DX12让其成为“动画”。

目标:

1. 熟悉动画蒙皮网格模型。

2. 学习网格层级转换的数学原理以及如何转换树状网格层级。

3. 了解顶点融合的原理。

4. 学习如何从文件中读取动画数据。

5. 学习如何在DX12中实现角色动画。

23.1 结构层级

许多物体是由多个组件组成,且组件直接有着“父子”层级关系,也就是说子物体可以在其自身的物理限制内独立运动,但是如果父物体运动时,子物体不得不也进行相应的运动。例如,我们将手臂分成三个部分,上臂,下臂以及手。手可以基于手腕随意转动;但是,如果下臂绕着肘关节转动,那么手一定也会转动。因此我们可以将物体的层级定义为:手是下臂的子物体,下臂是上臂的子物体,如果我们进一步扩展,上臂就是躯干的子物体等等,直到我们遍历所有的骨骼(如下图所示)。

上图展示了一个较为复杂的树状结构,模拟了一个两足的人形角色。向下的箭头表示“第一个子物体”,向右的箭头表示“兄弟”关系。例如,“左大腿”,“右大腿”以及“下脊柱”都是“盆骨”骨骼的子物体。而本小节的主要目的就是展示如何基于一个物体的位置以及其父物体的位置(例如,它的上层父物体,上上层父物体,上上上层父物体),来决定其位于场景中的位置。

23.1.1 数学公式

为了让各位老铁更容易理解,作者在书中所使用的层级关系比较简洁,分别为上臂(根节点),下臂,手,它们对应骨骼0,骨骼1以及骨骼2(如下图所示)。

所以,对于上述层级关系中的节点或者说物体,我们如何将其转换至世界空间内呢?显然,我们不能直接将其转换至世界空间,因为我们必须考虑到每个节点的父节点,父节点也会直接影响子节点在场景中的位置。

层级中的每个物体都是基于其本地坐标系并且以连接处的中心作为坐标系的原点进行旋转(如下图所示)。

因为所有的坐标系都处于同一个空间,我们可以对它们进行关联;在某一时刻(一般来说,层级动画都是与时间相关联的)我们将每一个坐标系与其父物体的坐标系进行关联。(根节点坐标系F0的父坐标系就是世界坐标系W;这就是F0与世界坐标系之间的关系。)现在我们已经知道了子坐标系与父坐标系之间的关系,所以我们可以通过一个转换矩阵将子物体坐标系转换为父物体坐标系。(其原理与本地坐标系至世界坐标系的转换相同。现在我们只是本地坐标系转换为父物体的坐标系。)假设矩阵A2能够将F2转换至F1,假设矩阵A1能够将F1转换至F0,假设矩阵A0能够将F0转换至W(世界坐标系)。(我们将A(i)称为to-parent矩阵,它能够将子物体的坐标系转换至父物体的坐标系。)之后,我们可以使用矩阵M(i)将上图的手臂层级关系中的第i个物体转换至世界空间:

在我们上图的例子中,M2=A2A1A0M1=A1A0M0=A0,这三个矩阵分别将手,下臂,上臂转换至世界空间。同时我们可以观察到,每个物体都将继承其父物体的转换;举例来说,如果上臂发生了位移,那么手也会发生位移。

我们所使用的例子只是一个简单的线性层级。但是,其原理可以运用于到复杂的树状结构;也就是说,层级中的任何物体,为了求出世界空间的转换矩阵,我们需要“向上”遍历所有父物体的to-parent矩阵直到世界空间(我们假设根节点的父物体坐标系就是世界坐标系)。唯一的区别就是树状结构的数据结构比起线性结构更为复杂。

例如,在本小节开头处的树状结构图中的左锁骨。其与颈部骨骼是兄弟关系,因此其也是上脊柱的子物体。上脊柱是下脊柱的子物体,同时下脊柱又是盆骨的子物体。因此,左锁骨的世界坐标系转换矩阵依次由左锁骨的to-parent矩阵,上脊柱的to-parent矩阵,下脊柱的to-parent矩阵,盆骨的to-parent矩阵组成。

留下评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据