主要是欧拉角和四元数的概念、使用四元数和位移、放缩矩阵表示关节的运动,以及如何使关节的运动绑定到Mesh Vertex上。
Table of Contents
2d动画技术
- 就是循环放图片,对称的动画的话也会有循环反转图片之类的方法来省内存。
- 2.5D的那个DOOM的多角度2d动画现在3d游戏中也常用,省计算资源。
- Live2D:将整体的图形分为控制网格、图层和图元,对其进行变换,做二次元手游用可以大幅省成本。
3d动画技术基本概念
DoF(自由度),刚体动画(类似皮影戏,会穿模),顶点动画(布料、流体等使用),Morph Target Animation(比较像顶点动画),2D、3D蒙皮动画(由骨骼带动模型来动,解决刚体动画的穿模,目前最常用),基于物理模拟的动画……
蒙皮动画技术
蒙皮动画和刚体动画的不同在于蒙皮动画的Mesh会受骨骼运动的影响,并且有权重的说法,一个面片可能受多个骨骼影响。骨骼本身也受其它骨骼影响,比如手部同时受小臂、大臂的骨骼影响等。
骨骼
骨骼系统存储的其实不是骨骼,而是由一个个关节构成的树。对于类人型生物,根位于最后一节脊椎(Pelvis)正下方地面位置(类似手办的支架接地点,方便表示位移等),然后连接到最后一节脊椎,然后一级级连接到全身;对于四足生物,根在肚子下方地面,连接到尾椎。骨骼不一定只包括角色本身,骑乘物、武器等的骨骼也被添加到角色的特定关节上,比方说上马、上车等,就是放一段动画然后人的某个关节与骑乘物的某个关节绑定(两个关节坐标系会完全重合)。
如何在3D空间表达旋转
欧拉角
二维空间中旋转的表达:
相比二维空间中的旋转只有一个轴,三维空间中有3个旋转轴,将这三个轴分别的旋转量乘起来能得到任意轴的情况(欧拉角):
注意顺序要约定好不能乱,矩阵乘法没有交换律,设为全局坐标系,为物体本身的坐标系,这里他用的是的顺序也就是先偏航再俯仰再横滚:
不同顺序结果不同(参考):
这里有个问题:假设俯仰(或者在任何顺序下的第二次旋转)角度为,显然,接下来的横滚操作相当于绕全局坐标系轴旋转,而第一次偏航操作也是在绕全局坐标系轴旋转,这种时候相当于只有两个旋转轴了,也就是欧拉角退化了(万向锁)。
使用欧拉角描述3D空间的旋转的其它问题有:不能进行线性插值、两次旋转没有可加性、如果不知道相对的旋转只知道绕任意轴的旋转则还要再算出来、知道旋转过的角度难以推导逆回去需要怎样的旋转等。所以一般用于编辑器(因为符合直觉,便于游戏开发者使用),不用它做动画。
四元数基础知识
(参考)考虑到可加性,汉密尔顿注意到使用类似复数的形式表示角度,其具有“可加性”(乘起来):
在二维平面中,如果想要旋转(也就是已知一个点在坐标系中的位置为),只需乘上,就可以得到这个点在旋转后的坐标。
于是推广到三维空间(可以证明,不可以推广到更高维),也就是四元数:
(这两张图里乘法运算的矩阵的右边几列的设计是为了按照虚部乘起来是负一的规则得到和直接四则运算乘法一样的结果,类似二次型的感觉,以便使用矩阵运算)
(从这一行表达式也能得到等关系,类似笛卡尔坐标系下的叉积)
(图里右侧是四元数的模、共轭和逆的定义,对于单位四元数,其共轭等于其逆)
这样的话已知一个轴和旋转角度,经过各路大佬研究,不能直接乘,应当:
- 定义如上图的纯四元数
- 定义、
- 进行图里那个很像二次型求特征向量的运算
最后得到的还是一个四元数,其第一项为0,后三项是右手法则旋转后这个点新的坐标。
四元数的应用
使用四元数,求逆就可以求反向旋转或者指定两个位置之间怎么旋转过去、旋转叠加可以直接将两次旋转相乘等操作。
欧拉角转四元数:
也就是说不管刚体现在是什么姿态,总存在一个轴,使得刚体绕着这个轴转一个角度后就可以到达另一个指定的姿态,而四元数描述的就是这种转动。
四元数可以变换成3×3的旋转矩阵。四元数对应的旋转矩阵可以表示为如下形式:
四元数可以进行归一化压缩, 把四元数所在的区间归一化,用定点数表达,具体怎么实现的没看懂。
关节与蒙皮
关节姿态有朝向、位置、延不同轴的放缩等参数,对应的操作都能使用矩阵表述,合起来就是仿射变换的矩阵:
动完之后位置的计算就是从根节点开始一个个算下去(一路累乘下来);关节的运动如何映射到蒙皮上呢?最基本的恒等式是每个Mesh Vertex在模型局部坐标系中的坐标不变,与绑定时相同(即)。具体的计算方法如下:
的计算,第一个等号好理解是说用关节在模型坐标系的变化的矩阵乘上顶点在局部坐标系相对关节的位置就是变化后的位置,然后第二个等号是将后者拆成了关节在绑定的时候在模型坐标系中的位置的逆乘上顶点在绑定的时候在模型坐标系中的位置(即)。这样式子就拆成了三项,第一项是会变的,中间一项是不变的,这个逆提前存好,最后一项是Mesh中存的坐标也是固定的(至少这次运算中是固定的)。真正渲染的时候最后再乘上一个到世界坐标系的变换。
蒙皮动画中每个顶点都与多个关节绑定,权重会不同,运算的话就是在每个关节动的时候都算一下这个点的坐标,然后加权平均。这也是为啥前面的运算都要在模型坐标系(转换这么麻烦),因为加权平均总不能在各自的坐标系。
动画插值
游戏中实际存储的动画片段可能只有一二十的帧率(不一定均匀,比方说使用Catmull-Rom Spline确定哪里是关键帧,弄得不好的话表现出来会很抖,因为矩阵一路乘下来误差会累积,可以用Visual Error等指标判断压缩效果,然后可以修改关键帧进行补偿),然后游玩的时候插值到玩家的帧率。
动画的全部数据都是根据局部坐标系,这样默认局部坐标系原点(应该就是关节本身的位置?)是旋转中心便于插值,否则还要算旋转中心什么的。
插值分线性的(Linear interpolation,LERP)和非线性的,非线性的比如说NLERP和用到三角函数的SLERP。
总结
计算动画的整个过程就是,首先根据动画片段的数据和时间确定当前帧和下一帧的内容,然后插值得到局部坐标系坐标,然后转到模型坐标系,然后利用关节的数据算出Mesh。
动画制作过程
艺术家会先用低精度模型做动画。
关节的地方记得多加Mesh。
蒙皮与关节绑定的权重是自动调的,动起来可能会像橡皮糖的质感,需要艺术家手动再调一下,操作类似涂色游戏,颜色深浅代表权重。
导出动画的时候根的位移要单独导出来一个位移曲线。