【UE5】动画系统
最近接触的项目涉及到动捕和动画,以前接触的范围主要是GamePlay以及C++和蓝图的交互,很少接触动画,借此机会学习一下UE5的动画系统。
首先把整个动画系统的框架了解一下。
参考博客:奶帆、骨架资源、骨架树、papalqi、郭袁、Stefan Perales
一、动画系统的框架
我们自上而下,从左往右看:
1.AimOffset
AimOffset在UE4中的直译是目标偏移,用于对主体动画的混合叠加,多用于射击瞄准,如在吃鸡游戏中人物持枪瞄准时根据视角不同可以向上瞄准和对地瞄准和左右侧身瞄准。Epic不愧是做射击游戏起家的,AimOffset在UE中使用的图标都是一个人持枪的样子。
2.AnimationMotage
AnimationMotage直译为动画蒙太奇,Motage在影视剪辑中是一种剪辑手法,通过将一系列视点不同的镜头组合起来的一种手法,感觉UE也是沿用这种解释,将不同而又有关联的多个动画组合起来构成一个完整的动画,这个完整的动画就是AnimationMotage。如一个攻击技能动画可以由拔刀动画+向上跳起动画+向目标砸下动画+收刀动画组成。这几个动画就可以由一个AnimationMotage组合在一起。AnimationMotage可以便于AnimationBlueprint更好的控制动画。
3.PhysicsAsset
PhysicsAsset—物理资产,官方给的定义是
物理资产用于定义骨架网格体使用的物理和碰撞。它们包含一组刚体和约束,这些构成一个布偶,而布偶并不 局限于人形布偶。它们可以用于任何使用形体和约束的物理模拟。因为一个骨架网格体只允许一个物理资产, 所以可以为许多骨架网格体打开或关闭它们。
我们在打开动画相关的资产的时候一般都能看到物理资产。
4.BlendSpace
BlendSpace—混合空间,BlendSpace是用于根据输入的float值在两个动画进行融合采样然后输出融合后的动画的工具,如两个动画一个是向前走一个是向左走,两个动画就可以通过输入的float值在混合空间进行混合,然后输出从前到左这个扇形方向任何一个方向运行的动画。
5.AnimationCompostie
AnimationCompostie—动画合成,按照官方的解释就是
动画合成作为一种将多个动画组合在一起将它们作为单个单元进行处理的方法。在某些情况下,你可能会遇到这样的情况:你需要将多个动画序列拼接在一起,这样就可以将它们当作一个序列而不是多个序列来使用。这正是 动画合成 的目的。动画合成是一种动画资产,专门设计用于允许你将多个动画组合在一起以作为单个单元进行处理。但是,请注意合成只是追加动画;它不提供任何混合能力。
6.SkeletalMesh
SkeletalMesh—骨骼模型,绑定了骨骼之后的网格体,也是角色实际应用mesh。
7.AnimationSequence
AnimationSequence—动画序列,帧动画的一种,官方给的定义是
动画序列(AnimationSequence) 是一个可以在骨架网格体上播放的独立的动画资源。它们包含了一些关键帧,这些关键帧可以及时地指出某个特定点处的一个骨骼的位置、旋转度及缩放比例。通过回放序列中的这些关键帧,并在将它们互相混合,使得骨架网格体可以产生平滑的动画效果。
每个 动画序列 资源指向一个特定的骨架,且仅可以在那个骨架上进行播放。这意味着,为了在多个骨架网格物体间共享动画,所有网格物体都必须使用同样的骨架资源。
8.Skeleton
Skeleton—骨骼,骨骼是整个动画的系统的基础,任何动画都要在骨骼的基础上进行创作,只要人物应用的骨骼保持一致,同一个动画就可以在不同的人物上应用。
官方定义是
如果您熟悉数字内容创建,那么对"骨架"的概念应该有所了解。 在多数3D应用程序中,骨架通常是一个数字层级架构,用于定义角色中的骨骼或关节,并以诸多方式模仿真实的生物骨架。 在虚幻引擎4中,一个重要的区别是骨架资源将 关联动画数据,而并非只是骨架网格体中的骨骼层级。 在UE4中,骨架资源将把骨骼(关节)数据关联到动画轨迹,从而驱动动画。
9.AnimationBlueprint
AnimationBlueprint—动画蓝图,动画蓝图是UE专门用来控制动画的专用蓝图,用于将各种动画的混合,叠加,控制,更新以及状态等进行程序化控制,然后输出最终的动画到角色身上。
10.各个资产之间的关系
我们以一个发球动作为例。
可以把整个骨骼(Skeleton)是整个动画系统的基础,存储着一些最基础的数据,决定了一个角色可以做什么样的动作;
骨骼模型(SkeletalMesh)是依附于骨骼之上的血肉,决定角色动画的外型形象;物理资产(PhysicsAsset)是依附于骨骼之上的物理碰撞体,是动画之间物理碰撞;
动画序列(AnimationSequence)是一段一段的动作片段,如起步做东,冲刺动作,抬脚动作、踢出动作;
混合空间(BlendSpace)和目标偏移(AimOffset)都是为动作片段优化动作的,混合空间为各个动画片段添加变化,如踢出动作可以混合出偏内侧踢和偏外侧踢,目标偏移为指定动画增加优化动作,如起步动作的屈膝优化;
动画融合(AnimationCompostie)是对整体动作的优化,可以将一个一个的动画片段进行截取组合,组合成一个完整的新动作,如一个个动作片段可能会有一些多余的小动作,动画融合就可以把这些小动作清理掉并把截取出来的动作并接成一个简洁的动作,可以将整个发球动作融合成助跑和射球两个动画融合,也可以直接融合成一整个完整的发球动作;
动画蒙太奇(AniamtionMotage)则是对整个动画的整合控制,可以直接整合一个个的动画片段,也可以整合组合过的动画融合,让后对整个动画提供参数控制,相当于给骨骼肌肉发送动作指令的神经系统;
动画蓝图(AnimationBlueprint)为整个动画系统提供程序逻辑控制的能力,是整个动作控制的大脑,控制着动作的一举一动,当然在一个做动作的过程中动画蓝图不是必须,就如我们做一些动作是可以直接通过肌肉记忆做出动作而无需过大脑。
二、骨骼
骨骼存储着一些最基础的信息,如:
- 骨骼层级信息;
- 参考姿势信息;
- 骨骼的名称;
- 插槽信息;
- 曲线信息;
- 动画通知信息;
- 插槽数据;
- 虚拟骨骼信息;
- 骨骼映射表;
- 重定位信息;
- 各个骨骼之间的约束信息。
1.骨骼的创建
骨骼的创建一般都发生在导入模型资产到UE的过程中由UE根据导入的骨骼模型和骨骼设置自动创建,同时UE也提供根据已有的骨骼模型来创建一个新的骨骼资产,UE在创建出新的骨骼资产后会把动画资源重新关联到新的骨骼资产上。
2.骨骼树
我们打开骨骼资产编辑器,在左侧就能看到一列密密麻麻的树型骨骼结构,这里我做一些简单的了解。
我们可以在骨骼资产编辑器中渲染视图的Character/Bones下勾选Bone Names和All Hierachy将所有骨骼和骨骼名称显示出出来。
-
root:整个树结构的根是root节点,按照规范root节点所在的位置就是人物在地面的中心;
-
pelvis:直译为盆骨,是整个躯干骨骼的根节点,动画通过这个节点来控制整个身体的运动,pelvis直接从root节点连接到盆骨位置处;
-
ik_foot_root和ik_hand_root:这两个节点就是上图中从root节点延申到脚和手的骨骼,是用于脚部和手部的IK动画的节点,这里暂时先不讨论;
-
spine_01-spine_03:是三节脊椎骨,从下往上依次嵌套,覆盖腹部、腰部和胸部,动画通过这三个节点来控制上半身的动作;
-
clavicle_l和clavicle_r:左右锁骨,是手部骨骼的根节点,控制着整个手臂的动作;
-
upperarm_l和upperarm_r:左右肩膀的骨骼;
-
lowerarm_l和lowerarm_r:左右臂的骨骼;
-
hand_l和hand_r:手腕的骨骼,手腕再往下就是手指骨骼了;
-
neck_01:颈部骨骼,动画通过这个节点来控制头部的动作;
-
head:头部骨骼,用于继续往上延申出控制眼睛动作的骨骼,控制嘴巴动作的骨骼和头发动作的骨骼;如:
-
thigh_l和thigh_r:盆骨外下的跨部的骨骼,是整个腿部骨骼的根节点,控制整个腿部的动作。
-
calf_l和calf_r:大腿骨骼;
-
foot_l和foot_r:小腿骨骼;
-
ball_l和ball_r:脚掌的骨骼;
每个根骨骼都有一个根节点,也就是图中骨骼根部的球状部位,骨骼之间通过根节点进行约束,出了root节点,每根骨骼节点都会存储相对于父节点的变换矩阵,通过变化矩阵动画系统就可以从根节点的运动计算出其下所有子节点的相对运动。
3.骨骼动画驱动骨骼和模型
所谓骨骼动画其实就是一系列的骨骼移动旋转的关键帧信息,动画系统通过每帧读取这些关键帧信息来控制骨骼做对应移动旋转动作,然后骨骼再驱动绑定在骨骼上的模型的点来控制模型跟随骨骼运动,这个过程是一些列复杂空间坐标转换,最终输出人物在世界坐标中的动画效果。
4.骨骼插槽
骨骼插槽就是字面的意思,附着在骨骼上的插槽,可以用于在骨骼的指定位置添加对象,如在手上添加武器,在头上添加帽子等。
添加插槽
在骨骼树下右键指定的骨骼选择Add Socket可以在指定骨骼下添加插槽,一个骨骼下可以添加多个插槽。插槽会记录下自己相对与骨骼的Transform信息,当对象绑定到插槽时会将Transform信息应用到对象上。
在编辑器中绑定插槽
静态绑定就是直接在编辑器中进行绑定,我们为Character添加一个StaticMesh并给与一个球体模型,然后在Details/Sockets下就可以选择组件要绑定的骨骼插槽了。
选了骨骼插槽后StaticMesh就会应用骨骼插槽记录的Transform信息,自动修改相对位置和相对缩放。
蓝图动态绑定插槽
我们以一个人物跳起时头顶发生爆炸的效果为例。
我们在头部骨骼上创建一个插槽,然后使用蓝图动态创建一个ParticleSystemComponent,将ParticleSystemComponent绑定到Mesh上,在AttachComponentToComponent节点上我们就可以直接绑定插槽。
然后在跳起时触发特效
运行效果:
C++动态绑定插槽
先上代码:
//.h
#include "Particles/ParticleSystemComponent.h"
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "OCharacter.generated.h"
UCLASS()
class OTHERWORLDLYKINGDOM_API AOCharacter : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Component")
UParticleSystemComponent* ParticleSystemComp;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Component")
USkeletalMeshComponent* SkeletalMeshComp;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Component")
UParticleSystem* ParticleSystem;
public:
AOCharacter();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
void OJump();
void OStopJumping();
};
//.cpp
#include "OCharacter.h"
//...
void AOCharacter::BeginPlay()
{
Super::BeginPlay();
ParticleSystemComp = NewObject<UParticleSystemComponent>(this, TEXT("ParticleSystem"));
ParticleSystemComp->RegisterComponent();
ParticleSystemComp->SetAutoActivate(false);
TArray<USkeletalMeshComponent*> SComps;
GetComponents<USkeletalMeshComponent>(SComps);
for (TObjectIterator<USkeletalMeshComponent> It; It; ++It)
{
USkeletalMeshComponent* Comp = *It;
if (Comp->ComponentTags.Num() > 0)
{
if (Comp->ComponentTags[0] == FName(TEXT("Main")))
{
ParticleSystemComp->AttachToComponent(SkeletalMeshComp, FAttachmentTransformRules::KeepRelativeTransform, TEXT("headSocket"));
}
}
}
ParticleSystem = LoadObject<UParticleSystem>(nullptr, TEXT("ParticleSystem'/Game/AnimationStudy/StarterContent/Particles/P_Explosion.P_Explosion'"));
ParticleSystemComp->SetTemplate(ParticleSystem);
InputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &AOCharacter::Jump);
InputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Released, this, &AOCharacter::StopJumping);
}
//...
void AOCharacter::OJump()
{
Jump();
if (ParticleSystemComp != nullptr)
{
ParticleSystemComp->SetActive(true, false);
}
else
{
UE_LOG(LogTemp, Error, TEXT("AOCharacter::Jump-ParticleSystemComp is null"));
}
}
void AOCharacter::OStopJumping()
{
StopJumping();
if (ParticleSystemComp != nullptr)
{
ParticleSystemComp->SetActive(false, true);
}
else
{
UE_LOG(LogTemp, Error, TEXT("AOCharacter::StopJumping-ParticleSystemComp is null"));
}
}
我这里是直接在Character中进行插槽绑定的,所以先为ThirdPersonCharacter
蓝图创建一个C++父类AOCharacter
,然后在父类中进行插槽绑定。
为了将UParticleSystemComponent
组件挂载在指定的USkeletalMeshComponent
上这里使用ComponentTag
标签来做组件的识别标志。
最终效果:
7.骨骼重定向
骨骼重定向的作用
首先我们需要明白动画的底层规则是什么,动画序列是依附于骨骼创建出来的若干关键帧的组合,这些关键帧中存储着这套骨骼的一些基本信息,所以这个动画序列只能在对应的骨骼上使用,如果想要将这个动画序列使用在另一套不同的骨骼上,由于动画序列中并没有另一套骨骼的信息,或者说信息不匹配,所以就无法应用。
骨骼重定向技术就是用来解决这个问题的,重定向有一个基础前提,就是源骨骼与目标骨骼必须在整体层级上保持一直,才能进行重定向。
什么叫做整体层级上保持一致呢?这里用小白人和一个丧尸的骨骼来举例子。
可以看到丧尸Hips骨骼的子层级和小白人的pelvis骨骼的子层级基本一致,动画主要使用盆骨,三根脊椎骨,锁骨,手臂骨,小臂骨手指骨,脖子的骨骼,大腿骨,小腿骨以及脚骨,二者在层级上都保持一致,区别只在于丧尸骨骼的手指骨骼被拉长了,盆骨处多了两个服装动画使用的骨骼BackCloth和FrontCloth,而丧尸骨骼相对于小白人缺少了两个IK骨骼。这种情况,尽管骨骼名称不一样,依然属于整体层级上保持一致,二者就可以做重定向来互相使用动画。
如果拿小白人和一只小狗的骨骼举例子,那么种情况就是整体层级不一致了。
如果将小白人的动画重定向后应用到丧尸身上,由于小白人的骨骼在丧尸上基本都有,所以动画可以应用,但是由于小白人没有服装骨骼,所以丧尸的服装将不会有动画,丧尸骨骼没有IK骨骼,所以小白人的IK动画在丧尸身上也不会生效。如果将丧尸的动画重定向到小白人身上,同样的道理,动画也可以应用上,但是也是由于小白人缺少服装骨骼,所以丧尸服装骨骼的动画在小白人身上也不会生效。
如何进行骨骼重定向
了解了重定向的基本规则之后,我们该如何重定向呢?
这里我使用外部动画应用到小白人身上为例子来说明。
这里我们先去网上下载一个动画素材下来,这里可以去Adabo的Mixamo网址去下载动画素材。下载素材需要先登录账号,注册一个登录进去,在Animations下我选择了一个跳舞的动画Rumba Dacing来做素材。
点击右侧的DownLoad进行下载,下载下来的文件是一个fbx文件,我们将文件导入进UE,勾选上导入动画,其他的选项全部默认就可以,然后导入全部。
导入进来两个材质,一个骨骼网格体,两个动画序列,一个物理资产和一个骨骼资产。
来看看动画序列:
我们双击进入骨骼资产,在菜单栏有一个重定向管理器,打开会弹出骨骼重定向编辑视图。
点击选择绑定,选择人形绑定,然后在下方我们需要手动的将新导入的骨骼一一的映射到标准的人形骨骼上。
这里映射的是基本的身体骨架,点击显示高级项,可以再进行手指和脚步的骨骼映射,一些没有的骨骼可以不映射,设置完之后可以点击保存将映射信息保存下来。
到这一步外部骨骼重定向到标准人体骨骼就完成了。
然后我们打开小白人的骨骼,同样使用重定向管理器,在选择绑定处也选择人形绑定,然后点击自动映射,因为小白人的骨骼UE就是按照标准骨骼来创建的,所以自动映射可以映射上。
然后右键新导入的跳舞动画,选择重定向动画资产/复制动画资产并重定向。
这时我们就可以进入真正的骨骼重定向界面。
选择我们需要重定向的小白人骨骼,点击重定向,这是UE会自动为我们创建一个重定向后的动画序列。
可以看到动画已经应用到小白人身上了,UE通过标准人体骨骼将外部骨骼的动画重定向到了小白人的骨骼上,但是骨骼位置似乎出现了偏移,这是因为,从Mixamo下载的动画初始姿势是Maya标准的T-Pos姿势,整体上看起来是一个T字,手臂和身体成90度角。
而UE的默认初始姿势则不是标准的T-Pos,手臂和身体成45度角。
这就会导致重定向时骨骼的变换出现偏差,有两个中处理方案,一种是外部导入的骨骼按照UE的标准制作初始姿势,另一种就是将UE默认的初始姿势修改成Maya的标准T-Pos姿势。由于我不会maya,所以我只能选择后面的一个方案来处理了。
修复小白人位姿偏移
这里我使用Mixamo来将小白人的姿势改为T-Pos。
首先将小白人的骨骼网格体导出来。
兼容格式要选择2013以下,静态网格体中的碰撞不需要导出可以取消勾选。
然后我们再次进入Mixamo点击右侧的Upload Character,把我们的导出的网格体上传到Mixamo,上传完成后小白人的模型就可以在Mixamo中浏览了。
然后在Animations下搜索T-Pose,点击T-Pose动作,小白人就应用上了T-Pose动作。
然后再把小白人下载下来并导入UE中,会直接导入一个名字叫T-Pose的动画序列。右键这个动画序列/创建/创建姿势资产。
然后打开小白人的骨骼,在重定向管理器视图选择修改姿势,导入我们刚创建的姿势资产,然后点击查看姿势,我们新的T-Pos姿势就应用到了小白人身上,现在我们再重定向一次,直接右键跳舞动画/重定向动画资产/复制动画资产并重定向,让UE重新创建一个动画序列,然后来看看效果:
效果还可以。
重定向链
这是UE5的新功能,IK Rig和IK Retargeter在做骨骼重定向的时候可以以一条骨骼链的形式来进行链与链的重定向并且通过IK重定向器直接使用名字进行映射,可以省去重定向过程中的很多麻烦操作。
这里我使用从模之屋下载的看板娘的模型套用到小白人身上作为例子。
首先从模之屋下载MMD模型,这里下载的模型是.pmx格式的,不能直接应用到UE中,所以需要先把.pmx格式的文件转换成.fbx,这里使用了一个日本大佬从一个Unity插件中提取出来的工具(pmx2fbx)进行转换,国内也有很多帮运,如:https://www.bilibili.com/video/BV11K4y1G7DL/?vd_source=e979466844c4915a4200c496efb35cfb
使用方法也很简单,输入指令将下载好的mmd模型转换为UE可识别的fbx文件,然后导入到UE。
导入进来的模型会自带很多空白材质,需要我们自己导入模型自带的贴图修复,这里就先使用白模了。
首先右键/动画/IK绑定/IK绑定
为我们新导入的模型骨骼创建一个IK绑定,选择我们新导入的骨骼网格体perer_41,并命名为IKRing_Per。
然后在IK编辑器里选择骨骼右键/新建来自选定骨骼的重定向链,在弹出的界面点击确定,这是UE会提示我们为骨骼链添加IK目标,由于现在还没有目标,所以选择无目标,这样一条骨骼链就创建好了。
这里我没有重定向手指,只重定向了几个主要的骨骼,下面列出我重定向的骨骼链及其涉及骨骼的名称:
骨骼链名称 | 涉及骨骼 |
---|---|
Root | 263_!Root |
Spine | 12_joint_Torso |
13_joint_Torso2 | |
Head | 19_joint_Neck |
21_joint_Head | |
LeftArm | 61_joint_LeftArm |
66_joint_LeftElbow | |
71_joint_LeftWrist | |
RightArm | 25_joint_RightArm |
30_joint_RightElbow | |
35_joint_RightWrist | |
LeftLeg | 115_joint_LeftHipD |
116_joint_LeftKneeD | |
117_joint_LeftFootD | |
118_!joint_hidariashisakiEX | |
RightLeg | 111_joint_RightHipD |
112_joint_RightKneeD | |
113_joint_RightFootD | |
114_!joint_migiashisakiEX | |
LeftClavicle | 59_joint_LeftShoulder |
RightClavicle | 23_joint_RightShoulder |
盆骨(14_joint_HipMaster)比较特殊,不用创建骨骼链,但是要设置为重定向根。
然后为小白人也创建一个IK绑定,命名为IKRing_SK,按照一样的逻辑创建对应的骨骼链和设定重定向根:
骨骼链名称 | 涉及骨骼 |
---|---|
Root | root |
Spine | spine_01 |
spine_02 | |
spine_03 | |
spine_04 | |
spine_05 | |
Head | neck_01 |
neck_02 | |
head | |
LeftArm | upperarm_l |
lowerarm_l | |
hand_l | |
RightArm | upperarm_r |
lowerarm_r | |
hand_r | |
LeftLeg | thigh_l |
calf_l | |
foot_l | |
ball_l | |
RightLeg | thigh_r |
calf_r | |
foot_r | |
ball_r | |
LeftClavicle | clavicle_l |
RightClavicle | clavicle_r |
然后再右键/动画/IK绑定/IK重定向器,在弹出的界面中选择IKRing_Per作为源,然后进入IK重定向器编辑视图。
在细节面板设置目标为IKRing_SK,为了重定向效果更好,我们需要将目标骨骼的姿势尽量修改得和源骨骼一致,在左侧点击编辑模式可以直接修改骨骼偏移来对姿势进行编辑,可以修改目标网格体偏移来设置源骨骼与目标骨骼的重合与分离。
全部设置好之后,我们就可以在资产浏览器中选择一个动画序列来看看重定向之后的效果:
看起来效果还不错。
重定向好之后我们要怎么把模型应用到小白人身上呢?
在应用到小白人之前我们先给人物上一下材质和布料(布料可以查看第三章骨骼网格体第2小节布料系统),这样好看点,做起来也有动力😍。
过程就直接省略了,直接看效果:
首先我们要为新角色创建一个动画蓝图,创建的时候要选择新角色的骨骼,这里命名为Anim_Per:
从网格体重定向姿势(Retarget Pose From Mesh)应该是UE5专门为数字人添加的节点,我在UE4.27中搜不到这个节点,Retarget Pose From Mesh可以从一个骨骼网格体复制动画数据到当前骨骼网格体,因为动画序列在不同的骨骼上是不兼容的,Retarget Pose From Mesh可以让一套骨骼便捷的使用另一套骨骼的动画序列,使用上需要在Details/Settings/IKRetarfeterAsset中设置我们配置好的IK重定向器。然后我们拷贝一个第三人模板的角色蓝图,在已有的骨骼网格体Mesh下新建一个骨骼网格体,并设置好我们的角色资产和动画蓝图。
然后将两个骨骼网格体的Details/Optimization/Visibility Based Anim Tick Option选项设置为Always Ticj Pose and Refresh Bones,这时我们的新角色就可以跟着第三人称模板的角色做动作了,然后把Mesh隐藏起来,然后跑起来看看效果:
看起来阴影有点问题,不过这是另一个问题了,这里就不用在意了。
导出重定向动画
这个方法是可以不一个个重定向动画序列的方式,当然这也导致我们的角色蓝图离不开父骨骼,如果我们想使用角色自己的独立动画序列资源,则在重定向编辑器中选择我们需要重定向的动画序列,点击资产浏览器下的导出选定动画即可,或者也可直接右键动画序列资产/重定向动画资产/复制和重定向动画资产,然后在重定向视图选择重定向器。
三、骨骼网格体
1.骨骼网格体转静态网格体
有时我们可能需要一些人物的Pose在做一些宣传图或者在游戏中做一些雕像之类的,骨骼网格体转静态网格体可以方便达成这些功能,其作用是将我们在骨骼编辑器中编辑好的临时姿势保存起来,因为骨骼编辑器可以编辑骨骼转向和偏移,但是都是临时的,我们可以将编辑好的姿势保存为静态网格体,这样以后就可以在任何需要的地方使用了。
做法也比较简单,在骨骼编辑器中将人物的姿势编辑好,然后直接点击菜单栏的Make Static Mesh即可将姿势保存为静态网格体。
2.布料系统
UE是自带了一套布料系统的,虽然效果上不是很优秀,不过也可以应付一些基本需求了。这里之所以把布料系统放在骨骼网格体章节下,是因为UE的布料是基于骨骼网格体的,并且UE的布料系统内容也不多。
这里说的布料系统基于骨骼网格体的意思是,UE的布料系统只能应用在Skeletal Mesh上,普通的Static Mesh是不能使用UE的布料系统的,这就要求所有要引用布料的模型都需要至少附带一根骨骼。
这里我们继续使用第二章中的MMD模型Perer来学习布料系统。布料编辑器是和骨骼网格体编辑集成在一起的,对布料的编辑就是直接在骨骼网格体编辑器中进行。
创建衣服数据
布料的一些基础信息UE使用了ClothingData资产来存储,直接在骨骼网格体编辑器中选中要创建衣服数据的网格体/右键/Create Clothing Data from Section。
AssetName可以修改衣服数据资产的名称,PhyiscsAsset可以选择衣服数据绑定的物理资产。
然后UE会自动打开Clothing管理窗口,当然我们也可以在Windows下手动打开Clothing窗口然后在ClothingData栏中点击Add Clothing来添加衣服数据。
应用衣服数据
ClothingData只是一个存储布料数据的资产,我还需要将资产应用到骨骼网格体上,选中要应用的骨骼网格体/右键/Apply Clothong Data,然后选择想要的资产应用。此时衣服上就有布料数据了,当然现在还没有布料效果,因为我们还没往ClothingData中刷入布料权重信息。
刷布料权重
点击菜单栏的Activate Cloth Paint,此时衣服骨骼网格体变成紫红色并显示网格,鼠标上到上边会出现绿色的笔刷,Clothing视图会多出很多配置选项,左上角会多出一个笔刷范围内的顶点的布料权重值Cloth Value。
在Clothing视图下我们需要关注一般只有的Tool Settings/Paint Value和Brush/Radius,前者设置的笔刷将赋予骨骼网格体的布料权重,默认值范围为0-100,超出范围的值需要手动输入,值越大代表权重越大,权重越大布料受物理系统影响越大,0就是不受物理系统影响,在骨骼网格体上表现为紫红色,受影响的部分变现为半透明灰色,中间值显示为黑色。
在刷权重的过程中可以按H键预览布料效果,或则取消激活Activate Cloth Paint也可以看效果。
有时候布料刷完之后表现起来可能怪怪的,这是因为布料受到物理资产的影响,布料会直接收到物理资产中的碰撞的碰撞影响,如果布料表现怪怪的我们可以调节一下物理资产中碰撞体大小和方位。
一个好的布料效果需要模型和布料经过大量的微调才行,一般来说网格体的点越多布料效果越好,但是也会越吃性能,具体项目需要在具体实践中找到平衡。
然后在给裙子也刷上布料就可以达到这个效果了:
UE的布料系统也包含很多内容,由于已经不在动画系统范畴,这里就只看这么多了,更多了留到以后再看。
四、物理资产
物理资产是专门用于骨骼网格体和布料系统做物理模拟的资产。
关于物理资产编辑器的界面的介绍可以看这篇文章:UE4物理精粹Part 2:Physics Assets Tool详解 - 知乎 (zhihu.com)
1.创建物理资产
物理资产可以在导入模型时勾选Create Physics Asset选项然UE根据骨骼创建默认的物理资产,也可以右键/Physics/Physics Asset来手动创建物理资产,手动创建物理资产时会让我们选择绑定骨骼,并且第一次打开时会然我们设置物理资产的约束。
2.物理形体
我们打开物理资产看到的一个个的胶囊体就是物理形体,UE通过这些物理形体来实现骨骼之间的物理碰撞。
创建物理形体
一般我们在导入模型或者手动创建物理资产后UE会为物理资产默认生成一套物理形体,一般不需要我们手动创建,当然如果我们角色UE默认创建的不好、物理形体丢失或者想要增加一些形体也是可以手动创建的。
如果物理形体丢失了,在物理资产编辑器视图的Tools视图中Generate All Bodies
按钮,在保证当前没有选择任何形体或骨骼的前提下,点击即可从新生成一套UE默认的物理形体组合。
如果想要增加物理形体,我们需要在Skeleton Tree视图选中想要添加形体的骨骼,然后点击Tools视图的Add Bodies
按钮,这个按钮添加的形体是默认的胶囊体样式,如果想要添加其他样式(如正方体),则右键骨骼/Add Shape,然后选择想要的样式即可。默认情况下物理资产编辑视图的Skeleton Tree视图好像是只显示形体而不显示骨骼的,我们需要点击Skeleton Tree右侧的设置图标选择Show All Bones才能看到所有的骨骼。
物理形体的属性
物理形体的属性相当的多,就不一一列举了,可以直接查看[官方文档](虚幻引擎物理形体参考 | 虚幻引擎5.0文档 (unrealengine.com))。
3.物理约束
物理约束本质上一种连接点,利用物理约束可以通过约束应用的限制和力度将多个Actors连接起来,如:绳索、吊桥等。
UE的物理约束系统是一个独立的系统,动画系统中的骨骼物理约束只是发动画系统对物理约束系统的应用。
在学习骨骼约束之前我们首先应该对物理约束系统有一个基础的了解。
物理动画
有了物理约束自然也就可以实现一些物理动画了,UE预制了一些物理约束Actor可供我们实现一些简单的物理动画。
PhysicsConstraintActor
物理约束对象(PhysicsConstraintActor)是一个连接点,可以对连接上连接点头尾的StaticMesh进行物理约束,如我们可以使用PhysicsConstraintActor创建一个具有物理惯性的下垂摆动动画:
使用方法也比较简单,PlaceActor中找到PhysicsConstraintActor拖入场景中,然后在Details/Constraint的Constraint Actor 1和Constraint Actor 2分别选择两个StaticMeshActor,设置需要摆动的方块启用物理模拟,并且Mobility设置为Moveable,运行后这个方块就会因为重力向下坠落,但由于受到PhysicsConstraintActor的物理约束,方块就会在物理约束下摆动,然后随着重力作用慢慢停止运动。
这里有一点需要注意,PhysicsConstraintActor只能约束StaticMesh,在选择头尾Actor时如果Actor是StaticMesh那么只需要选择约束Actor就可以实现约束了,如果Actor就是普通蓝图Actor则除了选择约束Actor还需要指定约束的StaticMesh组件名称。
CableActor
缆索是UE预制的绳子Actor,可以很便捷是制作出绳子的效果,这里还是使用上面的例子,但是两个Cube换成自定义的Actor,在加上CableActor来看看效果:
CableActor和PhysicsConstraintActor的用法差不多,也是从PlaceActor中找到然后拖入场景,然后在Details/Cable/Attach End To选择缆索末端的Actor,同样CableActor也只能约束StaticMesh,所以使用自定义Actor时需要指定ComponentName,预制的CableActor由一个空的CableActor和一个CableComponent组件组成,CableActor所在的位置为绳子头部,CableComponent所在的位置为绳子尾部。
PhysicsThruster
UE预制的在PlaceActor中的物理推进器Actor我没有研究出有什么用,可能有效果只是PhysicsThruster自身不可视我们看不到效果,不过我们可以从PhysicsThrusterComponent中窥见一二。我们只需要向自定义Actor中添加一个PhysicsThrusterComponent组件,然后勾选PhysicsThrusterComponent的Details/Activation/Auto Activate,然后Actor给与一个StaticMesh并启用物理模拟,物理推进器就可以推着Actor运动了,物理推进器组件会给与Actor一个持续的力,可以看一下有趣实践:
上面三种UE预制的物理约束都由组件,另外一些物理约束只以组件的形式出现。
PhysicsHandleComponent
物理柄组件是UE预制的专门用于制作物品抓取效果的组件,使用物理柄组件可以很方便快捷的实现任何具备物理效果的物体的抓取。
先来看一下效果:
实现上也比较方便,我们自己要实现的就是获取要抓取的Actor,和设置Actor跟随人物视角运动,其他就可以全交给PhysicsHandle组件了。这里我使用了继承自DefaultPawn的自定义Pawn来作为可控角色。全部蓝图如下:
PhysicalAnimationComponent
物理动画组件是用来设置角色在被Controller控制的同时也能被物理系统控制,一般需要配合布娃娃系统使用,如双手或身体的物理下垂,以实现“人类一败涂地”中的角色效果,用法其实也很简单,这里用一个案例来说明。
这里用第三人称模板来实践,首先为角色蓝图添加物理动画组件,然后在游戏开始时配置组件数据并启用布娃娃系统。
- Set Skeletal Mesh Component:为物理动画组件指定需要应用物理动画的骨骼网格体;
- Apply Physical Animation Settings Below:使指定骨骼及其所有子骨骼应用指定的物理动画数据;
- Set All Bodies Below Simulate Physics:启动布娃娃系统,需要注意的是Include Self需要取消勾选;
- 然后碰撞体组件的Details/Collision/Collision Presets设置为IgnoreOnlyPawn,骨骼网格体的Details/Collision/Collision Presets设置为Pawn。
然后看看效果:
DestructibleComponent
可摧毁组件专门用于制作破碎效果,组件用于存储可摧毁物体的物理数据,当然只有DestructibleMesh才可以制作破碎效果。
RadialForceComponent
径向力组件用于发出径向力或脉冲来影响物理对象或可摧毁对象的,径向力组件发出的力是瞬发的,发出后将不再持续。
DestructibleComponent和RadialForceComponent都涉及到物理破碎的知识,有点扯远了,这里也不多累述了。
4.布娃娃系统
要制作一个简单的布娃娃效果其实不难,UE已经为我们制作好了网格体的布娃娃效果,应用布娃娃效果的网格体必须绑定物理资产,然后我们就可以直接通过Set All Bodies Below Simulate Physics节点启用和关闭布娃娃系统了,当我们在控制角色上启用布娃娃系统时SkeletalMesh将直接交由UE的物理系统控制,此时Pawn将失去对SkeletalMesh的控制。
- Target:要应用布娃娃系统的网格体,可以是静态网格体也可以是骨骼网格体;
- In Bone Name:启用布娃娃系统的骨骼名称,指定名称往下的所有子骨骼都会启用布娃娃系统,如我们指定肩锁骨则整个手臂都会启用布娃娃系统,如果指定root则全身启用布娃娃系统;
- New Simulate:启用或关闭布娃娃系统;
- Include Self:具体是什么作用不清楚,官方文档没有说明,引擎源码也没有说明。
我们还可以通过Set All Bodies Below Physics Blend Weight节点来设置布娃娃系统与动画系统的控制权重,不设置默认权重为1,即启动后完全由物理系统控制角色动画。
然后我们来做一个简单的布娃娃系统。
首先编辑角色蓝图:
当角色掉落到地面时启用布娃娃系统,并设置权重为1。
然后碰撞体组件的Details/Collision/Collision Presets设置为IgnoreOnlyPawn,骨骼网格体的Details/Collision/Collision Presets设置为Pawn,然后看看效果:
五、动画序列
动画序列(AnimationSequence)是依附于骨骼的独立的动画资源,序列中大量的骨骼关键帧。是动画混合、动画合成、姿势资产和IK等的基础资源。
1.动画曲线
动画曲线就是以动画序列的帧数为X轴,以其他类型的值为Y轴的二维函数曲线,动画曲线没有什么特殊的意义,只是根据动画序列的帧数变化提供一个变化的值。
动画曲线的创建与编辑
动画曲线在动画序列编辑界面创建,单击Curves的下拉三角选择Add Curve/Create Curve。
单击曲线的下拉三角选择Edit Curve或者双击曲线可进入曲线的编辑视图。
动画曲线管理
在骨骼编辑器、动画序列编辑器和动画蓝图的菜单栏选择Window/Anim Curves可以打开动画曲线管理视图,在动画曲线管理视图可以对曲线进行筛选管理,是否激活材质参数以及编辑曲线的属性。
元数据曲线
在创建曲线时我们能看到一个Add Metadata选项,这个就是用来创建元数据曲线的按钮,元数据曲线就是一个特殊的动画曲线,元素据曲线是一根Y值为常量1的曲线,即Y值永远为1,不随X轴变化而变化,且不可修改。
按照官方的解释是,在大多情况下动画使用的曲线都是常量值为1的曲线,只有少数情况会用到值变化的曲线,所以才有了元数据曲线。
动画曲线的使用
这里以一个人物跳起时脚变大的麒麟腿效果为例子。
这里使用的是第三人称模板,在ThirdPersonJump_Start动画序列中添加曲线FootCurve,并添加(0.1,1)、(0.2,2)两个关键帧,在ThirdPersonJump_Loop动画序列中添加曲线FootCurve,并添加关键帧(0,2),在ThirdPersonJump_End动画序列中添加曲线FootCurve,并添加关键帧(0,2)、(0.2,1)。
这里所有动画序列都使用相同名称的曲线的一个好处是在动画蓝图中可以使用同一个名称来获取不同动画序列中的这个名称的曲线的值。
动画蓝图在播放到某一个动画序列时,通过名称来获取当前播放的动画序列的曲线的值。
在动画蓝图的JumpStart状态,JumpLoop状态,JumpEnd状态分别写入如下蓝图逻辑:
其中Transform(Modify)Bone节点做如下设置:
Transform(Modify)Bone是骨骼变换节点,可以对骨骼做位移,旋转和缩放变换,在Skeletal Control/Bone to Modify绑定骨骼既可对绑定骨骼做变换控制。
三者的不同在于播放各自的动画序列,JumpStart状态播放ThirdPersonJump_Start动画,JumpLoop播放ThirdPersonJump_Loop动画,JumpEnd播放ThirdPersonJump_End动画。
运行效果:
其他曲线节点
对曲线的获取除了上面用到的GetCurveValue节点,还有GetAllCurveNames和GetActiveCurveNames两个节点。
2.动画通知
动画通知(Anim Notify),是一种动画回调程序逻辑的机制,在动画的序列帧中绑定通知点,当动画播放到指定帧时就会触发函数回调,通知游戏逻辑。
动画通知的创建
动画通知的创建比较简单,再动画序列编辑器中的时间轴旁有一个Notifies栏,右键时间轴/Add Notify/New Notify,然后为动画通知命名,就可以在对应的通知栏创建一个动画通知。
每一个动画序列在被创建时会默认创建一个名称为1的动画通知栏,动画通知栏只是用来分类管理动画通知的,就如同蓝图变量里的Category。
在同一个通知栏同一帧处可以触发多个动画通知,一般同一栏同一帧处要触发多个动画通知的时候采用分栏管理会比较方便管理,点击Notifies的下拉三角/Add Notify Track可以增加新的分栏。
动画通知的回调
动画通知创建好后,编译完就可以直接在与动画序列绑定的动画蓝图中直接搜索到动画通知事件,动画通知被创建好后动画系统会为动画蓝图创建对应的名为AnimNotify_<动画通知名>
的蓝图事件,当角色动画播放到动画通知所在的动画序列的关键帧时对应的通知事件会被动画系统触发,然后我们就可以在动画蓝图中处理逻辑,或者通过调度器将通知传递到其他蓝图,或者直接引用其他蓝图的对象将通知传递出去。
在C++中使用动画通知
动画通知是依赖于动画实例(AnimInstance)而存在的,所以我们要想在C++中使用动画通知,就得先在C++中创建动画实例,然后再在实例中创建动画通知。
创建一个继承自UAnimInstance的自定义动画实例,在类中添加一个void AnimNotify_XXX(UAnimNotify* Notify)
格式的函数,如:
//.h
UCLASS()
class OTHERWORLDLYKINGDOM_API UOAminInstacne : public UAnimInstance
{
GENERATED_BODY()
public:
UFUNCTION()
void AnimNotify_Jump(UAnimNotify* Notify);
};
//.cpp
void UOAminInstacne::AnimNotify_Jump(UAnimNotify* Notify)
{
UE_LOG(LogTemp, Log, TEXT("Jump"));
}
这里有几点需要注意,函数必须是void AnimNotify_XXX(UAnimNotify* Notify)
格式,XXX对应的是动画通知的名字,动画系统会自动将这个函数与名字对应的动画通知相绑定,函数返回值必须是void,否则当动画通知回调时会触发警告:
LogAnimNotify: Warning: Anim notifier named AnimNotify_JumpStart, but the parameter number does not match or not of the correct type
并且函数必须使用UFUNCTION()
加入反射系统,否则动画系统将找不到函数与对应的动画通知相绑定。
创建好动画实例后,只需要在ThirdPerson_AnimBP的Class Settings的Details/Class Options/Parent Class下把父类改成我们自己创建的类,第三人称模板的动画蓝图就继承自我们自己创建的AnimInstance了,然后再在动画序列中创建一个与动画回调AnimNotify_Jump对应的动画通知Jump,当动画播放到动画通知所在的动画序列的关键帧处时就会自动触发C++中的动画回调函数,这样动画通知的信号就传递到了C++,当如果我们不想使用C++的AnimInstance我们也可以使用动画通知的蓝图回调事件加C++动态代理来实现这一功能。
自定义动画通知
除了使用自定义的动画蓝图外,我们也可以使用自定义的动画通知,我们只需要创建一个继承自UAnimNotify的蓝图类或C++类,动画系统就会将自定义的动画通知注册进系统,我们就可以在动画序列编辑器中看到自定义的动画通知了,如:创建一个名叫AnimNotify_JumpStart的自定义动画通知,然后我们就可以在动画序列里看到这个预定义通知:
自定义类中提供了Received_Notify
函数的重写,这样我们在接受到动画通知时可以做一些通用的处理逻辑。自定义的动画通知在被回调时直接进入Received_Notify接口,通过这个接口来处理逻辑,因此UE就将自定义动画通知的回调事件从动画蓝图中略去了,所以在动画蓝图中我们搜不到自定义通知的回调事件,因此自定义动画通知无法在动画蓝图中使用。并且自定义动画通知也不会显示在骨骼编辑器的Animation Notifies中显示。
骨骼通知
骨骼通知实际上和动画通知是一回事,我们创建一个动画通知时,动画通知是保存在骨骼资产里的,这也是为什么我添加动画通知时,骨骼资产会出现修改后的*号,我们添加的动画通知可以在骨骼编辑器的Animation Notifies视图下看到,如之前添加Jump通知。
我们添加骨骼通知时可以检索到骨骼资产里保存的所有的通知。
由于通知并不存储在动画序列里而是存储在骨骼资产里,所以我们在动画序列里删除的通知只是删除了通知的引用而并没有删除通知本身,我需要到骨骼资产里删除才是删除通知本身。
通知状态
通知状态应该交动画状态通知可能更合理,其实就是一种持续的动画通知,普通的动画通知是在动画运行到指定关键帧时进行一次调用,而通知状态则是可以跨多帧并且在通知所跨的每一帧都会进行通知,UE为我们预制了几个粒子特效播放的通知状态:
可以很便捷通过动画来触发一些粒子效果,比如人物走动时的烟尘效果。
- Trail:用来制作有运动轨迹的特效;
- Timed Particle Effect:用来播放老的粒子特效;
- Timed Niagara Effect:用来播放新的粒子特效;
- Advanced Timed Niagara Effect:可定时的粒子播放,只适用于新的粒子特效。
这里我们来使用Timed Particle Effect制作一个人物跑动时脚底冒火的效果。
分别在两个脚底骨骼ball_l和ball_r下创建两个插槽ball_lSocket和ball_rSocket,然后创建两个通知状态,并分别设置好触发时间、播放的粒子特效、绑定的插槽名称和插槽的缩放。
然后就可以跑起来看效果了:
自定义通知状态
官方预制的几个通知状态虽然用起来很便捷,但是功能却很单一,大多数时候还是得使用自定义的通知状态。
自定义的通知状态需要继承AnimNotifyState,我们直接创建一个继承自AnimNotifyState的蓝图类并命名为AnimNotifyState_Jump,自定义通知状态就注册进了动画系统,这时我们就可以在动画序列里看到自定义的动画通知了。
AnimNotifyState蓝图类是一个UObject类,并且蓝图编辑视图中没有Graphs视图,这就意味着AnimNotifyState蓝图类不能创建自定义事件,自定义动画通知状态的入口主要就是三个函数重载,Received_NotifyBegin
、Received_NOtifyEnd
和Received_NotifyTick
分别由动画系统在通知状态的开始帧、结束帧和每一帧中调用。在这三个函数接口中我们就可以在动画播放的指定时刻处理自定义的游戏逻辑。
动画同步标记
动画同步标记的资料目前我只在官方文档有找到,看来看去也没看明白怎么用,只知道动画同步标记是用来同步两个动画序列的,自己测试好像也没有看出有什么效果。
六、姿势资产
姿势资产(PoseAsset)是UE专门创建出来用于FACS(面部行为编码系统)和视位曲线驱动姿势的面捕动画(也就是我们俗称的面部捕捉)的资产,姿势资产一般配合变形目标一起使用,变形目标提供网格体变形的能力,而姿势资产则可以将这种变形动画混合进入动画蓝图中。
1.创建姿势
姿势必须依赖于某一个动画序列而存在,我们可以右键动画序列,在Create/Create PoseAsset下创建与指定动画序列绑定的姿势,或者右键空白处Animation/PoseAsset,然后在姿势创建视图绑定动画序列来创建一个姿势。
创建好姿势后,在姿势编辑器界面中会附带很多的Pose,动画序列每有一个关键帧,姿势资产便会创建一个Pose,这些Pose就是附加在骨骼数据里的曲线。
2.变形目标
变形目标(MorphTargets)实际上是建模中的一种术语,变形目标和骨骼动画有点类似,都是通过FBX导入,并且都自带网格体资产、动画序列资产和骨骼资产,不同的是变形目标还自带动画曲线。变形目标自带的曲线需要在建模时就名好名字,在UE中无法修改曲线名称。
导入变形目标的FBX是需要勾选网格体/导入变形目标
选项,否则导入的FBX将作为普通骨骼网格体导入。
变形目标导入成功后,我们可以在骨骼网格体编辑器的窗口/变形目标预览器
视图中看到变形目标自带的所有曲线,修改曲线值可以更改变形目标的形态。
3.使用姿势
姿势资产和动画序列一样可以直接拖到动画蓝图中以一个节点的形式使用,姿势节点有一个输入引脚一个输出引脚,姿势节点会输入的姿势进行混合然后输出混合好后的姿势。
姿势节点一般配合ModifyCurve
(修改曲线)节点使用,修改曲线节点可以通过曲线名称动态的修改动画系统中所有动画曲线的值,修改曲线节点可以在Details/Modify Curve/Curve Map中绑定一个Map来传递曲线值。
这里有一点是需要注意的,变形目标自带曲线,而通过变形目标的动画序列创建的姿势动画系统也会针对每一帧创建曲线,二者之间实际上是有重复的,即变形目标的自带曲线和姿势中的曲线可以控制同一形变,估计是因为变形目标的曲线名称不能在UE中修改,可能会出现美术的命名习惯和程序的命名习惯不一致,所以UE才搞这么一出吧。
所以对于上面的例子,我也可以不使用姿势资产,而通过修改曲线节点直接修改变形目标的自带曲线,如:
知道了原理之后我们就可以把变形目标换成人脸表情,我们就可以通过曲线来驱动表情了。
只要传入的面捕数据遵循LiveLink协议,UE就可以将数据传入LiveLinkPose
节点来驱动输入动画系统中的对应曲线,UE为我们预制好了LiveLinkRemapAsset重定向资源来做表情的重定向,这个资产我们可以在LiveLinkPose节点的细节面板中看到,对于和标准重定向资源不同的表情控制我们可以继承LiveLinkRemapAsset类来创建自定义的重定向资源,具体可以参见虚幻引擎Live Link。
七、混合空间
混合空间是UE专门用于混合动画的一种资产,相比与动画蓝图的混合节点,混合空间可以更方便的混合多种动画,并请且可以使用float进行状态控制。创建好的混合空间也可以直接在动画系统的资产浏览器找到,可以将混合空间视为一种特殊的动画序列。
混合空间有两种二维的BlendSpace和一维的BlendSpace1D,二者的用法基本都一样,在混合空间编辑视图里面最重要的就是AssetDetails面板。
这里就挑一些比较重要的,常用的设置讲解一下,其他的可以看[官方文档](虚幻引擎中的混合空间 | 虚幻引擎5.0文档 (unrealengine.com))
Axis Settings
-
Name:指定轴的名称,这个名称也是动画蓝图使用混合空间时对应轴的输入引脚的名称;
-
Minimum/Maximum Axis Value:轴的最小值和最大值。
-
Grid Divisions:轴的分段,值越大分的段就越多,分段越多动画混合就会准确。
-
Snap to Grid:勾选后动画系统会自动强制将不在网格顶点的混合点设置到网格顶点上;
-
Wrap Input:勾选后轴的输入值可以超出最大值和最小值的范围,当输入了超出范围的输入值时混合空间会将轴视为一个圆环,自动匹配输入值在环中的位置,并输出对应的姿势。
-
Smoothiing Time:值输入后动画更具输入值混合动画时的延迟,这里设置一个比较大数字看起效果可能会更明显,如:设置成2秒,将值设为0则关闭平滑时间。
-
Damping Ratio:平滑时间的缓动函数,有平均(Averaged)、线性(Linear)、立方体(Cubic)、慢入/慢出(Ease In/Out)、指数波(Exponential)和弹簧阻尼系统(Spring Damper)可选。
-
Max Speed:混合点跟随输入值的最大速度,会影响平滑时间,入我们上面设置的2秒的平滑时间,而实际混合点的跟随延迟并没有两秒,就是因为最大跟随速度是3。
-
Analysis:混合空间分析,有很多预制分析函数可选择,混合空间分析内容比较多,而且感觉一般情况也用不上,可以直接参见[官方文档](虚幻引擎中的自动混合空间创建 | 虚幻引擎5.0文档 (unrealengine.com))。
-
Weight Speed:权重速度,功能上和平滑时间差不多,相当于是UE预制的平滑时间,权重越小动画混合的越快,0则关闭权重速度。权重速度不可以与平滑时间或平滑类型一起使用。
-
Smoothing:启用权重速度的慢入慢出,和权重速度一样不可以与平滑时间或平滑类型一起使用。
-
Per Bone Overrides:每个骨骼覆盖,可以指定每根骨骼的混合速度。
-
Notify Trigger Mode:动画通知触发模式,可以设置混合空间中混入的动画序列中动画通知以什么模式触发,可以选择所有动画(All Animations)—触发所有动画序列中的动画通知、最高权重动画(Highest Weighted Animation)—只触发权重最高的动画序列中的动画通知、None—不出触发。
八、目标偏移
目标偏移是一种特殊的混合空间,用于在一个动画上叠加一个动画混合。
目标偏移从名字就可以看出最初的作用就是用于在持枪动画的基础上叠加瞄准动画用的,当然我们想叠加其他的动画也是可以的。首先我们需要创建一个目标偏移资产,右键内容浏览器空白/Animation/Anim Offset,目标偏移是一种特殊的二维混合空间,所以编辑界面和混合空间是一样的,和混合空间不同的是一般的动画序列是不可以直接拖入目标偏移的混合视图,我们要想在目标偏移中使用某个动画序列,我们必须对这个动画序列做一些设置。
我们需要设置动画序列的Asset Details/Additive Settings如下:
- Additive Anim Type:Mesh Space;
- Base Pose Type:Selected animation frame;
- Base Pose Animation:被叠加的动画序列;
- Ref Frame Index:0。
然后这个动画序列就可以被拖入目标偏移的混合视图去了。
在目标偏移的Asset Details/Additive Setttings/Preview Base Pose也需要设置成被叠加动画序列。
然后目标偏移资产就可以直接在动画蓝图中使用了。
目标偏移在动画蓝图中是这样的:
X,Y引脚分别为设置的横轴纵轴的名称,Base Pose传入要叠加的姿势,Alpha为混合权重。
目标偏移对加入叠加和被叠加的动画有一定的要求,如果二者比较重要的骨骼的偏移有偏差就会出现瞬移或者卡帧的问题,如我在Idle的姿势上叠加了一个被攻击的目标偏移:
九、动画合成
动画合成的功能很简单,就是单纯的将多个动画序列并接到一起作为一个动画资产来使用。
动画合成资产不具备动画混合能力,但在并接单个动画序列时提供一些简单的处理能力,如:删除动画序列的头尾帧,设置单个序列的播放速率和播放循环次数。
Composite即为合成轨道,合成轨道有两个轨道栏,导入的动画序列会由动画系统在两个轨道栏中一次错开,以方便编辑与区分。AssetDetails是这个动画合成资产的属性详情,不过上面的属性也没啥用处,连官方文档都懒得说明。
选中一个动画序列会显示这个动画序列在动画合成中属性详情,主要的属性就是开始时间(StartTime)、结束时间(EndTime)、PlayRate(播放速率)和循环次数(LoopCount),可以对单个动画序列进行简单的编辑。
动画合成也可以向普通的动画序列一样使用动画通知和动画曲线。
十、动画蒙太奇
动画蒙太奇可以算是一个高级版的动画合成,动画蒙太奇的功能也是将多个动画序列并接成一个资产,但相对与动画合成,动画蒙太奇的功能要强大得多,动画蒙太奇提供一种程序精确控制动画的方式。动画蒙太奇的作用是和状态机互补的,尽管状态机的功能很强大,但是也有不足的地方,比如当一个角色有10个技能,每个技能又由一系列的动画序列组成的时候,每个技能又由不能的按键触发,再加上角色基础的移动、跳跃等状态和一些只有在特殊场合才使用的动画,要只通过状态机实现这样的动作组,状态机会变得非常复杂,控制逻辑也会变得非常复杂,动画蒙太奇就可以弥补状态机的这一缺点,我们可以将10个技能和一些额外的动画都做成动画蒙太奇,这些蒙太奇可以使用一个或几个蒙太奇插槽混入状态机中,然后通过程序直接控制播放可以极大的减小状态机的复杂度。
动画蒙太奇编辑视图和动画合成编辑视图长得基本一样,使用上也大差不差,在编辑一段自己的动画蒙太奇之前我们需要先了解两个概念。
1.蒙太奇分段
可以看到动画蒙太奇编辑视图相对于动画合成编辑视图多了一个Montage轨道,这个轨道就是用来处理蒙太奇分段的,蒙太奇分段就是动画轨道上的一个时间片段,如上图中Montage轨道上就有三个分段,分段所在的帧即为分段的起始帧,分段会将下一个分段的起始帧或动画蒙太奇的结束帧作为分段的结束帧,当一个分段之后还有其他分段则使用下一个分段的其实帧作为这个分段的结束帧,当一个分段之后没有其他的分段了则使用动画蒙太奇的结束帧作为这个分段的结束帧。如上图Pose1的结束帧就是Pose2的起始帧,Pose3的结束帧就是整个轨道的最后一帧。
创建蒙太奇分段
右键Montage轨道即可创建一个新的蒙太奇分段,创建的蒙太奇分段都会在Timing轨道带一个序号标签,这个序号标签就是单纯用来标识的,没有其他作用也不能选中,所有的分段都会显示在MontageSections视图中。
编辑蒙太奇分段
创建好蒙太奇分段后可以直接拖动分段来设定分段的起始帧位置,在MontageSections中会默认将新创建的分段自动连接在一起,大多数情况下我们是不希望那所有分段都连接在一起的,所以我们可以点击Clear按钮清除所有连接,或者点击箭头/Remove Link来断开指定连接。
在MontageSections视图中没有连接其他分段的分段的后面会有一个白色正方形按钮,点击即可选择这个分段之后想要连接哪个分段。
当几个分段连接在一起之后,动画蒙太奇会在播放完第一个分段后按照播放链一次播放后面的片段。
2.蒙太奇插槽
蒙太奇插槽指定就是动画蒙太奇编辑视图中的Group轨道,在创建一个新的动画蒙太奇时动画系统会设置这个动画蒙太奇到DefaultGroup.DefaultSlot轨道,即默认分组下的默认插槽。
创建蒙太奇插槽
如果我们要创建自己的插槽,需要在Anim Slot Manger视图中操作,分组和文件夹的作用一样,用于管理各个插槽。
一个动画蒙太奇资产可以包含多个插槽,要添加更多的插槽进入轨道,只需要点击Group的下拉三角选择New Slot,即可添加所有的已被创建的插槽。
使用蒙太奇插槽
编辑好的动画蒙太奇是不能向动画合成一样直接拖入动画蓝图中使用的,而是需要通过蒙太奇插槽混合进入动画状态中。
蒙太奇插槽直接在动画蓝图中是搜索不到的,我们需要使用默认插槽(Slot Defaultslot)来切换,点击默认插槽在Details/Settings/Slot Name可以进行插槽切换。
蒙太奇插槽在没有播放动画蒙太奇时不会影响动画蓝图其他节点,在播放动画蒙太奇时将直接忽略插槽之前的状态,插槽的输出引脚将只输出动画蒙太奇的状态。
3.播放动画蒙太奇
只要把动画蒙太奇分段和插槽理解到位了,动画蒙太奇的精髓也就掌握了,接下来就是使用了。播放动画蒙太奇的方法就一个蓝图节点:
- In Skeletal Mesh Component:要应用动画蒙太奇的骨骼网格体组件,骨骼网格体组件绑定的骨骼和动画蒙太奇绑定的骨骼必须是一致的;
- Montage to Play:要应用的动画蒙太奇资产;
- Play Rate:整个动画蒙太奇播放的速率;
- Starting Position:播放的起始时间;
- Starting Section:要播放的蒙太奇分段;
- On Completed:蒙太奇播放完后调用;
- On Blend Out:混出时调用,这个混出就是动画蒙太奇资产属性的混合设置下的混出,类似于视频的淡出;
- On Interrupted:在动画蒙太奇播放被中断时调用;
- On Notify Begin:在蒙太奇通知或蒙太奇通知窗口开始激活时调用;
- On Notify End:在蒙太奇通知窗口结束时调用;
- Notify Name:当前活跃的动画通知名称。
除了Play Montage节点UE还提供了一个更简洁的节点Play Anim Montage:
通过上面的这些知识点我们就可以制作一个角色出场动画了,这里使用两断动画来并接出一个出场动画:
先再Anim Slot Manager创建一个自定义的插槽StartPose,点击下拉三角在Slot Name选择新创建的插槽,然后拖入两断动画序列进入轨道。
创建三个分段,Pose1、Pose2、Pose3,我们需要的是Pose1分段和Pose3分段,所以在Montage Sections视图将Pose1连接到Pose3。
在动画蓝图添加默认的插槽节点并切换到自定义的插槽。
然后在角色蓝图的BeginPlay播放动画蒙太奇的Pose1分段:
然后来看一下效果:
可以看到角色在播放蒙太奇的过程中有出现跳帧的情况,这是因为我们使用了带根位移的动画,像这种出场动画我们是希望动画带位移,我们想要使用动画的位移这就涉及到另一个知识点—蒙太奇与根运动。
4.蒙太奇与根运动
说起来也简单,要应用动画序列的根位移我们只需要勾选带有根位移的动画序列的Details/RootMotion/EnableRootMotion,这样动画系统就会自动计算动画位移和角色位移,然后我们再来看一下效果:
效果已经很可以了。
5.蒙太奇通知
蒙太奇通知是专门用于动画蒙太奇的动画通知,创建方式上和普通动画通知一样,使用上有些差别,蒙太奇通知不会在动画蓝图中创建对应的事件,而是由PlayMontage节点触发,当我们使用PlayMontage节点播放蒙太奇动画,在动画播放到蒙太奇通知所在帧时就会触发On Notify Begin回调,一个动画蒙太奇中有多少个蒙太奇通知就会回调多少次。
蒙太奇通知有三类,Montage Notify、Montage Notify Window和Disable Root Motion。
- Montage Notify:蒙太奇通知对应普通的动画通知,激活时会回调PlayMontage节点的On Notify Begin;
- Montage Notify Window:蒙太奇通知窗口对应普通的动画通知状态,开始激活时会回调PlayMontage节点的On Notify Begin,结束激活时会回调PlayMontage节点的On Notify End;
- Disable Root Motion:禁用骨骼运动这个动画通知有点特殊,作用就是在激活期间禁用动画序列的根位移,有时动画蒙太奇会使用动画序列的根位移,比如上面的例子,但使用了根位移我们就没法控制角色的移动了,有时可能在蒙太奇播放的某个时间断里我们想要控制角色移动,Disable Root Motion就可以满足这种精确控制。Disable Root Motion使用上和蒙太奇通知窗口类似,但是Disable Root Motion不会触发PlayMontage的回调,甚至不能修改通知的名称。
现在我们用蒙太奇通知来为出场动画加一些特效,制作在大剑与地面接触时产生爆炸的效果。
首先在骨骼上的武器骨骼上加一个骨骼插槽weaponSlot,然后在动画蒙太奇中添加两个蒙太奇通知。
然后在角色蓝图中编写特效触发逻辑:
然后来看一下效果:
6.子蒙太奇
动画蒙太奇还可以创建类似子类的子蒙太奇,子蒙太奇所有属性包括分段、动画通知都和父蒙太奇一样,且不可更改,唯一能更改的就是插槽轨道中的动画序列,子蒙太奇的作用就是相同的动画蒙太奇配置应用不同的动画序列来适应不同的场景。
十一、动画蓝图
动画蓝图是整个动画系统的终点,所有的动画序列经过骨骼定向、混合、编译调整、融合之后,都通过动画蓝图整合在一起,给予角色使用。
动画蓝图均集成自AnimationInstance类,并且创建时需要绑定骨骼,这也印证了UE的动画系统都是基于骨骼的,一切的一切都要在骨骼之上才能应用。
1.动画蓝图编辑器
动画蓝图是动画系统专用蓝图,和不普通蓝图编辑器界面有所不同,动画蓝图有两个Graph,Event Graph和Anim Graph,Event Graph就是普通的蓝图编辑视图,普通蓝图能干的事它都能干,提供一个每帧调用的Event Blueorint Update Animation事件。Anim Graph则是专门的动画编辑视图,用于对动画做控制,如姿势混合、曲线控制、动画序列的读取以及状态机等都在这个视图编辑,视图提供一个最终输出OutputPose,动画可以在Anim Grahp中经过各种各样的编辑修改,但最终都只能连接上OutputPose来输出给角色。
按官方的说话,二者是相互配合工作的,Event Graph用于更新Anim Graph所需的数据,而Anim Graph使用这些数据驱动状态机、混合空间等驱动角色运动。
2.Event Graph常用节点
动画蓝图的Event Graph有一些特殊的预定义事件。
BlueprintBeginPlay
效果和常用的BeginPlay事件一样,在游戏开始时调用一次。
BlueprintInitializeAnimation
BlueprintInitializeAnimation的调用有点类似构造函数,应该是在动画蓝图被构造的时候由系统在构造函数里调用的,在编译和实例化动画蓝图时会被调用一次。
BlueprintUpdateAnimation
在PIE和Runtime都会每帧都会调用一次
BlueprintLinkAnimationLayersLayersInitialized
BlueprintLinkAnimationLayersLayersInitialized节点在链接动画层初始化时会被调用一次,按照官方的说法是:
在所有链接动画层初始化时激活连接的节点。您可以使用此节点运行一次逻辑,一旦所有链接的动画层首次初始化,该逻辑就会被激活。
BlueprintPostEvaluateAnimation
BlueprintPostEvaluateAnimation的作用我始终没看懂,按照官方的说法就是:
在评估 AnimBP 后激活顺序节点。使用此节点,您可以激活将在评估 AnimBP 后运行的逻辑
BlueprintPostEvaluateAnimation和BlueprintUpdateAnimation一样在PIE和Runtime都会每帧调用一次
其他
出来上面的几个事件外,动画蓝图还可以直接调用InputAction,即在设置界面配置的按键绑定事件。
3.Anim Graph常用节点
空间转换节点
空间转换节点有两个,LocalToComponent和ComponentToLocal。
在UE的动画系统中常规的动画姿势是运行在局部空间中的(这个局部空间个人理解应该就是以根骨骼为参照的局部坐标系),但是所有的骨骼控制节点和一些混合节点则是运行在组件空间中的(组件空间个人理解应该是以父骨骼为参照的局部坐标系),当需要对组件空间中的姿势做控制时就需要这两个节点做空间转换,所以两个节点一般成对出现。
其中白色代表局部空间数据流,蓝色代表组件空间数据流。
LayeredBlendPerBone
这个节点的中文名为每个骨骼的分层混合
。
节点的作用就是在基础姿势上从骨骼的层级上混合其他姿势到基础姿势中。
这里以第三人称模板的跑步姿势为基础姿势,然后往这个姿势中混合一个抬剑的姿势作为例子。
首先从Epic商城中找到Bossy Enemy Animation Pack
姿势包,然后导入到我们的项目中来。使用第二章骨骼第7小节骨骼重定向中重定向链的方式让小红人使用小白的动画序列,然后在动画蓝图做动画混合:
这里Boss_BattleEntrance_RM就是抬剑姿势。
- Base Pose:需要被混合的基础姿势;
- Blend Poses 0:需要加入混合的0号新姿势;
- Blend Weights 0:0号新姿势混入基础姿势的权重;
- Add pin:添加新的混合姿势;
到这一步混合还是不能生效的,我们还需要再节点细节面板中对要进入混合的骨骼做过滤。
在节点的细节面板中对骨骼进行配置:
深度混合代表骨骼参与混合的程度,0表示不参与混合,1表示完全取代基础骨骼变化,0-1之间则表示不同程度的混合,-1表示完全不参与混合,骨骼完全不会影响原骨骼。
然后运行一下看看效果:
LayeredBlendPerBone节点有两种模式Branch Filter和Blend Mask,在Details/Config/Blend Mode中可以切换两种模式,前面使用的就是Branch Filter–骨骼筛选,Blend Mask–骨骼遮罩可以做到比Branch Filter更精准具体的混合。
要使用骨骼遮罩我首先需要在骨骼编辑器中创建骨骼遮罩。
在BlendMasks栏显示的是已经存在的骨骼遮罩资产,创建好骨骼遮罩后骨骼编辑器会在骨骼树的右侧新增一列骨骼遮罩列,骨骼遮罩会对每一根骨骼都设有权重,权重为0表示这根骨骼上的叠加姿势完全不会应用到这个骨骼上,权重为1表示在这根骨骼上完全应用叠加姿势,权重介于0-1则根据权重值在这根骨骼上做姿势混合。
鼠标放置在骨骼遮罩列列头上会在列头显示设置菜单,在菜单中可以做切换骨骼遮罩和删除骨骼遮罩等操作。
这里我以走路姿势叠加一个被攻击的姿势作为例子。
这里我们我们把上半身的骨骼的遮罩权重全部设置成1,下半身的骨骼的遮罩权重全部设置成0,这样就可以实现一个在走路的过程中被攻击的动作。
设置好之后,就可以在LayeredBlendPerBone节点中应用了,在Details/Config/Blend Masks中使用我们新创建的骨骼遮罩BlendMask,然后编译,看一下效果:
感觉走起路来会飘,这是因为有一些骨骼是两个姿势都会使用且比较重要的,我们不能一刀切将骨骼遮罩权重设置1和0,所以我们在微调一下骨骼遮罩的权重,这里我们把root和pelvis骨骼的设置为0,将spine_01、spine_02、spine_03骨骼设置为0.5,然后再来看看效果:
可以看到效果就已经好很多了。
LayeredBlendPerBone节点的骨骼遮罩模式除了可以是使用骨骼遮罩(BlendMask)外还可以使用混合描述,混合描述又分为TimeBlendProfiles和WeightBlendProfiles,这些都是一些比较细微的混合了,感觉属于高端玩法了,一般情况也用不上,所以这里就不列举了,具体用处与功效可以参见官方文档。
Blend
Blend节点功能上和LayeredBlendPerBone一样,只是Blend不能做骨骼过滤,且只能做两个姿势的混合,使用上比LayeredBlendPerBone更方便,Blend不会做骨骼过滤,所以性能上会比LayeredBlendPerBone强,所以在不需要做骨骼过滤的情况下更合适。
BlendMulti
BlendMulti是Blend的多输入版,默认是两个输入引脚,右键节点/Add Blend Pin可以向节点添加新的引脚,选中引脚右键/Remove Blend Pin可以删除引脚,并且BlendMulti没有了基础姿势,所有的姿势都可以设置权重。
BlendPosesByBool
这是一个姿势的切换节点,可以根据输入的Bool值在两个姿势之间进行切换。
BlendPosesByInt
BlendPosesByInt就是BlendPosesByBool的多输入版本,通过Int值来在多个姿势之间做切换,引脚的添加与删除和BlendMulti一样。
BlendBoneByChannel
BlendBoneByChannel节点的功能很强大,除了不能添加更多的输入引脚功能上比LayeredBlendPerBone节点还强大,BlendBoneByChannel不仅可以筛选骨骼,甚至可以筛选骨骼的Translation、Rotation、Scale变换和应用的坐标空间,在节点的Details/Blend/Bone Definitions中可以添加要应用的骨骼和要应用的变换,SourceBone是基础姿势的骨骼,TargetBone是附加姿势的骨骼。在Details/Blend/Transform Space可以选择混合要应用的坐标空间。
如我们在走路姿势上附加一个被攻击的姿势,但只应用右手手臂的动作。
设置骨骼筛选
最终效果:
可以和下面的ApplyAdditive节点的效果对比看会更明显。
ApplyAdditive
ApplyAdditive节点的作用是动画附加,可以将一个动画附加在基础动画之上,要附加的动画序列需要做特殊的处理,即动画序列编辑器中的AssetDeltails视图/Additive Settings/Additive Anim Type设置为Local Space,Base Pose Type 设置为Selected animation frame,然后Base Pose Animation选择一个参考姿势,参考姿势的作用是附加动作和参照动作一样动作的地方在后续附加在其他动作上时会被忽略,不同的就会附加。
如我们在走路姿势上附加一个被攻击的姿势:
然后效果:
混合的还是很好的,效果基本和LayeredBlendPerBone差不多了。
ApplyAdditive和Blend的区别就是ApplyAdditive是附加动画到基础动画上,由于有一个参照姿势进行动作过滤,所以混合起来效果会更好,而Blend则直接将两个姿势混合,所有的骨骼都会根据权重互相影响,在这种情况下混合起来效果就没那么好,不过Blend很适合做步态的混合。
BlendPosesByEnum
这个节点的名字不是固定,是根据需要应用的枚举类型变化的,如我有一个枚举叫BlendEnum,那么我在搜索BlendPosesByEnum节点的时候就不是搜索BlendPosesByEnum而是搜索BlendPosesBlendEnum,直接搜索BlendPosesByEnum会列出系统所有的枚举在BlendPosesByEnum的应用。
BlendPosesByEnum节点的作用就是可以根据枚举中值来添加输入引脚,引脚会根据枚举的值来命名,并且使用枚举来做姿势切换,BlendPosesByEnum还提供一个默认姿势,当没有添加任何引脚时就会使用默认姿势。
BlendPosesByEnum节点默认是没有添加枚举中定义的引脚的,需要手动右键进行添加。
ApplyMeshSpaceAdditive
这个节点在网上的资料实在是找不到,官方文档也没有说明,只在Youtubo上找到了一个视频案例使用方式和ApplyAdditive基本一样,只是动画序列里的AssetDetails/AdditiveSettings/AdditiveAnimType选择MeshSpace。
MakeDynamicAdditive
MakeDynamicAdditive的作用正好和ApplyAdditive相反,MakeDynamicAdditive是从基础姿势中减去附加姿势。
Inertialization
Inertialization(惯性化)节点按照官方的说法是用来做高性能优化的,一旦启用了惯性化,那么动画系统将不再进行姿势混合计算,而是使用惯性化来输出姿势,可能是我测试的动画根本不吃什么性能,所以我实际使用中没有感觉有什么作用😂。
ModifyCurve
ModifyCurve节点用于在动画蓝图中驱动动画序列里创建的动画曲线。可以右键添加和删除曲线引脚。
LiveLinkPose
LiveLinkPose是UE专门开发用于接收动捕、表捕、手捕设备实时数据的节点,LiveLinkPose可以直接将这些实时数据混合成姿势用于角色动画的姿势混合中,如在播放指定动画序列时混入脸捕数据。
LiveLinkPose节点由LiveLink插件提供,需要启用LiveLink插件才能搜索到这个节点,在LiveLinkSubjectName中输入LiveLink视图配置的数据源名称即可实时接收到源传递过来的数据,并与输入姿势混合,并且输出一个带有实时数据的混合姿势。
4.状态机
状态机是动画蓝图里面一个非常重要的模块,用于管理复杂的姿势混合。
一个角色可能会有很多动画,或者各种技能,当这大量的动作姿势在AnimGraph混合的时候会导致视图非常复杂,在普通蓝图中可以使用函数、宏、事件来封装或者使用节点来组合,而动画蓝图则使用状态机来封装。
一个状态机由若干的状态(State)、导管(Conduit)、状态别名(Alias)、转换规则以及唯一的入口(Entry)组成。
创建状态机
直接在AnimGraph视图右键搜索State Machines即可创建一个状态机。状态机在表现上和普通蓝图的节点很相似。状态机没有输入引脚只有输出引脚,并且输出的也是一个姿势。
创建好状态机后就可以双击进入状态机节点,对状态机进行编辑了。
State
State是用来封装姿势混合过程的节点,一个State输出一个最终姿势,State节点可双击进入进行姿势混合编辑。
每一个状态都可以在Details/AnimationState中定义三个回调事件,分别是进入状态事件(EnteredStateEvent)、离开状态事件(LeftSatateEvent)和完全混合状态事件(FullyBlendedStateEvent),在CustomBlueprintEvent处填写自定义事件名称,就可以为这个状态创建三个动画通知回调事件,和普通的动画通知效果一样,直接在EventGraph中搜索即可使用。
Transition Rule
我们从一个State1节点的边缘按住鼠标左键拖动到另一个State2节点的边缘即可创建State1转换到State2的TransitionRule,TransitionRule由一个箭头加一个转换节点组成,转换节点可双击进入,转换节点固定输出一个bool值,只有返回true时才可转换到所指向的State,转换节点中可以编写一些bool表达式逻辑,由于转换规则没有输入引脚,所以在转换规则编辑视图中是不可以直接调用带输入输出流程引脚的函数的,不过可以使用纯函数,所以一些比较复杂的bool表达式可以使用纯函数封装。
在转换规则中UE定制了几个转换专用的纯函数蓝图节点,不过个人感觉一般也不怎么用得上,所以就直接上官方文档链接了—[虚幻引擎中的转换规则](虚幻引擎中的转换规则 | 虚幻引擎5.0文档 (unrealengine.com))。
除了纯函数函数蓝图节点外,UE也为转换规则定制了几个动画通知函数。
这些动画通知函数除了WasAnim Notify State Active in Any State
外,其他的都只能在转换规则中使用。这些通知主要分为三类:
- Was Anim Notify Name Triggered In Any State:在转换规则之前的任何状态中如果指定名称的动画通知被触发则返回true;
- Was Anim Notify State Active In Any State:在转换规则之前任何状态中如果指定类型的动画通知状态被激活了则返回true;
- Was Anim Notify Triggered In Any State:在转换规则之前任何状态中如果指定类型的动画通知被触发了则返回true;
- Was Anim Notify Name Triggered In Source:在转换规则之前的活动状态中如果指定名称的动画通知被触发则返回true;
- Was Anim Notify State Active In Source:在转换规则之前活动状态中如果指定类型的动画通知状态被激活了则返回true;
- Was Anim Notify Triggered In Source:在转换规则之前活动状态中如果指定类型的动画通知被触发了则返回true;
- Was Anim Notify Name Triggered In State Machine:在转换规则之前的指定状态中如果指定名称的动画通知被触发则返回true;
- Was Anim Notify State Active In State Machine:在转换规则之前指定状态中如果指定类型的动画通知状态被激活了则返回true;
- Was Anim Notify Triggered In State Machine:在转换规则之前指定状态中如果指定类型的动画通知被触发了则返回true;
除了上面的几个通知外,转换规则也和状态也样Details/Notifications下提供了三个自定义动画通知,开始过渡事件(Start Transition Event)、终止过渡事件(End Transition Event)和中断过渡事件(Interrupt Transition Event)。
而对于中断过渡事件UE提供了更高端的设置,在Details/Events/TransitionInterrupt下可以设置更详细的中断配置。
Transition Rule Details
-
Priority Order:转换规则的优先级,当同一时刻有多个转换规则满足转换要求时,动画系统将选择优先级数字最小的优先转换。
-
Bidirectional:这个设置官方已经放弃使用了。
-
Transiton/Blend Logic:选择当前转换规则所使用的从前一个状态转换到下一个状态的混合模式,提供标准混合(Standard Blend)、惯性化混合(Interialization)和自定义(Custom)三种,选择不同的模式在Blend Settings下就可以设置不同选项。选择自定义模式在Blend Logic下拉列表后面会多出一个按钮Edit Blend Graph,点击按钮能进入自定义混合模式编辑界面,即可编辑自己的转换规则混合模式。
UE为转换规则自定义混合视图也定制了四个专用的蓝图纯函数节点:
SateWeight:获取上一个状态的混合权重。该数字在转换时长内逐渐从 1 减小到 0。
GetTransitoinTimeElapsed: 获取指定转换的耗时(以秒为单位)。
GetTransitionTimeElapsed(Ratio):获取指定转换的耗时(以交叉转换时长的比例表示)。换句话说,该数字在转换时长内逐渐从 0增大到 1。
GetTransitionCrossfadeDuration:获取指定转换的交叉转换时长。这是 混合设置(Blend Settings)> 时长(Duration)属性中使用的数字。
-
Transition Rule Sharing:设置共享转换图表,在编辑状态机的时候有些转换规则的转换逻辑可能都是一样的,此时我们无需去编辑每一个转换规则,我们只需要编辑其中一个,然后点击Transition Rule Sharing栏后面的(Promote to Shared)按钮输入共享视图的名称,将这个转换规则的视图提升为共享视图,编译后我们在其他的转换规则的Transition Rule Sharing的下拉列表就可以看到新创建的共享视图了,选择即可应用共享视图,应用了共享视图的转换规则节点UE会自动为节点配色,以便区分。
-
Automatic Rule Based on Sequence Player in State:启动后转换规则会在上一个状态中最相关的动画结束时自动混入下一个状态,而不用编写转换逻辑。
-
Sync Group Name to Require Valid Markers Rule:和同步组配合使用,使用了同步组后只有在上一个状态包含了同步组标识的动画序列时这个转换规则才生效。
-
Transition Crossfade Sharing:应用共享Blend Settings,点击后面的Promote To Shared按钮可以将当前设置提升为共享设置,编译后即可在其他的转换规则节点中使用这个设置,修改设置时会同步所有转换规则。
-
Dureation:转换所需要的时间长度。
-
Mode:转换混合时使用的曲线类型,按住Ctrl+Alt可以查看曲线预览。
-
Custom Blend Curve:设置自定义曲线。
-
Blend Profile:设置转换规则要应用的混合描述。
共享转换规则作用域只在单个状态机中,在其他的状态机中读取不到,并且状态到导管,和状态到状态的共享转换规则也不通用。
Conduit
导管(Conduit)是用来给状态梳理转换流程的,导管可以看作是一种特殊的转换规则,普通转换规则只能在状态之间进行一对一转换,导管则可以实现一对一、一对多、多对一和多对多的转换。双击导管节点可进入导管编辑视图,导管编辑视图和转换规则一样也只返回一个bool值。导管的Details视图只有一个名称属性,没有其他任何属性。
如这样的一个状态机:
我就可以用导管疏导成这样:
这在一些极为复杂的状态机中很有用。
如果想要从Entry直接连接到导管,则需要勾选状态机的Details/Settings/Allow Conduit Entry States选项。
Alias
状态别名(Alias)的作用和导管一样也是对复杂的状态转换进行疏导,状态别名可以看成若干个状态节点的集合的别名,这里的别名可以直接理解为编程语言中的别名,我们可以在状态别名的Details/State Alias下勾选状态机中哪些状态属于集合,当集合中的任一状态激活时,别名也同时会被激活。
如上面的状态机,我们可以使用别名来疏导成这样:
状态机属性
- Max Transitions Per Frame:设置在整个状态机中一帧内可以同时发生的转换的数量,默认值是3,表示在一帧内如果满足转换条件则可以同时触发三个转换,三个转换会在系统的配置下或根据优先级或根据默认规则彼此竞争最终使用一个转换,如果设置成1,则一帧内只能做出一个转换决策,从而避免多个转换之间互相竞争。
- Max Transitions Requests:这个属性应该UE5.1新加的,我在UE5.0的官方文档中没有找到这个属性的介绍,直接机翻的意思是"可以随时取消的最大转换请求数。删除最早的转换请求以适应新创建的请求",应该也是和转换相关的。
- Skip First Update Transition:勾选此选项,当状态机初始化时如果转换规则满足则直接进入对应的状态,不勾选则初始化时及时满足转换规则也不会进入对应状态而是依旧处于默认状态。实际使用中似乎感觉这个选项没什么乱用,效果只会在状态机初始化时执行一次,之后要想效果再生效就只能重启引擎让状态机再初始化一次,并且不会影响运行时的效果。
- Reinitialize on Becominig Relevant:当状态机变得相关时重新初始化,即当多个状态机混合时,每次进入这个状态机时,状态机都进行一次初始化,但是只会进入到默认状态,即使满足转换规则也不会进入对应的状态。
- Create Notify Meta Data:启用转换规则的动画通知,如果不勾选,则状态机内所有的动画通知都不可用。不知道是不是bug,我实际测试时并没有实现官方文档说的这个效果,动画通知始终有效。
- Allow Conduit Entry States:启用该属性将允许导管用作进入状态,从而允许不同的默认状态,具体取决于导管的转换规则。
十二、ControlRig
控制绑定(ControlRig)是UE为了虚拟制片引入一个插件模块,使用ControlRig可以在Sequence中很便捷的控制骨骼动画,除此之外也给程序提供了一个便捷的控制骨骼运动的接口,发展到现在ControlRig主要应用已经有虚拟制片、动画IK以及动捕,面捕,手捕等的骨骼控制等。
ControlRig在UE5中默认是不启动的,所以如果我们想要使用ControlRig资产就必须启用ControlRig插件。
1.ControlRig资产
我们可以动过右键内容浏览器/Animation/ControlRig/ControlRig或直接右键对应的骨骼网格体/Create/ControlRig来创建一个ControlRig资产(UE5.0和UE5.1可能会有点不一样)。创建ControlRig资产时会让我们选择ControlRig的父类,如果没有自定义的ControlRig父类则直接选择ControlRig类,我们可以通过继承ControlRig类来自定义ControlRig资产的父类,以实现一些通用功能的封装。
ControlRig有专门的编辑器界面,通过骨骼网格体创建的ControlRig是已经绑定好骨骼的,而直接创建的ControlRig里面没有任何东西,我们需要自己手动绑定骨骼,双击进入编辑器界面在RigHierachy视图下有一个ImportHierarchy按钮,点击在弹出的界面中选择我们要应用的骨骼网格体即可为资产手动绑定骨骼或则右键RigHierachy视图的空白处/Import来选择导入的谷骨骼网格体。
2.ControlRig编辑器
ControlRig编辑器中有很多的视图都是比较重要的,我们需要了解一下他们的作用。
菜单栏
- Forwards Solve:解算器预览,解算器决定ControlRig的计算方式,不同的解算器对应不同的ControlRig入口,ControlRig默认使用Forwards Solve解算器,对应Forwards Solve事件入口,我们可以点击解算器预览按钮后面的设置按钮选择不同的解算器预览,解算器往后连接的一系列节点组成的一条长链被称为解算链,解算器预览提供四种预览,Forwards Solve、Backwards Solve、Backwards and Forwards、Contruction Event,选择Forwards Solve,ControlRig编辑器将激活向前解算器,选择Backwawrds Solve,ControlRig编辑器将激活向后解算器,选择Backwards and Forwards,ControlRig将同时激活向前向后解算器,先执行向后解算器,再执行向前解算器,Construction Event好像没什么卵用。
- Auto Compile:自动编译,选中后ControlRig编辑器将在我们做了任何修改之后自动编译,而无需我们手动编译。
- Control Rig Editor Preview:这个选项官方文档中也没有说明,自己在摸索之后感觉是和后面的调试模式功能配合使用的,这个选项可以选择使用Control Rig Editor Preview或资产本身。
- ReleaseMode:ControlRig的运行模式,切换到DebugMode配合Control Rig Editor Preview可以在ControlRig编辑器中进行解算链的调试,在DebugMode模式下后面的运行按钮会变亮,我们在解算链中添加断点,然后运行解算链,运行会在断点节点处中断,然后可以使用后面的几个工具进行断点调试。
- Diff:这个选项使用来做版本控制的,一般没有直接使用UE连接版本控制软件都用不上。
- Hide Unrelated:解释是说隐藏与选中节点无关的节点,但是没搞明白怎么用。
RigHierachy
绑定层级视图显示了整个骨骼层级,我们可以选中对应的骨骼打开右键菜单来对骨骼进行操作,其中比较重要的就是New菜单下的控制点,创建好的控制点会依附在对应的骨骼层级下。
Execution Stack
执行堆栈视图显示了整个解算链的执行流程,在执行堆栈视图可以清晰的看到执行流程并点击可以快速定位到对应的节点。
Curve Container
曲线容器视图列出了ControlRig绑定骨骼可以使用的所有动画曲线,我们可以使用GetCurveValue
和SetCurveValue
节点来获取与操作这些曲线。
3.Control
ControlRig中最重要的内容就是控制点,我们对骨骼的控制都通过Control控制点来操作,我们通过选中对应的骨骼在右键菜单的New栏中选择New Control来创建新的Control控制点,创建出来的控制点会依附在对应的骨骼层级中,以红色的图标表示。同时也可以选择多个骨骼在右键菜单的New栏中选择Add Controls For Selected选项来批量创建,批量创建的控制点不会依附在对应的骨骼层级中而是会单独的创建一个层级。
控制点的细节面板(这里就挑一些重要的看了):
-
Control/Animation Type:动画类型,官方文档也没有说明具体由什么用,网上也几乎搜不到资料,只能自己摸索了。
类型 说明 Animation Control 有具体形体,可以控制动画的控制点 Animation Channel 具有动画通道的没有具体形体的控制点 Proxy Control 代理控制点,看说明是可以代替多个控制点的移动控制,并且Driven Controls下也可以添加驱动控制点,就是不知道怎么用 Visual Cue 不可选中也不可控制动画,但有具体形体的控制点,主要用于标识作用 -
Control/Value Type:控制点值的类型,不同类型的值可以进行不同形式的骨骼控制。
类型 说明 Bool 布尔型值的控制点可以在操作蓝图节点中设置布尔值,只是没弄明白设置设个布尔值对骨骼控制有什么作用 Float 浮点型值得控制点可以在PrimaryAxis中选择一个轴,控制点将只能在这跟轴上移动,不可以在其他轴上移动 Int 整型值控制点作用上和浮点型类似,除此之外整型值控制点可以在ControlEnum中绑定枚举类型,将整型转换成枚举类型,以便程序控制时更方便 Vector2D Vector2D值控制点可以限制控制点在一个平面内移动,在PrimaryAxis可以选定一个轴,选定的轴将被排除在平面外,即控制点只能在剩下的两个轴组成的平面内移动 Position Position值类型控制点可以限制控制点只能修改位移 Scale Scale值类型控制点可以限制控制点只能修改大小变换 Rotator Rotator值类型控制点可以限制控制点只能修改旋转量 Euler Transform EulerTransform值类型控制点对控制点没限制,控制点可以修改整个Transform值 -
Transform/Min/Max:我们选择一些值类型的控制点时在Transform栏中可能会出现Min和Max的控制栏,我们勾选上指定的轴就可以对应用在这个轴上的输入值控制接收最小值和最大值。
-
Shape/Shape Properties/Shape:选择控制点形体的样式,对于不同值类型的控制点选择适合的样式可以很直观的看出控制点的值类型和控制方式。
控制点的变换应用
我们单单只创建控制点是不能直接使用控制点控制骨骼的,我们需要使用两个节点来传递变换值,获取控制点变化的Get Transform - Control
节点和设置骨骼变换的Set Transform - Bone
节点,我们将节点连接到解算器,编译后就可以在预览视图中通过控制点实时预览控制点对骨骼的控制了。
我们这里做一个使用控制点来实现一个简单捏脸的例子实践一下。
使用控制点实现捏脸效果
这里使用官方提供一个免费角色作为素材。
首先为角色创建一个ControlRig资产—Shinbi_CtrRig,并在角色脸部的指定骨骼上都创建对应控制点:
然后配置解算链:
这里节点比较多就做了封装。
到这里骨骼的控制就实现了,然后我们需要将控制应用到动画中,我们为角色创建一个新的动画蓝图Anim_Shinbi,实现如下:
ControlRig节点需要在Details/ControlRig/ControlRigClass
中选择我们创建的ControlRig资产—Shinbi_CtrRig,然后在ControlRig节点的Details/Input下就可以看到在ControlRig资产中配置到结算链上的骨骼控制引脚了:
勾选上这些引脚用来接收输入,在动画蓝图中创建对应的变量来传递输入值。
然后我们创建一个UI把值传递到动画蓝图中,并对值做一些大小限制以实现比较好一点的效果,然后就可以实现简单的捏脸效果了,来看一下效果:
4.Bone
Bone是一种虚拟骨骼,创建出来后使用空心的骨骼图标表示,与实心的真实骨骼图标做区分,虚拟骨骼没有网格权重,不会影响网格交换,一般用来做辅助骨骼。
5.Null
空项(Null)是一种容器,用于管理控制器和虚拟骨骼,类似文件夹。
6.FullBodyIK
FBIK(FullBodyIK)是UE5在ControlRig框架下实现的一种IK方式,首先我们应该清楚什么是IK,IK即Inverse Kinematic—逆向动力学,与FK(Forward Kinematic)—正向动力学相对,我们知道人体骨骼动画中的骨骼是一种树型结构,父骨骼的移动会影响到子骨骼的移动,而子骨骼的移动也能反作用于父骨骼,通过父骨骼的移动正向计算其下所有子骨骼的移动的过程就是FK,反之,已知某一子骨骼的移动,反向计算其上层级骨骼的移动的过程就是IK,如我们常见的足部IK,就是通过控制足部骨骼的位置和旋转来适应不同的地形,然后通过IK来计算小腿、大腿、盆骨等上层层级骨骼的位置旋转来协调不同地形上的绳梯姿态。
UE自身提供了4中IK方法,TwoBoneIK、FABRIK、CCDIK和FBIK,每种IK方式各有优劣,具体可以看这篇博客【骨骼动画】UE的IK解决方案 - 知乎 (zhihu.com)。
看UE5的趋势官方应该是更倾向与使用FBIK的,因为在UE5的第三人称模板中官方已经使用FBIK为我们制作好了一个效果还行的足部IK了,ControlRig叫CR_Mannequin_BasicFookIK,并且直接应用了第三人称动画蓝图中了。
FBIK的核心就三个东西,首先使用射线检测确定骨骼的落点变换,然后使用ControlRig解算器控制骨骼变换,最后使用FullBodyIK
计算其他骨骼的变换,这样一个IK动画就完成了。
这其中的最重要的自然是FullBodyIK节点,节点功能很强大,输入引脚也是极其的多,我们一个个看。
-
Root:设置IK计算的根骨骼,即IK计算的最上层骨骼,再往上就不计算了,在人形骨骼上一般都设置为盆骨;
-
Effectors:官方文档成Effectors为执行器,用来设置IK计算的起始骨骼,这是一个数组可以设置多个起始骨骼。
Bone:应用的Effector设置的起始骨骼名称;
Transform:IK起点的变换,注意这里不是IK起始骨骼的变换,而是通过射线检测计算出来的骨骼落点的变换。
Position Alpha/Rotation Alpha:效果类似动画蓝图Blend节点的Alpha,用于控制骨骼变换的应用程度,1表示完全应用IK计算后的骨骼变换,0则是完全不应用。这里UE5.0和UE5.1有点出入,5.0二者合并成了一个Offset Alpha;
Strength Alpha:Effectors对骨骼链的影响程度;
Pull Chain Alpha:这个也是5.1新出的配置,官方文档上也没有更新这个设置的说明,按照编辑器的中文解释,这个设置使用来针对不同密集程度的骨骼链做IK解算时改善计算结果的;
Pin Rotation:这个设置也是5.1新出的,官方文档上也没有更新这个设置的说明,按照编辑器的中文解释,这个设置也是用来在移动输入的骨骼变换和执行器输入的骨骼变换之间做混合的,1表示使用执行器的骨骼变换,0表示使用移动输入的骨骼变换。感觉和Rotation Alpha的效果差不多,实际实践中感觉Pin Rotation的影响程度更高一点。
-
Bone Settings:骨骼设置用于针对单个骨骼进行解算属性设置,由于IK解算有时解算出来的结果有些骨骼可能不是很理想,所以骨骼设置是很有必要的。
Bone:需要应用设置的骨骼名称;
Rotation Stiffness/Position Stiffness:旋转刚度/位置刚度设置IK计算时对应用骨骼的影响程度,0表示骨骼可以自由移动,即完全影响,1表示骨骼完全锁定。
X/Y/Z:这些设置就是和Control控制器的Min/Max设置的效果是一样的,限制应用骨骼的在轴向上的变换范围,有三种模式,Free—骨骼的变换不受限制,此时Min/Max值不会生效,Limited—骨骼的变换将限制在Min到Max值之间,Locked—骨骼会被锁定,无法进行任何变换;
Use Preferred Angles:是否启用偏好角度,启用偏好角度会导致更多解算迭代,所以会消耗更多的计算;
Preferred Angles:用来强制使应用骨骼在解算时只在解剖学上的正确方向弯曲,不过我始终没有玩明白怎么用。
-
Excluded Bones:排除骨骼就是用来指定某根骨骼排除在解算链之外,不参与解算,主要用于来矫正姿势。
-
Settings:Setting是全局解算器设置;
Iterations:迭代次数,设置解算器的全局迭代次数,迭代次数越高,解算效果越好,同时也会越吃性能;
Mass Multiplier:质量倍乘器,值越大解算应用时全身骨骼看起来就会越僵硬,值越小看起来就会越软爬爬的;
Min Mass Multiplier:控制质量倍乘器的最小值;
Allow Stretch:这个设置没能摸索出有啥用;
Root Behavior:设置解算器的行为模式;
Start Solve from Input Pose:如果设置为true,解算器将在每一Tick重设,解算将从当前姿势开始,如果设置为false,解算器将从上一次解算的结果开始解算,输入的动画将倍忽略,一没弄明白有什么作用,默认都是勾选的,一般也不会动它。
7.解算器
在UE5.1中ControlRig提供了两种解算模式,Forwards Solve(向前解算)、Backwards Solve(向后解算)。
向前解算即Control控制器驱动骨骼,是应用范围最广的解算,是ControlRig的默认解算方式。
向后解算即使用骨骼驱动Control控制器,向后解算一般用于将动画序列烘培到Sequencer中的ControlRig上。
8.构造事件
ControlRig没有公开构造函数,但是为我们提供了一个构造事件—ConstructionEvent,需要我们手动创建节点。
9.样条线控制
样条线控制可以将一整条骨骼链作为一个整体进行控制,尤其是应用在触手,蛇、马尾辫等长条状的网格体上会很便捷。
创建样条线控制
创建样条线控制我们需要为一整条骨骼链的没一根骨骼创建Control控制器,然后将控制器的Translation添加进Spline From Points
节点的Points数组中:
Spline From Points节点的输入引脚说明参考虚幻引擎中的Control Rig样条线操控。
然后将样条线绘制出来:
编译之后就可以在预览视图看到绘制出来的样条线了。
需要注意的是Points必须传入四个以上的元素才能生成样条线。
应用样条线控制
绘制出的样条线还不能控制骨骼,还需要将样条线的控制应用到骨骼上。
使用Fit Chain Spline Curve节点可以将样条线控制应用到骨骼上,多选骨骼拖到蓝图中,在弹出菜单中选择Create Item Array,可以创建一个Rig Elemeny Key Array骨骼数据节点,传给Fit Chain Spline Curve节点的Items上,Spline连Spline From Points返回值,然后就可以使用样条线控制骨骼链了。
10.姿势缓存
姿势缓存是ControlRig提供的一个功能,可以将ControlRig中的动画的某一帧的姿势存储为一个姿势缓存变量,其实ControlRig的姿势缓存在功能效果上和姿势资产区别不大,但是姿势缓存有一个强大的能力,就是基于ControlRig强大的骨骼控制能力和程序控制能力,姿势缓存可以只单独缓存指定骨骼的姿势变换,应用姿势时也只应用这些骨骼的姿势变换,并且可以通过程序控制在运行时存储动画的任意时刻的姿势。
ControlRig框架专门提供了一个RigPose
类型来存储姿势缓存,并且提供GetPoseCache
节点来获取ControlRig控制下的动画姿势,最后通过ApplyPoseCache
节点来应用姿势缓存,甚至在调试时提供了DrawPoseCache
节点来绘制姿势缓存:
我们可以将控制变量StartCachePose和ApplyCachePose通过动画蓝图的ControlRig节点传递出去,我们就可以通过程序实时的缓存姿势并应用姿势了。
可以看看一个简单的效果:
11.ControlRig函数库
ControlRig函数库和蓝图函数库的功能是一样的,用来共享ControlRig的公共逻辑,和蓝图函数库不同的是,ControlRig的每一个资产都可以是一个函数库,我们只需要将函数设为Public就可以使这个函数在所有的ControlRig资产里使用了,但是为了方便管理一般都单独使用一个不绑定骨骼网格体的ControlRig资产来专门管理公共函数。