Animation Clip
Unity 的动画是基于所谓 Animation Clips 的概念,它记录了一些对象上的数据(比如坐标、旋转、透明度等等)的关键帧,然后插值获取每一帧的数据。Animation clips 可以通过导入第三方软件的导出动画获得,也可以在Unity中直接创建。第三方导入的 Animation Clip 是只读的,如果需要修改,则需要拷贝出另外的副本。
Animator Controllers
恰当的时机播放特殊的动画,比如角色站立时播放站立的动画,跑动时播放跑步动画,建筑静止时播放静止动画,升级时播放升级动画,并且还需要定义这些动画的切换过程,完成这些工作的就是 Animator Controller。具体而言,它是通过状态机的方式来实现上述需求。
它会将各个状态关联到 Animation Clip 上,可以使用代码直接切换状态,也可以通过修改各种预先设置好的参数(Parameters)来达到同样的目的。和 Animation Clip 一样,Animator Controller 也可以以 Asset 的形式被创建、编辑、保存。编辑获得想要的 Animator Controller 后,将其添加到 Animator 组件上即可在游戏中使用。
Animation 状态机
State
上文提到状态机中的每个状态都对应一个 Animation Clip,但是除了这些真正的动画状态之外,还有如下特殊状态
- Enter,状态机的入口
- Exit,状态机的出口
- Any,代表任意状态
Transition
状态与状态之间存在转换的过程,Transition 即是用来描述这个过程,我们可以在这里定义状态之间的切换,比如切换的持续时间,从旧状态的哪一帧结束,新状态的哪一帧开始,从而实现各种业务需求以及表现的平滑过渡。此外可以启用 Mute 和 Solo来限制状态之间的切换,因为即使没有 Transition ,也可以强行从一个状态硬切换到另一个状态。
Animation Parameter
上面说到可以通过修改 Parameter 来达到切换状态的目的,Parameter 的值可以是整数、浮点数、布尔值或者Trigger(使用完后会被自动重置的布尔值),可以通过 Animator 提供的接口来修改它们。可以作为 Transition 的条件从而影响状态的切换。
State Machine Behaviours
可以为状态添加 State Machine Behaviours ,他提供了一些接口让我们可以在一些时机执行相应的逻辑,比如在状态退出的时候调用播放音频的接口。
Sub-State Machines
可以将多个状态组合一个 Sub-State Machines ,可以减轻 Animator 的维护成本。
Animation Layers
Unity 使用 Animation Layers 管理用于不同部分的状态机。不如下半身层管理走路、跳跃,上半身层负责投掷、射击。
可以通过调整层权重(Layers Widget)来管理动画中的层。点击 layer 右侧的齿轮。可以打开层的设置。
可以设置 Avatar mask(确定动画将会应用到模型的哪部分),Blending(和其他层的混合模式),Override 代表忽略其他层,Additive 代表会叠加到前面的层之上。此外,还可以通过 sync layer 实现状态机的复用, 一个 layer 可以通过与其他的 layer 同步从而共享被同步的 layer 的状态机。
Animator Override Controller
类似 Animator Controller,可以用来复用 Animator Controller 的状态机。它可以覆盖替换 Animator Controller 中的状态对应的 Animation Clip。
Avatar
我们可以在导入模型的时候,将骨骼关联到 Avatar 上,这个 Avatar 可以是导入模型时创建,也可以引用之前导入的,这个关联过程如果满足匹配的话就可以自动关联,否则就需要手动关联,Unity 允许部分骨骼关联。拥有 Avatar 可以使用 Unity 提供的目标匹配(Target Matching)、IK (Inverse Kinematics),重定向(Retargeting)等特性。
Blend Tree
混合不同的 motion 再游戏动画里是很常见的需求,比如根据角色速度混合走路和跑步动画,还有跑动时要混合跑步与转向动画。这时候就可以使用 Blend Tree 了。
状态机和 Blend Tree 都能实现不同动画间的平滑过渡,但是前者是基于两个状态的 transition,后者则可以是大于等于两个动画的混合。Blend Tree 本身也可以是状态机里的一个 state。当然这些动画的差距不能太大,毕竟线性插值也是有极限的。
Blend Tree 将会根据绑定的 Parameters 还有 Blend Type 来确定当前播放的动画。
1D Blending
1D Blending 通过单个参数来确定动画,它仅仅是简单在各个子树之间根据权重插值,看图就明白了。
蓝色锥形的高度代表权重,可以看出随参数的变换,各个动画的权重变化。这个权重的分配可以手动编辑,也可以靠 unity 自动完成。自动完成可以是均匀分配,也可以是根据动画的速度等参数加权分配。
2D Blending
2D Blending 通过两个参数来确定动画,本质多是通过两个值构成的向量获得在二维平面上各个位置的权重,不过各个类型之间还是有所区别的。
- 2D Simple Directional,适用于动画代表不同方向的情况,比如向前后左右走,单个方向只允许有一个动画。
- 2D Freeform Directional,也适用于动画代表不同方向的情况,但允许同向存在多个动画。
- 2D Freeform Cartesian,适用于动画不代表不同方向的情况,参数可以用来描述方向之外的概念,比如角速度或者线性速度。
和 1D Blending 一样,各个动画的位置也可以通过设置自动计算出来。
Direct Blending
除了上述的通过参数计算出各个动画权重的方式,还有直接用参数作为权重的方式。
这样可以直接而非间接地控制动画的混合,可以看见每个动画都被直接分配到一个参数上,因为直接所以事实上是最灵活的类型,可以用其实现淡入淡出、甚至自己的 2d 混合算法,还可以结合 blend shape 做出复杂的表情动画。
blend shapes
Blend Shape 也是依赖 SkinnedMeshRenderer 组件,打开该组件即可看到各个shape 的权重。
基本原理是各个预设好的 shape 的顶点按照权重去混合,成本不低(相比起骨骼动画而言),一般只用于脸部表情等精细部位。
总结
大体上过了一下 Unity 动画基于 state machine 还有基于 Blend Tree 的两种机制,其实两者并非互斥的,Blend Tree 本身也是 state machine 中的一个 state,它只是提供了另一种动画控制与平滑过渡的机制。
参考
https://docs.unity3d.com/Manual/AnimationSection.htmldocs.unity3d.com