在这篇文章中,我们将从零开始学习 UE 的骨骼动画基本使用方法,通过一个 demo 工程,演示如何利用 UE 提供的骨骼动画能力来实现角色在不同速度和方向下的移动效果。

新建 Demo 工程

运行 UE,新建一个工程,这里简单使用了「Third Person」模板并命名为 UeAnim。新建完成后,导入模型和动画资源,这里使用了 UE 官方的「Animation Starter Pack」,它可以在 UE 的 marketplace 中找到:

导入后,目录结构如下:

接下来删除 viewport 中的原始角色,并修改 Source/UeAnim/UeAnimGameMode.cpp 中的 DefaultPawnClass 对应的蓝图,我们之后不会用到原始的资源:

AUeAnimGameMode::AUeAnimGameMode() {
    static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/AnimStarterPack/Ue4ASP_Character"));
    if (PlayerPawnBPClass.Class != NULL) {
        DefaultPawnClass = PlayerPawnBPClass.Class;
    }
}

编译代码,并将「World Settings」中的「GameMode Override」修改为对应的 game mode,这里是 UeAnimGameMode

此时点击「Play」按钮,可以看到场景中出现了「Animation Starter Pack」里的模型:

资源类型说明

打开 Content/AnimStarterPack/UE4_Mannequin/Mesh 目录,可以看到三个资源:

紫红色资源 Skeletal Mesh1 SK_Mannequin

Skeletal Mesh 资源是骨骼动画要控制的目标。网格体 mesh 分为静态网格体 static mesh 和骨骼网格体 skeletal mesh 两种,两者的区别在于 skeletal mesh 可以被动画化,因为它具有和骨骼的绑定关系,通过移动骨骼可以实现对它的变形。这里需要提到一个「蒙皮」概念,蒙皮是指把 mesh 的顶点绑定到骨骼上,并且每个顶点可以被多个骨骼按一定权重进行控制。需要注意的是蒙皮是一个容易让人误解的词,这里的「皮」不是指贴图,而是 mesh 本身。

也就是说,我们看到 skeletal mesh 的动画并不是动画师直接操作 mesh 顶点实现的,而是通过操作骨骼实现的。而骨骼的定义则是通过下面要说的 Skeleton 资源实现。

青色资源 Skeleton2 SK_Mannequin_Skeleton

Skeleton 资源是整个动画系统的基础,它是一组相互连接结构化排布的骨骼,我们可以通过改变骨骼的朝向和位置来生成动画。「骨骼」也是一个容易被误解的词,因为动画师控制的其实不是「骨骼」而是「关节」,「骨骼」是「关节」之间的空位,因此事实上一般提到「骨骼」都是指「关节」。

橘黄色资源 Physis Asset3 SK_Mannequin_PhysicsAsset

Physis Asset 用于定义该模型使用的物理和碰撞信息。

在上两层目录,即 Content/AnimStarterPack 中有许多资源文件,这些都是动画相关的文件,其中:

绿色资源 Animation Sequence4Aim_Space_Hip

Animation Sequence 是可在骨架网格体上播放的单个动画资源,记录骨骼随时间的运动状态信息,也就是定义了动画。需要注意的是,每个 animation sequence 资源专门针对特定的 skeleton,且只能在这个 skeleton 上播放,为了能在多个 skeletal mesh 上共享动画,它们必须要使用同一个 skeleton 资源。

蓝色资源 Blueprint Class5 Ue4ASP_Character

Blueprint 是 UE 中的可视化脚本,可以通过拖拽节点的方式构建游戏逻辑。

褐色资源 Animation Blueprint6 UE4ASP_HeroTPP_AnimBlueprint

Animation Blueprint 资源和一般的蓝图类似,也是可视化脚本,可用于创建和控制动画行为。前面的 animation sequence 资源仅定义了动画本身,并不记录何时播放以及如何播放的信息,我们需要通过 animation blueprint 对动画播放进行控制。

橙色资源 Blend Space6BS_CrouchWalk

Blend Space 资源可以根据多个输入的值混合 animation sequence,创建出多个动画间的过渡效果。

动画混合

一般来说,UE 本身不用于制作动画,我们仅会去导入并使用动画资源,例如控制一个角色何时播放哪些动画,动画之间如何切换等,或在其上进行微调。模型和动画资源是由美术使用类似 Maya 之类的工具制作的。我们拿到这些动画资源并导入后,可以双击 animation sequence 资源打开 animation editor 查看单个动画的预览效果:

在使用这些动画之前,我们需要先实现在多个动画之间的平滑切换。例如,我们想实现一个角色从静止逐步加速,先变为走路,再加速到跑步的效果,我们不会对这个过程中每一个速度值都设计一个动画,而会设计静止、走路、跑步三个动画,分别对应于角色移动速度为 0、1.5m/s、3m/s 时的状态,这之间的其他速度值就用这几个动画混合生成。我们可以用前面提到的 blend space 来定义这个生成逻辑。Blend space 有两种,一种是普通的 blend space,另一种是 blend space 1D,其中 blend space 的混合参数值有两个,blend space 1D 的混合。这里以 blend space 为例说明,在 Content Browser 中新建一个 blend space 资源:

前面提到,每个骨骼动画都是专门针对特定的 skeleton 实现的,因此 blend space 显然也需要针对特定 skeleton 实现。UE 会在创建 blend space 的时候要求我们指明对应的 skelton 资源,这里选择 AnimStarterPack 目录下的 skeleton:

双击这个这个资源后,我们可以在 Animation Editor 中编辑 blend space:

在 blend space 中,我们可以根据两个参数的值来确定动画的混合逻辑,在 editor 的下方可以看到一个二维的坐标系,两个参数分别对应两个坐标轴,拖动绿点可以在上方查看混合的效果:

这里坐标轴的对应的名字和其变化范围可以在左侧的「Asset Details」中设置,这里将 x 轴设为方向,取值为 -90~90,y 轴设为移动速度,取值为 0~300:

然后,将左侧的 Asset Browser 面板中的动画资源拖动到坐标系中对应的位置,例如当旋转 0 度,速度为 0 的时候是 idle 动画,那么就将 idle 动画拖到 direction 为 0 且 speed 为 0 的位置上:

类似地,我们可以将向左走路动画放在 direction 为 -90 speed 为 150 的位置,向右跑步的动画放在 direction 为 90 speed 为 300 的位置……将这些动画放好后,我们可以拖动绿点进行预览:

动画控制

为了使用动画,我们需要动画播放的控制器,前面提到,UE 通过 animation blueprint 控制动画行为。在 Content Browser 中新建一个 animation blueprint 资源,命名为 BP_Anim ,这里同样要指定使用 AnimStarterPack 目录下的 skeleton:

双击打开新建的 blueprint 进入 Animation Blueprint Editor,可以看到中间有两个 tab,一个是 Event Graph 一个是 AnimGraph:

默认情况下,AnimGraph 中只有一个「Output Pose」节点,我们可以将任意动画从右侧的 Asset Browser 面板中拖入 AnimGraph 里,然后将动画的输出连到 Output Pose 节点的输入上:

此时点击「Compile」按钮,会发现动画节点和 Output Pose 节点之间的连线亮起,在预览面板中可以看到动画播放的效果:

但这样的连接并不能实现状态的转换,例如在点击蹲下后将角色动画切到蹲下的动画。在 animation blueprint 中,我们通过状态机来实现这样的转换功能。删除刚刚添加的动画节点,然后右键添加一个 State Machine 节点,并将其输出连接到 Output Pose 的输入上:

双击新增的 State Machine 节点,进入该节点的编辑界面,如果需要返回刚刚的 AnimGraph 界面,可以点击顶部的「AnimGraph」。默认情况下,这里只有一个「Entry」节点,我们拖动这个节点的输出,可以新增节点,这里新增一个 State 节点:

将这个 state 节点命名为 Normal,这个节点用于表示通常状态下的动画。双击这个节点,进入这个 Normal 节点的编辑界面,我们可以看到和之前 Output Pose 类似的一个动画输出节点 Output Animation Pose。此时我们可以从左侧的 Asset Browser 面板中拖出之前的 blend space 资源,并将其输出连接到 Output Animation Pose 的输入上:

问题是我们的 blend space 需要当前的方向和速度作为输入,这个数据又要从哪来呢?我们可以点击上方的 Event Graph tab,切换到事件编辑界面:

在右下方的 My Blueprint 面板中找到「Variable」session,添加两个 float 类型的变量,命名为 SpeedDirection 用于表示速度和方向:

接下来,我们需要设置这两个变量,首先,新建一个 Get Player Character 节点,并将其类型转换到我们使用的 character 类型上,这里是 Ue4ASP_Character 。从这个节点出发,获取其 Velocity 并计算其长度,这个就是角色当前的速度值,将这个值设给 Speed 变量。然后,通过 Calculate Direction 节点获取当前方向,并赋值给 Direction 变量,大致如下图所示:

此时我们可以回到 Normal 节点的编辑界面,将 SpeedDirection 两个变量赋值给 blend space 的对应位置。编译后,我们可以在左侧「Anim Preview」面板中输入不同的速度和方向值,就可以在左侧的预览面板中看到具体效果:

目前我们的状态机只有一个状态,我们可以添加更多状态并定义状态之间的转换规则。回到之前的 state machine 编辑界面,从 Normal 节点出发再拖一个节点出来,命名为 Crouch,这个节点用于表示下蹲状态下的动画。此时我们发现 Normal 和 Crouch 之间有一个绘制了双向箭头的圆圈,这个是用于表示两个状态之间的转换规则。由于我们之前是从 Normal 节点出发添加的 Crouch 节点,因此 UE 自动建立了 Normal 到 Crouch 的转换,为了将状态转回去,这里从 Crouch 节点出发,将箭头指向 Normal 节点:

为了标记角色是否是蹲下状态,我们添加一个 bool 变量,命名为 Crouched 并从 character blueprint 中获取 IsCrouched 的值,并赋值给它:

如果我们需要用该蓝图没有提供的状态,那么就需要去该 character 蓝图中自行添加,然后再在此处获取。

回到 state machine 编辑界面,双击从 Normal 到 Crouch 的转换规则圆圈,进入转换规则编辑界面,将 Crouched 变量的值赋给 Result 节点:

类似地,在 Crouch 到 Normal 的转换规则中,将 not Crouched 的值赋给 Result 节点:

而在 Crouch 状态中,我们也给 Output Animation Pose 输入一个动画,这里就不重复 blend space 的制作了,简单将一个 idle 的蹲下动画作为输入:

此时可以修改 Anim Preview 面板中的数值来预览动画状态改变的效果了:

应用动画

在制作好前面的动画后,我们可以打开 Ue4ASP_Character 蓝图,在 Viewport 面板中选中我们的角色模型,然后在右侧的 Details 面板中找到 Animation 一节,将其中的「Animation Mode」改为「Use Animation Blueprint」,再将「Anim Class」改为刚刚制作的动画 BP_Anim

另外,为了实现蹲下的能力,我们还需要做几处修改。首先在 Ue4ASP_Character 蓝图中间的 Event Graph 中找到 Crouching 组,在这里修改蓝图逻辑来触发角色的蹲下状态。简单起见,这里不作复杂判断,直接在 Crouch Button Down 为 true 的时候触发蹲下, false 的时候解除蹲下:

然后,我们在左侧的 Components 面板中选中 Character Movement 一项,在右侧的 Details 面板中找到 Nav Movement 一节,勾选其中的「Can Crouch」,确保可以蹲下:

修改好后保存更改并编译。最后,在菜单栏的 Edit 菜单下点击「Project Settings…」,然后在 Input 菜单中的 Action Mappings 列表里加一项「Crouch」,并绑定一个按键,这里绑定的是左 Ctrl 键:

回到主界面,点击「Play」运行游戏,就可以用 WASD 键控制方向,用左 Ctrl 蹲下,查看动画效果了: