Skip to content

SkeletonAnim 骨骼动画

RoySkinMeshComponent的组件对骨骼动画做了封装。它是继承自RoyMeshComponent,也就说它首先拥有了把网格模型转化为可渲染对象(RoyObject3D)的能力,对这部分的理解请参考RoyObject3D。在本小节,我们重点关注集成的骨骼动画能力。

骨骼动画中的骨骼,实际上是一个树形结构,与场景组织的树形结构类似,每一个节点也包含一个Transform矩阵,代表了这个骨骼节点在模型本地空间中的偏移。一般来说骨骼的数量因制作的内容不同而不同,骨骼数越少,性能越好。一般人体可以使用几十个骨骼节点来表达。当骨骼运动的时候,实际上是这颗骨骼树在运动和变化,即每个节点的Transfrom矩阵变化。

模型中的每一个顶点,都会附着到骨骼上,一般来说一个顶点会受到4根骨骼的影响,而每个骨骼对这个顶点的影响也不同,用权重来表达,如4根骨骼对应的权重就是一个Array(4)。这个过程有一个形象的词汇:蒙皮,所以骨骼动画也叫做骨骼蒙皮动画。骨骼是矩阵,血肉就是模型的顶点。

至此模型上多的信息有:

  • 全局的骨骼矩阵的列表,Mat4[]
  • 顶点buffer中,描述每个顶点受到那些骨骼影响的数据,Uint4
  • 顶点buffer中,描述每个顶点受到骨骼影响的权重数据,Vec4

一个顶点往往描述了其在模型本地坐标空间中的位置,当渲染到屏幕的时候会乘上世界矩阵变换到世界坐标空间,在执行后续的渲染流程。当有骨骼动画的时候,模型中的顶点,需要按照权重先乘以其受影响的骨骼矩阵计算出在当前帧的骨骼动画中,所处于的模型本地坐标空间的位置,然后再变换到世界空间走后续的渲染管线流程。

我们已经知道骨骼就是一组矩阵,如果在不同的时间点上,这组矩阵可以插值得到,那么就形成了这个矩阵数组(骨骼数组)的不同姿态,将这些姿态结合蒙皮信息在连续的一段时间内应用于顶点,就形成了连贯的动画。在未应用任何骨骼矩阵之前,模型的顶点本身也有一个姿态,我们把这个姿态成为T-Pose。

以上大致表述了骨骼动画的各个方面,下面我们来看RoySkinMeshComponent的实现:

  • 持有一个RoyAnimator的实例,它持有了骨骼节点树,并提供插值功能。
  • 持有一个RoySkinInfo的实例,它保存了骨骼插值的结果,最终会传递给渲染对象RoyObject3D。
  • 动画的其他方法,如播放、停止、播放速度、是否要循环播放等。

场景中所有的RoyAnimator都会被收集,在渲染之前进行骨骼矩阵的插值,并将结果放到RoySkinInfo,传递给渲染对象RoyObject3D,RoyObject3D发现自己有这个结构体,那么上传到GPU,驱动GPU渲染。

Glb本身是一个支持骨骼动画的模型格式,我们在GlbLoadComponent中也解析了这部分数据,所以如果一个glb文件带有骨骼动画信息,会自动创建RoySkinMeshComponent,否则创建RoyMeshComponent。