Skinmesh 蒙皮 在最终的渲染结果中,蒙皮将完全显示出来,蒙皮实际上就是顶点、法线和纹理坐标等将被渲染的元素。 而其中,最关键的当然是顶点,顶点将直接被骨头牵扯运动,因而使得整个模型呈现骨骼所决定的样子。
Skeleton 骨骼 骨骼是一种抽象的概念,在最终的渲染结果中,它不可见。类如人体骨骼,骨骼是若干骨头(Bone)成树状的集合体,而每块骨头又分别与若干数量的蒙皮顶点关联。 当骨头运动的时候,与之关联的所有蒙皮顶点也会受骨骼的影响而运动。
骨头与蒙皮顶点的关联需要考虑到每块骨头对蒙皮顶点的影响。尽管大部分情况下,一个顶点将仅仅被一个骨头的影响,但是关节处的顶点往往被多根骨头影响,例如踝关节,可能会分别受小腿骨50%和脚骨50%的影响,这种影响叫作权重(Weight)。在这种情况下,我们称踝关节的这些顶点,受小腿骨影响的权重是50%,受脚骨影响的权重也是50%。Bone 骨头 spine 是骨骼编辑器,所以骨头是基础。每个骨头都会有 位移T/缩放S/旋转R 的属性(TSR属性)。骨头可以有子节点,最终形成了一个树型结构。可以对应2dx 里面的 node。
插槽 骨头上的一个挂载点。不是所有的骨头上都能放置东西的,因为很多骨头其实只参与计算,真正重要的骨头,也就是需要挂载其他东西的骨头上必须放置插槽。slot 只是用来标记特殊的骨头位置,本身只有一个颜色属性,也可以说,重要的骨头节点可以称为 slot。Attachment 附件 挂在插槽上的内容,可以是图片,也可以是判定区域,只要是你能想到的东西,都可以当成附件。
Draw order 描画顺序 骨架上插槽的一个顺序列表。用来控制描画的先后顺序。
Animation 动画 基于时间轴的一个骨头状态列表。
Skin 皮肤 一套Attachment(附件)的集合,类似于换装。
Bounding Box 边界框 用来指定骨头上的边界的多边形的区域。
atlas 图集 贴图集合,小图片合并在一起,就成了图集
二、实现
上面大致介绍了一些基本概念,然后我们从实现角度上来说下为啥这么设计。
(1)首先,假设我们需要一个骨骼系统。于是,我们就设计了一个树状的骨架,每个节点就是(Bone)。
(2)再想下,骨头上要放图片啥的,于是我们就需要访问到特定的骨头,遍历太傻了,好吧,我们给这些骨头加个名字,这样就能访问到具体的骨头了,那这些名字就叫slot。
(3)好吧,可能有些人觉得,slot 和 bone 本质上一样,为啥需要分开呢,没必要的。我只能说事情其实并不简单。来想下,我们已经有了一个完美的骨架,图片也在应该在的骨头上了。那我们该如何显示图片么?遍历么,从根结点开始,一直到最下层的节点,不管你用啥排序,这个顺序是固定的,但是现实总是很残酷,很多时候,我们需要不停调整图片描画的顺序,也就是调整树的节点排序。那怎么办,我们指定下骨头描画的顺序吧(Draw order),这些特定的骨头也就是 slot。
(4)你看,这下完美了,也就是 bone 用来计算位置,slot 用来控制描画。
(5)完美的骨骼系统,一定要有碰撞区域(bounding box),这和图片差不多,一个用于显示,一个用于边界判断,好吧,那就抽象成一个概念叫(attachment),于是,slot 上就可以附加不同的 attachment 了。
(6)终于可以换附件了,但是一个一个换好累。于是,我们把一组附件合在一起,组成了 skin。这下简单了,一换 skin,整个世界就变样了。
(7)啊,做着做着,就发现图片太多了,要优化啊。怎么办,简单,把小图片合在一起,每个图片对应了一个大图里面的一个区域,这就是 atlas。