Unity 动画
整理一下先前做动画的收获
骨骼动画
- 序列帧动画:记录动作的每一帧
- 非矢量动画:每一帧是固定不可复用的,新的一帧本质上是完全重画一次物体,没有发生形态上的改变
- 关键帧动画:记录动作的始末和轨迹曲线,运行时根据曲线进行插值(很显然,这是一种矢量动画)
- 每个关键帧被称为姿势
顶点动画
骨骼动画的本质是顶点动画
- 刚体动画:在渲染中网格不发生改变,刚体的变化矩阵发生改变
- 顶点动画:在渲染中网格顶点发生了直接的变化(位移旋转缩放)
- 骨骼动画:一种对顶点动画的压缩算法
- 流体动画
- 粒子动画
- 变形动画:常用于制作表情,捏脸
根据顶点动画的实现方式,分为CPU和GPU
CPU动画 | GPU动画 | |
---|---|---|
顶点位置改变时机 | CPU应用阶段 | GPU几何阶段 |
数据流 | CPU传递给GPU的顶点数组发生改变 | 顶点着色器输出发生改变 |
骨骼动画
骨骼动画的模型整体不是刚体,同时为了避免旋转、移动时发生断裂,也不能将物体拆分为多个小刚体,因此只能选择顶点动画。
然而顶点动画带来的顶点移动,如果全部交由vertex着色器处理,过于昂贵,实时渲染不可接受
而且骨骼动画的顶点受更高层次的骨骼节点控制
- 同一根骨骼的顶点要保持相对位置不变
- 骨骼间顶点要进行平滑
- 顶点的大体形状受骨骼形状制约,顶点变化时要保持和骨骼的联系
实现
矩阵调色板蒙皮技术(Matrix Palette Skinning):
- 骨骼为近似刚体,其变化矩阵按顺序存储在数组中(我们称这个数组为骨骼)
- 顶点缓冲中会存储其骨骼ID和权重信息(一个顶点通常会受1~4个骨骼影响,可以用两个Vector存储)
- 进行变化时,顶点可以根据骨骼ID和权重查询变化矩阵,并通过插值的方式实现顶点动画(我们称查询矩阵为蒙皮)
- CPU通过姿势间插值,以获得每一帧骨骼的位置及矩阵,GPU根据顶点信息查询矩阵进而实现运动
坐标系
骨骼树
三维骨骼本质上是一系列Bone组成的树状结构
在骨骼动画中,我们更关心骨骼的相对位置,于是我们选择本地坐标系(A物体的本地坐标就是以A物体中心为原点,相对于中心的偏移),并让坐标系层次嵌套
比如大臂移动时也会带动小臂移动,我们就把小臂的本地坐标系定义在大臂的本地坐标系之下,我们称大臂是小臂的父物体,小臂是大臂的子物体。而小臂在大臂的本地坐标系的坐标被称为局部坐标系(可以参考Unity的GO组织)
顺着嵌套关系向根部搜索,就可以获得物体的世界坐标系
下图为树节点的数据结构
- 本地坐标系就是object space transform
在播放动画时,会从空间树的根节点(一般为盆骨节点或者root节点)开始向下递归变化,以保证父物体的local transform总是先于子物体刷新
//对关键帧进行插值 |
骨骼
- 盆骨:选盆骨作为根节点(或者是空根节点的第一也是唯一的子节点),是因为盆骨在运动时相对匀速,且位置居中,可以避免骨骼树过深
- 脊椎骨:模拟躯干运动,一般有2~3块
- 捻度骨骼:Twist Bone,生物学中像小臂这类骨骼不是一块骨骼,而是两条并排的骨骼,以此实现肘关节不动而手掌可以旋转
坐标变化
- 位移矩阵
- 缩放矩阵
- 旋转矩阵
- 齐次坐标
- 仿射变换:缩放–旋转–平移
- 列矩阵左乘
- 手性变换:只需要对所有的矩阵任选一维进行取反即可(哪个维度不重要,只要统一即可)
旋转
骨骼动画是矢量动画,是关键帧动画,因此会用到大量的插值,这决定了旋转的表达必须便于插值
三维空间中的点可以由三个正交向量插值表示,根据嵌套关系,一个物体发生旋转,其实就是其基向量相对于父节点基向量发生改变
双向量法
既然旋转可以由基向量的朝向表示,那么我们就直接基向量表示旋转吧!
正好三个基向量正交,而且对长度不敏感,那么我们还可以将三个向量压缩为两个向量
更进一步,这些向量都在球面上,那么用球坐标系替代直角坐标系
问题:
- 需要时刻保证两个向量垂直
- 不好插值
欧拉角
在航空业应用广泛,本质是一种过程量,描述了从初始位置沿着xyz轴旋转指定角度的过程,使用时需要明确旋转顺序(即顺规)
直角坐标系 | 欧拉角 | |
---|---|---|
前进方向 | Z | Roll 桶滚角 |
上方向 | Y | Yaw 偏航角 |
右方向 | X | Pitch 俯仰角 |
问题:
- 没有统一标准,而欧拉角强依赖于顺规
- 某些情况下会有两个轴平行,以至于失去一个自由度,导致万向节死锁
- 不能线性插值
轴角与四元数
轴角(x, y, z, w)指沿着轴(x, y, z)旋转w度,也可以压缩为三维向量(wx’, wy’, wz’),轴角可以通过对轴向量和旋转角度分别插值对方法进行插值
四元数是一种超复数,可以用来表示旋转
蒙皮解算
Mesh中的顶点缓存中会存储骨架、骨骼索引,骨骼权重,运行时在顶点函数进行位置的偏移,效果表现为Mesh跟着骨架一起运动,而且在边缘处会进行变形(效果与权重分配有关),就像皮肤蒙在骨骼上一样,这个过程被称为蒙皮结算
Motion Matching
游戏中不止使用一个动画,于是动画系统不仅需要播放动画,还需要管理动画。最常见的管理方式是数据驱动,实现形式为图状态机,通过一些bool、float、trigger数据控制动画状态
但随着角色3C不断复杂,动画系统也越发复杂,状态机里塞进了海量动画节点,他们的状态难以维护,为此育碧提出了Motion Matching
MM通过角色当前的姿势(Pose Channel)和行动轨迹(Trajectory Channel)在动画数据库中进行匹配,自动设置当前动画状态
-
Trajectory Channel通常是一个二维平面,通过人物移动速度,绘制一个移动轨迹,主要作用是跑步时转向会侧倾
-
Pose Channel是使用角色骨骼的几个节点,通常是两个脚的节点(当然你可以使用更多的节点,但随着节点数量的提升,匹配速度会更慢),主要作用是脚着地、手抓墙
骨骼动画播放
Unity Playable Script 动画播放
当我们在使用Unity Animator时,会发现我们必须要先将所需的动画片段放入Animation Controller中才能播放。如果我们想要一个Resources目录下的某个Clip,是做不到的
当游戏动画逻辑非常复杂时,状态机会非常复杂,几乎不可维护,于是很多公司会自己用Playable Script重写一份动画播放系统
Playable Script仍然是驱动Animator和Avatar的,所以角色身上仍需要Animator组件
直接播放一个动画片段
PlayableGraph playableGraph; |
等效于
var output = AnimationPlayableOutput.Create(playableGraph, "AnimationOutput", GetComponent<Animator>()); |
自行解算Humanoid
对于一个Humanoid骨骼的模型,我们可以直接遍历获得骨骼的Transform,对其进行修改
public Animator animator; |
Rig
一种基于反向动力学的组件,可以覆盖动画,原理是为一个骨骼点绑定其几个父节点,并刷上相关权重,当骨骼点因为外力移动时,父节点会跟着一起运动,从而使得整体动画协调
常用于武器运动时手跟着一起动、脚着地时腿跟着一起动、头看向临近的人
Blendshape动画
blendshape常用于实现表情动画、形变动画,相较于骨骼动画,十分昂贵
blendshape本质是在两个(或多个)顶点数量相同但位置不同的两个网格间插值出新网格
一个Mesh会有多个blendshape channel,每个channel都存了原始的mesh顶点buffer信息(主要是位置和法线),和目标mesh的顶点buffer信息,在解算时在两个mesh间线性插值。当有多个channel时,会按顺序依次插值
我们常用IClone和CC4制作bs模型
Unity播放bs
一个拥有bs channel的模型导入unity,会在SkinMeshRenderer上看到bs channel,直接修改这些channel就能实现动画播放
物理动画
大部分物理动画是通过解算一些物理观测点,再将这些点映射回(骨骼)动画中
Unity Magica Cloth
Magica Cloth是Unity一个布料模拟插件,有两个版本,我使用的是基于Jobs的普通版本(2是基于DOTS的)
1. 添加预制体
在场景中拖入MagicaPhysicsManager.prefab
位置在Assets/MagicaCloth/Res/Prefab
2. 绘制骨架
使用Animation Rigging绘制骨架,方便后续配置布料
Animation Rigging – Bone Renderer Setup
3. 添加Magcia Bone Cloth
Create Others – Magica Cloth – Magica Bone Cloth
- 将布料的根节点拖到Root List中,通常会有多个根节点
- 店家Start Point Selection开始调整节点
- 为节点刷颜色,红色只能旋转,绿色可以运动,根节点们都要为红色(你可以先点Fill将所以节点都设为绿色,然后切换到红色笔刷状态,按住鼠标左键在场景中将根节点都刷为红色)
- 完成后按End Point Selection保存
- 调整参数(也可以直接选择Preset)
- 点击最下方的Create,完成创建
4. 防穿模
在模型骨架下创建Magica Collider
Unity Ragdoll Animator
Ragdoll(布娃娃系统)是一种基于物理模拟角色动作的技术,通常是通过在角色关节和躯干上放置碰撞器和约束实现,可以参考动物派队、人类一败涂地的角色控制,该技术还常用于实现角色受击、尸体倒地等
我使用的是插件Ragdoll Animator 2,使用起来非常简单,而且可以做角色动画和物理的混合
人物模型初始化
- 导入一个模型,将其Rig设为Humanoid
- 将模型拖入场景,添加组件Ragdoll Animator 2
- 点击Try Auto-Find Requied Bones,人形模型可以自动初始化
参数调整
- 调整碰撞体的类型、大小(Construct–Colliders)
- 调整躯干重量、摆动范围(Construct–Physics)
- 调整肌肉力量、动画混合程度(Motion)
- 设置IK(在Extra–Utility–Kinematic Bone Selector)
动画压缩
用ALU和效果换存储和带宽,动画有很多关键帧和插值函数组成,Unity Editor下可以对动画Clip进行采样,生成更简化的关键帧,在运行时通过插值还原回动画信息