动画技术简介
挑战1
- 互动性和动态性。
- 动画系统必须能够实时响应玩家的操作和环境的变化。
- 动画系统需要与其他游戏系统(如物理引擎、AI系统等)紧密合作。
挑战2
- 游戏动画需要在实时环境中每帧计算,这对性能提出了要求。
- 动画数据量巨大,包括模型、纹理和动画数据,需要有效的管理和优化以减少对磁盘和内存的占用。
挑战3
- 游戏动画追求更生动的表情和更真实的体验,这要求动画具有更高的细节和复杂性。
- 动画技术如面部动画、布娃娃物理(Ragdoll Physics)和动作匹配(Motion Matching)被用来增强游戏的真实感和玩家的沉浸感。
2D动画
Sprite animation
把动画中每一帧的动画记录播放。
doom用2D的方式做3D的动画。
特效系统中用到了序列帧的方式。
Live2D
把角色所有的元素(比如眼睛、头发)全部变成一个个小的图源,把图源拼在一起变成一个大资源。
每个图源通过旋转、放缩、warning(仿射变换)。
对图源设置深度,可以实现出现还是不出现。
对图源生成控制网格,拥有控制点。通过控制点,就可以调节不同的样式。
3D动画
动画就是基于对刚体运动、刚体自由度的一个表达。
6DoF
DoF Degress of Freedom:自由度,指一个物体可以在多少个维度进行变化。
对于刚体来说,在整个空间中运动的自由度就是6个自由度。
刚体有平移的3个自由度,3DoF。
刚体可以沿着x、y、z轴为中心,沿着其转,这里就是3个自由度3DoF。
Rigid Hierarchical Animation
刚体层次动画。
最基础的动画系统。
per-vertex Animation
顶点动画。

比如旗帜。
对一个顶点每一帧的变换存储下来。
基本上是先模拟出动画,然后存储下来变成texture,在实际中就直接使用。
Morph Target Animation

顶点影响权重。
每个顶点之间的权重会进行插值。
主要用于人脸中。实际中比如游戏中的捏脸系统。
3D Skinned Animation
3D的蒙皮动画。

每一个顶点都受到多个骨骼同时作用。
2D Skinned Animation
2D和3D中的原理是一致的。
Physics-based Animation
布娃娃系统。
衣料。
IK 反向动力学。
Animation Creation
编辑器中动画师手K(K Free)动画。
动捕。
蒙皮动画
让Mesh动起来
- 创建绑定姿态的网格:首先,你需要一个网格模型,它处于一个标准的姿态,这样便于后续的动画制作。
- 为网格创建绑定骨骼:然后,你要给这个网格模型添加一个骨骼结构,骨骼是用来控制模型动作的基础。
- 分配蒙皮权重:接下来,你要为网格上的每个顶点分配权重,这些权重决定了顶点如何随骨骼移动。
- 骨骼动画化:之后,你可以通过移动和旋转骨骼来制作动画,让角色或对象动起来。
- 通过骨骼和权重动画化蒙皮顶点:最后,当骨骼移动时,网格上的顶点会根据之前分配的权重跟着移动,这样就完成了整个动画过程。
坐标系

World Space:世界坐标系。
Model Space:以模型自己为中心的坐标系。
Local Space:局部坐标系。动画中的每一个骨骼自己的坐标系。
骨骼构建

- Humanoid Skeleton 类人形:树状结构,七点在人的胯部(脊椎的最后一个骨头)
- No-humanoid Skeleton 四足动物
Bone和Joint

游戏引擎中,骨骼(Bone)实际存储的是肘关节(Joint)的数据。
实际游戏中的骨骼

可能考虑到眼睛眉毛,人身上的变形(武器、翅膀)等等。
武器骨骼
一般来讲武器是在人物的主骨骼上有一个武器的骨骼,一般是绑在手上的。

包括人在骑乘时,也有一个骑乘的骨骼。
Root Joint

一般定在两腿之间。
当决定角色的移速、跳跃的高度等,都是用Root Joint来处理。

如果是非人骨骼,那么其Pelvis Joint骨骼放在马的尾椎处,而Root Joint则放在马肚子下面。
Bind Animation

人播放人的动画,马播放马的动画。
人上面有一个Bind Joint和马的Bind Joint重合在一起,这个Bind Joint空间、旋转等数值都是重合的。
Bind Pose

T-Pose角色的肩膀部分是被挤压的,需要做精细的肩胛处的变形的动画时,精度就不够。因此现在的3A会用站的比较自然的A-Pose。
Skeleton Pose

把很多的Pose连在一起时,会变成一个动画。
真正表达动画的Pose时,有九个自由度(9DoFs),还有个放缩。
放缩比如有人脸的变形、角色弹性变化时会用到。
三维旋转的数学原理
二维定向数学

普通的θ或者笛卡尔坐标系。
三维的定向数学
欧拉角

绕着任意轴旋转。分别沿着x、y、z旋转角度,叠加后可以得到一个旋转的矩阵(图中那个R方程)。
把任何一个空间上的点带入之后,就可以得到一个欧拉角。
Yaw-Roll-Pitch
Yaw-Roll-Pitch就是欧拉角的另一种表达

- Yaw:航向角
- Pitch:公角
- Roll:翻滚角
Gimbal Lock 万向锁
Gimbal Lock 万向节(万向锁)
相机的“稳定器”、无人机、“微云台”、陀螺仪
存在的问题
问题1:

计算是顺序依赖的。(旋转的顺序不同,得到的结果就不同)
使用欧拉角时,得提前定义旋转顺序。
问题2:

沿着y轴转了90°之后(β=90°),z轴实际是和x轴共轴了,那这时沿着z轴做的任何旋转实际上都没有意义。只有两个旋转之间(α和γ之间的差值)才有意义)
问题3:
比如有(α1,β1,γ1)和(α2,β2,γ2)。
这里非常难以得到差值,这两个的差值不能简单地在线性上加减得出来。
问题4:
如果要对一个物体先做一个(α1,β1,γ1),再叠加一个(α2,β2,γ2),这时的表达不能简单的用α1,β1,γ1,α2,β2,γ2这六个值加在一起就能表达出来。
问题5:
欧拉角通过xyz三轴的旋转来表达,但是实际中物体并不是严格的按照空间上的xyz去做的。
给定一个定轴时(定轴运算),就会非常难。
四元数
只有在三维空间中,才能用四元数。(群论的东西,但是看不懂,老师也看不懂。。。)

定义了三个虚部:i j k(对应3个单位轴),对于任意一个旋转,可以尝试用一套公式去表达(q的那个方程)。
乘法就是单位轴向量在做叉乘。
逆就是表示旋转的逆。
欧拉角转四元数

蒙皮动画的实现
Joint的表达处理
旋转变化

大多数的动画中,都只有旋转的变化,是动画中最核心的。
平移变化

站立和蹲下时,pelvis root(尾椎的那个骨骼)会发生变化。
表情动画、特殊的机械动画等都有平移动画。
放缩变化

面部表情中可能会用到,一般来说都不会用。
Affine Matrix 仿射矩阵

Joint数据存储
动画的数据一般是存在local space中,即只会存储相对于“父亲”的变化。

- 当动画全部存在model space中,做差值时,骨头会一会边长一会变短(如图中右侧那样)
对于骨骼来说,只需要知道其父骨骼和父骨骼在local space长什么样。
local space—>model space:从根节点开始,一个骨骼一个骨骼算下来。
Skinning Matrix 动画矩阵

- 没听懂。反正好像这个恒等式很重要。
大概的理解:通过这些矩阵的计算后,每个骨骼(joint)会一个自己的skinning matrix。这些在存储时,是由专门的数据结构来存储的:

然后在GPU中,为了用在shader中,又有一个公式去计算,算出一个skinning matrix palette:

多关节蒙皮动画
多关节蒙皮动画允许单个顶点与多个骨骼相关联,特别是当模型的某一部分需要由多个骨骼共同影响时。
例如,一个角色的上臂可能同时受肩膀和肘部的影响。
多关节蒙皮混合
蒙皮混合是多关节蒙皮动画中的一种技术,它通过计算顶点在不同骨骼影响下的位置,然后根据权重进行插值计算出最终位置。
这种方法可以避免模型出现不自然的变形
插值
后面这里讲了一堆的插值,应该是动画系统中实际的一些处理,实在是没听懂。。。。跳过了。
管道渲染

大量动画的clip,存在角色的各个pose(frame)。
差值算出真正的pose,转换到model pose中。
然后将每个骨骼算成自己的skinning matrix palette,接着就是GPU运算每一个顶点动起来。
动画数据压缩

- 大部分的骨骼放缩都是1,位移其实也可能是不变的,大量的数据是旋转。
对于不变的数据,直接只存一个值。
对于rotation,引入keyframe(关键帧)的概念,通过关键帧之间的插值可以算出。
动画制作流程
构建mesh。
制作骨骼骨架,增加一些物体的骨骼,root等。
蒙皮骨骼刷权重。
制作动画(制作关键帧)