文章目录
- 一,动画技术简介
- 动画技术的挑战
- 二,2D游戏动画技术
- 2.1 精灵动画(sprite animation)
- 2.2 Live2D
- 三,3D游戏动画技术
- 3.1 基于层次的刚体动画
- 3.2 顶点动画
- 3.3 Morph Target Animation
- 3.4 蒙皮动画
- 3.4.1 2D蒙皮动画
- 3.5 基于物理的动画
- 四,蒙皮动画的实现
- 4.1 如何制作一个模型动画
- 4.2 Local Space、Model Space and World Space
- 4.3 骨骼的构建
- 4.4 骨骼的绑定
- 五,3D旋转的数学原理
- 5.1 2D旋转
- 5.2 3D旋转
- 5.3 欧拉角:Roll、Pitch、Yaw
- 5.4 欧拉角的问题
- 5.5 四元数(Quaternion)
- 六,蒙皮动画的细节:关节与蒙皮
- 6.1 蒙皮计算
- 6.2 动画帧间Clip
- 6.3 引擎侧动画系统pipeline
- 七,动画压缩技术
- 7.1 DoF压缩
- 7.2 数位压缩
- 总体压缩
- 压缩误差
- QA
一,动画技术简介
人类祖先就喜欢通过画画试图把动态的人物画下来,近代发现了视觉残留(1/24秒),奠定了动画视觉实现的基础
早期尝试:跑马灯、定格动画、早期动画电影(一帧一帧画的)等
未来方向:实时渲染动画、电影(Zafari)
动画技术的挑战
- 游戏中的动画是要与很多gameplay、地形、怪物交互,还受用户控制的影响
- 实时是基础,不仅包括计算,还有动画数据的加载定位、内存数据处理等
- 对自然感真实度的要求,角色如何表现得是否生动,是否符合物理,以及表情动画的实现(与肢体动画是2套技术体系)
并且当下很火的虚拟人最核心的技术就是动画技术
二,2D游戏动画技术
虽然3d很火,但现在最赚钱的还是2d游戏,并且有很多有意思的新技术
2.1 精灵动画(sprite animation)
通过把游戏的人物的动画一帧一帧记录下来,然后循环播放来实现动画的效果。(仙剑1、2)
除了人物动画,特效类也可以这么做
2.2 Live2D
皮套人嘿嘿
把角色的各个部件拆成一个个的小图元,把这些图元拼在一起,然后靠这些图元的旋转、变形、仿射变换等使角色变得更加鲜活。并且需要给各种图元设置深度来表达层次关系,控制可见性。(本质就是图像变形+图层叠加)
三,3D游戏动画技术
- 自由度(DoF,Degree of Freedom)
字节出的vr眼镜宣传能支持6DoF,那什么是DoF呢?
定义:一个物体可以在多少个维度发生变换。比如平移就是三个自由度(在x,y,z方向上移动),旋转也是3个自由度(物体绕x,y,z轴旋转 )。通常动画是9DoF的(就是Transform那9个量),因此6DoF就是…………
3.1 基于层次的刚体动画
早期动画实现方式,类似皮影戏,将角色用一系列的刚体块(mesh绑定骨骼)表示,用关节点约束。
但皮影戏一样,这些骨骼动的时候mesh会互相穿插。
3.2 顶点动画
预烘焙顶点动画,离线下将每个顶点的复杂物理计算结果按照时间帧保存到一张纹理上,横轴表示顶点,竖轴表示不同时间每个顶点的偏移量。一般会存两个texture,一个texture存位置,一个存法向。
3.3 Morph Target Animation
另一种顶点动画,是把一系列key frame保存下来,应用是lerpkey frame去使用,通常用于人脸动画(类似BS)
3.4 蒙皮动画
骨骼驱动顶点的动画,每个顶点有不止一个骨骼驱动,可以避免mesh穿插;同时消耗也比逐顶点小
3.4.1 2D蒙皮动画
2D有时也用蒙皮骨骼动画,更加灵活效果丰富
3.5 基于物理的动画
- Ragdoll布娃娃系统
- 布料和流体模拟
- 反向动力学Inverse Kinematics(IK)----给出指定点计算身体怎么运动最自然,用于游戏物体、地形交互等
四,蒙皮动画的实现
4.1 如何制作一个模型动画
整体上,the Animation DCC(Digital Content Creating) process 分为:
- 制作一个有着固定姿势的mesh(T-pose)(一般用低精度mesh制作动画,在某些关节会再新额外加一些mesh来优化比如咯吱窝)
- Skeleton binding骨骼绑定
- Skinning蒙皮,刷权重(现在基本是自动计算的,只需部分手工微调)
- Animation creation将骨骼设置为所需姿势
- Exporting导出(注意如果像跳跃动画里root也位移了的话,一般不会保存到动画数据里–压缩了,会有一个专门的位移曲线来记录)
4.2 Local Space、Model Space and World Space
局部空间 – 以骨骼局部为参考系空间,坐标都是相对坐标
模型空间 – 以模型为参考系的空间
世界空间 – 以游戏世界中心为参考系的空间,坐标是绝对坐标
4.3 骨骼的构建
人类骨骼有几种通用标准,比如人形骨骼(Humanoid)标准,其骨骼起点一般是在胯部的RootM,其他骨骼一层层形成骨骼树,互为父子节点。一般还有一个两脚之间的根骨骼Root,方便判断移动,位置,离地高度等(下图右可见)。此外还有面部的骨骼、外骨骼(衣物、道具)等。
- 游戏中存储的实际是关节的数据(位置旋转等),通过父子节点关系影响骨骼链
- 人体骨骼一般50-100根,需要TA团队在游戏初期就设计好, 算上人脸骨骼和外骨骼可能总数300+
动物,比如四足动物是另外的标准,骨骼起点一般在尾椎的地方,Root根骨骼一般在四足中间
4.4 骨骼的绑定
例如人骑在马上,人和马都有一个叫 mount 的关节。该关节是用来绑定人和马的,不仅要连接,方向也要绑死,这样人和马的运动才能保持一致
五,3D旋转的数学原理
线代知识,少量记录
5.1 2D旋转
5.2 3D旋转
5.3 欧拉角:Roll、Pitch、Yaw
yaw:绕z轴 (ψ)
pitch:绕x轴 (θ)
roll:绕y轴 (φ)
5.4 欧拉角的问题
- 旋转顺序依赖:如果轴旋转的顺序不同得到的角度不也不同,所以必须约定旋转顺序,旋转矩阵也很复杂。
- 万向节死锁问题:(比如拍摄稳定器、陀螺仪都用的是万向节技术)
首先我们旋转每个轴的顺序是固定的。例如,按x,y,z轴顺序旋转,x轴先旋转,此时如果把y轴旋转90°时,z轴会被旋转到x轴的位置,此时还需要旋转依次z轴,但是此时旋转z轴就相当于旋转x轴,相当于只转了两个维度,本来是3个自由度(可以对x,y,z轴旋转),现在变为了两个(只能对x,y轴旋转,而不能旋转z轴)
注:这里的x,y,z轴都是相对世界坐标系而言的
- 插值和叠加问题:在如角色动画关键帧需要插值计算中间帧的方位角或旋转过程,这个时候插值就很困难,线性插值结果是错的。同时机械臂父子节点的旋转叠加也不能直接欧拉角(cos(α+γ) != cosα+cosγ)
- 表达问题:欧拉角只能按x,y,z轴旋转,但是现实中的旋转的旋转可以按任意轴,欧拉角并不能很好地、直观地表达。
5.5 四元数(Quaternion)
在二维空间,旋转某个角度可以用归一化的复数 e − i θ = c o s θ + i s i n θ e^{-iθ} = cosθ +isinθ e−iθ=cosθ+isinθ来表示,在三维空间内我们定义一个四元数q = a + bi + cj + dk,其中a为实部, bcd为虚部。见下图,计算类似矩阵运算
- 欧拉角到四元数:
- 用四元数计算旋转:(向量变成四元数)
- 四元数的反向、叠加、从u转到v等
- 四元数绕轴旋转
啊太困了有需要再仔细看吧
六,蒙皮动画的细节:关节与蒙皮
6.1 蒙皮计算
关节的Pose有三个维度:
Orientation(方向、朝向):一般只需要Rotation即可表达骨骼链的位置
Position:某些情况也需要用到位移,比如root骨骼表达的位置、人脸骨骼等
Scale:面部表达经常用,调整五官大小(类似2d美颜)
以上3个变换合并起来形成了仿射矩阵Affine Matrix:
蒙皮动画只保存顶点相对骨骼local space的旋转变换,也就是Affine Matrix,以及骨骼权重;通过这些参数就能确定顶点位置。
- 这里老师讲引擎侧的骨骼局部坐标和世界坐标怎么转换计算,就是先算骨骼的转换矩阵,再通过驱动顶点的矩阵反向计算相对坐标,再计算位置。并且在骨骼之前(MVP流程?)还需要计算骨骼的世界坐标系矩阵道一次。
- 注意骨骼权重插值需要在模型空间插值,而不是局部空间
6.2 动画帧间Clip
动画资产一般是十几二十帧,远小于实际游戏帧率,所以应用时需要插值(clip)
- 针对位移和缩放,一般直接线性插值即可
- 针对旋转,四元数线性插值后再取normalization,这样也是避免长度发生变化(Nlerp)—但插值不是线性的
- 插值中值得注意的是,当两个变换q1和q2相乘结果小于0时,可能会出现错误,例如本来只需反向转30度,现在正向转了330度,从而导致插值结果从 -30~0 变为0 ~ 330。因此需要计算插值的角是否大于180,如果大于,则反向插值:
- 四元数插值是不均匀的,头尾快中间慢,因此提出一种slerp的算法来按角度进行插值,但这种计算方式稍微贵一点,同时分母sin值很小时也不稳定,所以实际中通常在角度差距大时用slerp,差距小时就直接用lerp了
6.3 引擎侧动画系统pipeline
七,动画压缩技术
现代3A游戏动画量非常大,所以必须压缩好
7.1 DoF压缩
- 对大部分骨骼来说,其translation和scale都不怎么变化,所以可以直接去掉;
- 针对旋转,比较简单的方法是使用关键帧Key Frame进行插值,对动画的每一帧进行插值,当插值误差超过一定阈值时就设为关键帧,因此关键帧的间隔不是固定的。
- Catmull-Rom Spline:关键帧虽然减少了数据,但插值出来都是折线,使用Catmull-Rom Spline在两帧P1P2之外分别再取P0P3,然后拟合这个曲线可以缓解。(类似贝塞尔曲线)
7.2 数位压缩
四元数很多时候不需要32位浮点数的精度,所以可以将数值压缩到0-1之间然后乘以65535用16位整数去表示。
具体的,针对四位数Quaternion,利用其normalization后的特性(四元数的四个值中有一个较大,其余的都在正负
1
√
2
\frac{1}{√2}
√21之间,并且4个数的平方和为1),因此可以直接保存3个较小的值去表示大值,如下图,可以用48bit表示128bit的数据
总体压缩
压缩误差
压缩会带来误差累积问题。所以需要检测误差是不是被控制在可接受范围内。
不同骨骼对error的敏感度是不一样的,DoF那几个量的误差虽然更直观,但不符合人眼的感受,最实际可用的误差是visual error视觉误差(模型所有点用压缩前后的数据计算完之后进行比较),但完整计算的量太大,所以一般对每个关节定义2个垂直点,通过offset控制距离,如果精度敏感就设置大一些,只需对比这两个点压缩前后的error即可
误差补偿Error Compensation:在多帧误差累积后反向进行偏移来补偿。其问题就是这一帧和上一帧会很不连贯,会产生抖动问题。
QA
- 顶点绑定的关节有数量限制吗:为了限制计算量,实践中不超过4个;并且关节数量也最好不超过255个,方便数位存储
- 骨骼和场景碰撞的动画怎么做的:场景交互的动画并不是用一根根骨骼和场景计算碰撞的,而是用刚体进行碰撞
- Morph Target动画与蒙皮动画的区别:蒙皮动画驱动骨骼影响顶点,而Morph Target动画存储顶点位置