在前一篇文章中,我们已经了解了骨骼动画相关资源的功能,学习了如何将美术提供的动画资源放在蓝图中进行控制,也了解了如何在动画间进行平滑切换,并最终将动画应用到了角色身上,实现了角色在不同速度和方向下的移动效果。在这篇文章中我们将基于前一篇文章的 demo 继续学习 UE 骨骼动画其他功能的使用。

监听动画播放进度

有时我们希望基于动画播放状态来实现特定逻辑。比如在播放跑步动画时,我们可能会需要在角色脚接触到地面的时候播放脚踏地面的音效,这就需要我们在动画播放的过程中监视动画播放的状态。UE 通过 animation notify1 来实现这一点。打开 Jog_Fwd_Rifle 动画,这是我们之前在学习 blend space 时用到的动画。打开后,可以看到预览界面的下方有一组轨道,在这里的左侧可以看到一个「Notifies」组,这里就是 animation notify 的轨道,默认情况下应该有一个名为「1」的轨道供我们直接使用。如果监听事件比较多,我们也可以根据需要添加更多轨道:

在这里我们直接就使用默认轨道了。暂停动画并拖动进度条,在角色右脚碰到地面的位置右键点击轨道 1,此时会弹出「Notify」菜单,在「Add Notify…」子菜单下我们可以看到许多预设的 notify 类型,其中就有播放声音,但这里为了方便 gif 图演示,就不使用默认的内容了,直接添加一个名为 RightFoot 的 notify:

继续拖动进度条,在左脚碰到地面的位置添加 LeftFoot 的 notify。Animation notify 也是和 skeleton 绑定的,在添加同名 notify 时,我们不点「New Notify…」而是从「Skeleton Notifies」中找到已经存在的名字。添加完后轨道如下:

类似地,我们给之前用到的所有动画文件如 Walk_Fwd_Rifle_Ironsights 也都用类似的方法添加脚踏到地板的 notify。由于 animation notify 和 skeleton 绑定,因此在新增 notify 时,会发现不仅动画本身出现了修改,skeleton 文件也会显示出现了修改,我们都保存一下。如果想看到一个 skeleton 下有哪些 notify,可以切到 skeleton,然后打开 Animation Notifies 面板查看:

接下来,打开我们之前使用的 BP_Anim 蓝图,切到 Event Graph 面板,此时我们可以在这里可以添加刚刚新建的 nofity 事件作为触发源。这里简单处理,当监听到 LeftFoot 时打印 Left ,监听到 RightFoot 时打印 Right

保存蓝图,此时运行游戏,移动角色,此时就可以看到左脚和右脚接触地面时打印出 LeftRight 字符串了:

除了监听动画播放的特定时间点之外,我们可能还会需要在动画播放的过程中持续修改某一个值,实现一些业务逻辑和动画的同步处理。例如在我们的角色受到攻击时,出现身体变红的效果,那么一个合理的想法是让这个颜色在受击动画幅度最大时最红,然后逐渐恢复。此时我们可以通过让一个材质参数和受击动画同步变动来实现这一效果。为了做到这一点,我们先打开 AnimStarterPack/UE4_Mannequin/Materials 目录下的 M_UE4Man_Body 材质资源,添加一个名为 RedWeight 的材质参数。然后将原先的 BodyColor 和红色按 RedWeight 为比例进行混合,当 RedWeight 为 0 时完全用原先的颜色,当 RedWeight 为 1 时完全用红色,大致如下图所示:

那么现在的问题是我们如何将动画播放的状态和这个 RedWeight 进行同步呢?首先,我们打开 Hit_React_1 动画资源。这个动画直接播放的效果如下:

注意到刚刚我们添加 notify 的轨道上不止有「Notifies」轨道,还有「Curves」2 轨道,这就是我们要使用的工具。先新建一个轨道,确保名字和刚刚使用的材质参数 RedWeight 完全一样:

双击新建的 curve 可以打开 Curve Editor,右键点击 RedWeight 对应的 curve(这里是紫色的),在菜单中选择「Add Key」添加一个关键点,这个值是 RedWeight 的初始值。因为我们不想让颜色在受击前变化,因此这里值是 0:

然后,我们拖动进度条,找到受击动画达到最大幅度的位置,添加一个关键点,让 RedWeight 的值为 1,此时颜色最红。最后,在动画结束的位置添加一个关键点,让值为 0,恢复到原始颜色:

如果此时保存修改并播放动画,我们会发现并没有任何颜色变化。这是因为 UE 要求我们手动指定这个 curve 是对应于一个材质参数。打开对应的 skeleton ,在 Anim Curves 面板中找到我们添加的 RedWeight 参数,勾选上「Material」选框:

修改完毕后,保存文件,再播放动画,我们就能看到想要的效果了:

分区混合动画

我们在上一篇文章中已经学习过一种动画混合方法,即 blend space,而除了 blend space 这种多个动画平滑切换的应用场景外,我们还有另一种常见的动画复用场景,即部分骨骼播放 A 动画,部分骨骼播放 B 动画。

例如,我们有静止、走路、跑步的动画和一个静止重装弹的动画,那么我们自然希望能直接实现走路、跑步时重装弹的动画,而不用多制作两个重复的动画。此时,我们希望角色下半身按照之前走路、跑步的逻辑切换动画,而上半身则播放重装弹的动画。UE 提供了 blend node3 来实现这个能力。

打开之前使用的 BP_Anim 蓝图,基于 Normal 节点拖出一个新节点,命名为 Reload。然后新增一个变量 Reloading 用于作为状态切换的指示,这个过程和之前切换蹲下是类似的。双击进入 Reload 节点进行编辑,首先,在这里增加一个 Layered blend per bone 节点,这个节点允许我们以某个骨骼为界来按一定比例混合多个动画。这里我们将输入的 Base Pose 设为我们之前在通常状态下使用的动画,而 Blean Poses 0 则使用装弹动画 Reload_Rifle_Hip 。这个混合节点还允许我们混合更多动画,并分别设置混合的权重,不过由于我们希望在装弹时上半身完全使用装弹动画,因此我们也无需增加混合内容,而权重我们也只需要保持为 1 即可:

接下来,我们打开对应的 skeletal,寻找我们需要的骨骼。我们可以打开骨骼名称的显示来方便我们查找,这里可以看出,骨骼 spine_01 下的所有骨骼就是上半身的骨骼,因此我们选定该骨骼作为混合节点的根:

确定骨骼后,回到 BP_Anim 的编辑界面,选中 Layered blend per bone 节点,在右侧的 Details 面板中找到「Layer Setup」组,新增一个「Branch Filters」,并将「Bone Name」设为 spine_01

这里还有一个「Blend Depth」参数,我们暂时忽略,填入 0。保存蓝图并编译,我们就可以在预览窗格中看到混合后的效果了:

至于这个 Blend Depth 参数,则是用于控制混合的范围的,取值有点不直观,规则为:

  • 0 or 1 :自己和所有子骨骼完全参与混合
  • N > 1 :逐层子骨骼递增混合比例,直到第 N 层混合到 100%,后续都是 100%
  • -1 :只有自己参与混合,所有子骨骼不混合

假设我们想让角色左下臂不要混入装弹动画,那么我们可以在 skeleton 中找到左下臂对应骨骼,这里看到是 lowerarm_l

然后,我们就可以在这里添加一个 Bone Name 为 lowerarm_l 的 Branch Filter,并将 Blend Depth 设为 -1。此时保存并编译,然后播放动画,我们就能看到一个有趣的效果,整个上半身包括左上臂都混入了装弹动画,但左下臂仍然和静止时一样是一个僵硬的状态,这是因为左下臂的所有子骨骼都保持了之前的动画,没有受到装弹动画的影响:

联动其他模型

目前我们的角色只有自己在动,但在游戏中经常有角色拿着武器、背着东西的情况,此时,这些和角色关联的对象也应该跟随角色的动画一起运动,以表现出它们被角色持有的效果。如果仅将其作为一个子节点挂在角色上,那么这个模型仅能跟随角色改变整体位置而不会受动画影响。UE 为这种情况提供的解决方案是使用 socket4。可以认为 socket 是相对于 skeletal mesh 中某一骨骼的偏移量。在 skeleton 上设置好 socket 之后,就可以基于 socket 实现模型联动了。虽然骨骼本身也可以作为其他模型的参考点,但 socket 自身可以相对骨骼进行位置、方向、缩放进行调整的能力,使得用起来更加灵活。

这里我们尝试实现一个角色背着剑的效果,为方便演示,再导入一个免费的资源,同样也是官方提供的「Infinity Blade: Weapons」:

打开角色的 skeleton 资源,找一个适合作为参考点的骨骼,这里选择了 spine_03 。右键点击 spine_03 ,在菜单中选择「Add Socket」来添加一个 socket,命名为 Spine03Socket

这个 socket 的位置会以 spine_03 骨骼为参考,默认情况下和骨骼位置一样,因此会嵌入到角色身体里。我们选中这个 socket,将它移动到比较靠背后的位置:

不过这样我们还是不太好看清楚实际使用时候的效果,我们可以右键点击 Spine03Socket ,在菜单中选择「Add Preview Asset」来添加一个预览模型,这个模型只会在这里被预览,不会影响实际运行的效果。我们简单加入一把刚刚导入的剑模型,这样我们就可以比较直观地调整 socket 的位置、缩放等属性了:

调整好后保存 skeleton 资源,然后随便打开一个动画,即可直接预览动画播放时的效果:

我们可以根据预览效果逐步调节参数优化效果,在效果满意后自然就是去应用这个 socket 了。打开角色蓝图,点击左上角的「Add Component」按钮添加一个 skeletal mesh,将它挂在 Character Mesh 下。然后,在左侧的 Details 面板中设置 Parent Socket 为 Spine03Socket 并将其 mesh 设置为刚刚我们添加的剑模型:

保存并编译蓝图,回到主界面运行游戏,此时就可以看到角色背着一把剑跟随它运动了: