Animation Blend Tree
🕌

Animation Blend Tree

Blend Tree

notion image
💡
动画树最原始的这个 idea,至少老师个人的理解,是从表达式树开始的。
动画树其实是一个单向展开的树,并不是一个图,它最终一定要有一个流出的节点。就像表达式树一样,最终有一个根节点。

LERP Blend Node

notion image
最常用的就是线性插值节点。
动画树的线性插值节点中,最简单的是二元线性插值,输入的是个权重。比如说输入权重 0 就表示用 clips A,1 就表示全部选用 clip B,0.5 的话就两个 clip 各取一半。
如果是三通道或是四通道的线性插值系统,一般会单独输入权重,也就是 weight 1、weight 2、weight 3,让我们自己来控制。

Additive Blend Node

notion image
Additive Blending 在动画树里面也有专门的节点。

Express Layered ASM in Blend Tree

Use a blend tree to describe the desired final pose of ASMs
notion image
前面讲的 Layered ASM 就可以很轻松地用这样的结构的动画数据表达出来。
因此动画树可以认为是 Layered ASM 的一个超集,它可以表达所有的Layered ASM 能表达的东西。

Blend Tree Nodes

notion image
动画树真正的酷的地方就在于它是一个递归结构。38:17
虚幻引擎在动画树的节点设计得非常的灵活,节点既可以是一个动画的素材,也可以是一个 Blend Space,也可以是一个 ASM,最终只输出一个节点即可。
💡
虚幻引擎中,ASM 动画状态机节点点开了之后,它里面又可以内嵌很多的 node,这些 node 又可以再内嵌一棵小动画树。
这小节提到的都是叶节点,叶节点往上有很多中间的计算节点,最常见的就是前面讲的各种 LERP 节点、Additive Blend 节点或是 Mask 节点。

Unreal Animation Blueprint

A blueprint graph which outputs a final pose
  • Take clip poses or the results of ASMs as input
  • Blend input poses by different methods
notion image
虚幻引擎中的节点可以如上图连接。
 
💡
动画树为什么可以一直变换它的输出?树的数据是静态的,它为什么可以根据鼠标键盘、游戏的状态等输入,从而产生不同的 pose? 这里面有一个关键的东西就是动画树的控制变量

Blend Tree Control Parameters

notion image
动画树中,我们会定义大量的变量暴露给外面的 gameplay 系统。比如说当前的移动速度、朝向、健康状态、是否跳跃、是否受到攻击等。可以想象动画树是无数个流着水的管道,每个管道汇在一起,由阀门控制用哪个管道多一点,而这个阀门就是由控制变量来控制的。

Unreal Animation Blueprint Control

notion image
游戏引擎一般会定义变量叫 variable。variable 有两类:
  1. 环境的一些参数
    1. 比如我的速度,我的朝向,我的健康值。
    2. 比如说现在血量只有一半了,那角色动作会切换到很虚弱的动作,这种动画提前做好。如果血量很满,那这时候就可能是另外一组昂首挺胸走路的动作。两组动作在开关处混合,开关取决于血量是不是大于 50%。
  1. event
    1. 当一件事情(事件)发生的时候,会修改一些变量。这个修改一般是 event 发生的时候,把动画树里面的一些局部的标记给修改掉。
    2. 比如现在手上拿了一把步枪,突然接到一个指令,要把步枪换成一颗火箭筒。这个时候角色拿枪的上半身的动画就会从一个动作变成了另一个动作,变成扛住火箭筒。也就是说这个信号来了,就会修改动画树内部的一些状态。
💡
相当于类的 private 的(私有的)变量,但是它可以被外部的状态激活并且修改。
我们知道了动画会像流水一样被阀门控制如何混合,另外动画树中还有很大的一块代码是计算结构,去计算每个阀门开放的百分比。这些百分比通过变量控制,外部的控制信号在动画树中进行一些简单的加减乘除比较。
 
动画过渡 - Unity 手册
动画过渡允许 状态机 从一个动画状态切换或混合到另一动画状态。过渡不仅定义状态之间的混合应该耗费多长时间,而且还定义它们应该在什么条件下激活。您可以设置仅在特定条件成立时才发生过渡。要设置这些条件,请在 Animator Controller 中指定参数值。 例如,您的角色可能具有"巡逻"状态和"睡眠"状态。您可以将巡逻和睡眠之间的过渡设置为仅在"alertness"参数值低于某个水平时才会发生。 要为过渡命名,请在字段中输入名称,如下所示: 状态的 Inspector 窗口会显示该状态使用的过渡,如下所示: 在任何给定时间只能有一个激活的过渡。但是,当前激活的过渡可能会被另一个过渡中断(如果已将设置配置为允许此行为,请参阅以下的 过渡中断 )。 要查看某个过渡的属性,请单击 Animator 窗口中连接两个状态的过渡线。这些属性将显示在 Inspector 窗口中。 使用以下属性可调整过渡及其在当前状态和下一状态之间如何混合。 Has Exit Time Exit Time 是一种不依赖参数的特殊过渡。但是,它依赖状态的标准化时间。选中此选项可在 Exit Time 指定的具体时间进行过渡。 Exit Time 如果选中 Has Exit Time__,此值表示过渡可以生效的确切时间。该时间以标准化时间表示(例如,退出时间为 0.75 表示,在已播放 75% 动画的第一帧上,__Exit Time 条件为 true)。在下一帧上,该条件为 false。 对于循环动画,每个循环都会评估退出时间小于 1 的过渡,因此可使用此选项在每个循环的动画中以适当时机对过渡进行计时。 对 Exit Time 大于
动画过渡 - Unity 手册
相当于上面文档中最后的“条件”部分。
 
💡
现在做引擎如果觉得太复杂,可以定义一些接口的变量。可以让我们的 gameplay 系统可以去修改这些变量。在动画系统做好之后,让它在每个节点读取这些变量。然后允许它支持一些简单的比如加减乘除、比较大小或等于的运算,这样也可以实现一个有点意思的动画系统。