参考视频教程 从零开始的Lyra动画蓝图制作+解析
前期准备
- UE商城订阅
LyraStarterGame,并创建项目,需要UE5.0及以上 - 打开项目,过滤
动画序列,右键批量导出到一个文件夹 - 新建一个第三人称项目(c++或蓝图),如果是c++项目先生成
GameMode的蓝图类 - 蓝图中左上角编译处设置,
在成功时自动保存和勾选跳转到错误结点 - 将2导出的动画序列文件夹,拖到项目中,并选择
骨骼模型 - 添加插件
Animation Locomotion Library和Animation Warping(动画扭曲) - Lyra中找到
TurnYawAnimModifier,右键在文件夹视图中显示->回退到Animations目录->右键AnimModifiers->迁移到当前项目的Content下
基础移动
- 复制
BP_Character和BP_GameMode,将BP_GameMode->Pawn设置成BP_Character,世界模式设置为BP_GameMode,Project Setting->地图和模式->默认游戏模式->MyLyraGameMode BP_Character设置Auto Posses Player->Player 0,Player Starter设置自动接受输入->玩家0
此时,可以正常操作人物了,但是还没有动画
- 创建动画蓝图
ABP_LyraCharacter,添加基本动画状态


- 获取动画转换数据
Lyra使用Blueprint Thread Safe Update Animation来代替Event Graph->Update Animation,这样可以获得更高的性能

注意:后续函数都需要勾选线程安全

- 获取旋转

- 获取速度


- 获取加速度
- 先创建
获取角色运动组件的函数,返回值命名为ReturnValue,并勾选纯函数

这样就可以在属性存取中直接使用了
- 获取加速度


- 更新获取所有数据

此时完成动画转换逻辑,需要填补动画序列,Lyra中进行解耦
- 创建动画层接口
ALI_AnimationLayerInterface,定义需要的动画

此时没有具体实现
- 创建蓝图
ABP_ItemLayerBase实现ALI_AnimationLayerInterface接口,角色蓝图ABP_LyraCharacter也实现该接口
为了方便解耦,这里定义动画序列变量, 对应输出姿势

- 再创建子蓝图
ABP_PistolLayers继承ABP_ItemLayers,并在类默认值中指定具体的动画片段,实现绑定

- 最后将角色蓝图
ABP_LyraCharacter和ABP_PistolLayers链接到一起
打开角色蓝图类BP_LyraCharacter,新建动画层

此时就可以播放动画了,但是动画带位移,并在位移后回溯
- 设置根运动
过滤所有的MF Pistol的动画序列,右键->属性矩阵,勾选RootMotion下的启用根运动和强制根锁定

距离匹配
为了让运动的距离,和动画的距离保持一致,需要用到Locomotion Library插件(用于为动画生成距离曲线)
Start, Cycle, Stop都需要进行距离匹配
距离匹配在ABP_ItemLayerBase中实现
Start
替换为序列求值器, 显示时间即为动画显示的帧,需要动态指定,以匹配距离

Setup Start Anim
初始化显示时间为0

Update Start Anim
需要进行距离匹配,使用Advance Time by Distance Matching

参数说明:
Distance Traveled: 上一帧移动的距离
在动画蓝图ABP_LyraCharacter中获取

Distance Curve Name: 动画距离曲线的名称
需要使用Locomotion Library插件,先添加DistanceCurveModifier

删除原本的距离曲线

添加新的距离曲线,这里命名为Distance

在ABP_ItemLayersBase中将Distance Curve Name提取成变量,并赋值Distance
Cycle
因为移动是循环动画,动画时间无限长,所以根据显示时间进行距离匹配不太合理,需要基于速度进行匹配
这里使用的是动画播放器,并添加Update Cycle Anim函数即可

Update Cycle Anim
使用函数Set Playrate to Match Speed即可

参数说明:
Speed To Match: 上一帧的移动速度,基于Update Start Anim->Distance Traveled进行计算,也是在ABP_LyraCharacter中计算,并存取

Stop

Setup Stop Anim

Update Stop Anim
分两种情况,如果急停,需要距离匹配;否则直接加速结束动画。

急停情况,通过Predict Ground Movement Stop Location预测角色停止位置,然后用Distance Match To Target来让动画匹配停止点

停止情况,直接加速播放动画即可

曲线压缩设置
此时游戏运行,输出日志会有很多黄色警告,说未使用统一索引编码
先打开一个动画,找到曲线压缩设置,并索引过去,然后复制一份,重命名并设置为UniformIndexableAnimCurveCompressionSettings



然后全选所有MF的动画序列,属性矩阵修改,设置Compression->曲线压缩设置都为UniformIndexableAnimCurveCompressionSettings,Ctrl+S保存,然后回到UniformIndexableAnimCurveCompressionSettings中点击压缩即可
步幅适配
游戏人物的速度不是一成不变的,速度快时需要步幅变大,速度小时需要步幅减小;
在动画蓝图ABP_ItemLayersBase中做修改
-
Start

-
Cycle
和Start相同

同步组
为了保持动画切换时,左右脚能够保持一致,也需要用到Locomotion Library插件
- 设置
Start和Cycle的动画播放器/动画求值器为同步组

- 然后打开
Start和Cycle使用的动画序列,添加SyncMarkerAnimModifier修饰符并应用


8向移动
四向移动
获取速度的方向信息
- 在
ABP_LyraCharacter中创建函数Update Cardinal Direction From Velocity,类别为方向
- 计算速度角度

- 根据速度的方向角,设置方向的枚举
- 创建
蓝图->枚举,EAnimCardinalDirections

ABP_LyraCharacter创建一个函数Select Cardinal Direction From Angle(纯函数+线程安全),类别为工具函数
设置输入,最后一个类型是刚建的枚举




向前向后的Dead Zone乘上2,是为了让玩家更容易进入向前和向后的状态




- 回到
Update Cardinal Direction From Velocity函数中,调用Select Cardinal Direction from Angle
需要参数:
Dead Zone: 默认值10,提升为变量Dead Zone
Use Current Direction: 取决于上一帧是否有速度,有则使用,无则不用
在函数Update Velocity中计算得到


- 添加到
Blueprint Thread Safe Update Animation中

- 创建结构来代表所有动画,
蓝图->结构,SAnimCardinalDirections

Start,Cycle,Stop需要方向适配
7.1 Start

Setup Start Anim

7.2 Cycle
Update Cycle Anim


7.3 Stop

Setup Stop Anim

- 打开
ABP_PistolLayers
添加对应动画

- 给其他的
Start和Cycle动画添加同步组标记
此时运行存在问题
10. 打开Character Movement->旋转朝向移动取消勾选,类默认值->用控制器控制Yaw勾选
Left Start动画起步会滑步,这是由于该动画起步前摇太长,需要处理,截取前五帧即可
朝向扭曲,实现八向
- 前面完成了4向移动,后面通过添加朝向扭曲,实现八向
12.1 ABP_ItemLayersBase->FullBody_Start


12.2 FullBody_Cycle 与上同理
朝向扭曲在前,跨步扭曲在后
回转运动
向左启动时,突然又向右启动,这时Start其实只切换了一次,所以会出现滑步
回转动画本身有两部分:当前方向的急停动画+反方向的加速动画
- 先修改
ABP_LyraCharacter中的动画状态机

24.cnblogs.com/blog/1537983/202401/1537983-20240122172750777-1595182968.png)
Pivot Sources->Pivot
只要加速度和速度不同向,则需要回转

Pivot->Cycle
在回转动画播放到匀速运动时通知切换,动画中添加通知(第4节),创建蓝图类继承自AnimNotifyState,命名为ANS_ToLocomotion
切换状态

ALI_AnimitionLayerInterce添加FullBody_Pivot动画层,在ABP_LyraCharacter中返回这个动画层姿势

- 在
ABP_ItemLayersBase实现Full Body Pivot层接口,创建状态机
之所以创建状态机,而不是单个动画,原因:在Pivot过程中又反向运动,会导致无法重新进入该状态,即回转运动只能进行一次,没法叠加执行


3.1. PivotA状态

- 绑定函数
Setup Pivot Anim
- 需要根据
加速度方向决定用哪个回转动画
在ABP_CharacterBase中创建函数Update Cardinal Direction From Acceleration

这里不需要参数Use Current Direction和Current Direction,只有在判断前后移动时需要扩大Dead Zone死区
由于加速度和当前速度方向不一致,所以加速度的方向应该取反,创建纯函数Get Oppisite Direction

最后添加到Brintprint Thread Safe Update Animation中

- 回到
ABP_ItemLayersBase,根据Direction From Acceleration决定使用序列

Update Pivot Anim进行距离匹配

2.1. Stop阶段距离匹配,利用Predict Ground Movement (Pivot) Location 和 Distance Match To Target

2.2. Start阶段距离匹配,使用Advance Time By Distance Matching

24.cnblogs.com/blog/1537983/202401/1537983-20240122174520717-2018213814.png)
- 将
跨步扭曲和朝向扭曲加入进来

3.2 Pivot B状态
复制一份Pivot A,然后考虑到Pivot A和Pivot B的转换条件,应该是加速度方向改变
所以需要记录上一帧的加速度方向,在Pivot A->Setup Pivot Anim中补充代码

然后确定状态转换条件


ABP_PistolLayers中设置动画,并添加动画通知,添加同步标记


Pivot A和Pivot B设置同步组
在ABP_ItemLayersBase中序列求值器->细节设置

- 解决垂直移动问题
目前回转运动只能解决一条直线上的运动,如果在左右回转时,立马施加垂直向前的运动,则会边回转动画边前向移动
在ABP_LyraCharacter中创建函数Update Is Moving Perpendicular to Initial Pivot,用于判断当前运动方向和初始运动方向是否一致
- 初始运动方向获取
在动画状态机->Pivot输出姿势->变为相关时->创建绑定, 命名为Setup Pivot State
变为相关时,记录一次当前的速度方向,记为Pivot Start Direction From Velocity

- 判断是否垂直,结果记为
Is Moving Perpendicular to Initial Pivot
当Pivot Start Direction是前后,而当前速度``不是前后则认为垂直;左右同理

- 将
Update Is Moving Perpendicular to Initial Pivot添加到Blueprint Thread Safe Update Animation中

- 在
ABP_ItemLayersBase中补充Pivot A->Pivot B的转换条件,即当垂直时不要过渡到回转,而直接过渡到Cycle

只有在动画的后半段通知后,才会过渡到Cycle动画,还是存中问题
- 提前过渡动画到
Cycle
增加一个转换条件,设置原转换条件优先级为2,值小先检测

垂直移动了,则直接转换到Cycle

没有垂直移动,才根据动画通知转换
第一次Start右走,突然变换方向朝前,人物会往右看/右斜,原因是向前移动时,还在播放Start动画,没有及时转化到Cycle
- 添加转换条件,修改原条件优先顺序为2

10.1 在Start输出姿势,绑定函数Setup Start Anim,存储初始移动方向


10.2 如果当前方向和初始方向不一致,则提前转换到Cycle

原地转身 - 根旋转与胶囊旋转分离
让人物不随着鼠标而旋转,原理是:让根骨骼和鼠标旋转相反,这样胶囊体在旋转而骨骼模型保持静止
AnimGrgph中添加旋转根骨骼, 创建变量Root Yaw Offset

- 在
Update Rotation Data中获取两帧之间的旋转量Delta Rotation


-
创建函数
Update Root Yaw Offset- 创建枚举
EAnimRootYawOffsetMode
Accumulate逐渐累加Root旋转,与鼠标旋转抵消,用于Idle状态HoldOn保持现在的Root旋转,用于Start和StopBlendOut逐渐减小Root旋转,让鼠标能够完全控制人物移动方向

创建变量Root Yaw Offset Mode
- 创建函数
Set Root Yaw Offset



限制范围是为了避免:镜头正对着人物前方,然后人物
Start时动画突兀
3. 分支处理不同情况

Accumulate

HoldOn直接忽略,不作任何处理即可BlendOut插值到0

- 设置默认状态为
BlendOut,大部分时候都是鼠标完全控制旋转

- 创建枚举
-
设置
Acculate状态,创建函数Update Idle State

-
设置
HoldOn状态,创建Update Start State函数绑定到Start动画的更新时


- 相同操作,用于
Stop动画,函数Update Stop State

- 添加到
Blueprint Thread Safe Update Animation中,注意Is First Update要放后面

- 需要更改
Update Cardinal Direction From Velocity
视角转,但是人物移动方向没有转

这是由于计算World Rotation是用胶囊体旋转(视角旋转始终和胶囊体旋转一致),但是播放动画却是基于网格体朝向的,所以会出现人物要向前走,但实际动画是播放网格体朝向的向前走,出现不一致
所以在计算Local Velocity Angle时需要减去Root Yaw Root


人物动画和视角朝向不一致

这是由于朝向扭曲用的还是Local Velocity Angle,需要更改为Local Velocity Angle with Offset,涉及Start, Cycle, Pivot

视角与人物朝向偏差太大时,会先播放朝后启动动画,再转身Cycle,应该直接切换到Cycle

增加Start->Cycle转换条件,将优先级设置为1,混合时长设为1,其他两个增加1,当根偏移超过60度直接转换到Cycle

同时为了保证转身更自然,转换条件也设置同步组为Locomotion,会先走两步,脚部标记有衔接的时候才会过渡过去

混合有点突兀,把Start->Cycle的过渡时间设置为1
原地转身 - 原地转身
根旋转偏移限制在[-120,120]之间,超过了就会鼠标带动人物模型旋转
如果超过了偏移限制,则播放原地转身
- 修改
ABP_ItemLayerBase中的FullBody Idle实现,将序列播放器先剪切



- 创建
原地转身状态机,因为原地转身动画具有很长的后摇,转身过程中,如果视角又转动很大,则需要重新进入原地转身状态,所以这里也需要两个状态相互转换,所有转换都选择惯性化混合

-
Idle->Turn In Place Rotation&Turn In Place Recovery->Turn In Place Rotation

-
Turn In Place Recovery->Idle

-
Turn In Place Rotation->Turn In Place Recovery
根据动画曲线判断,Lyra中找到TurnYawAnimModifier,右键在文件夹视图中显示->回退到Animations目录->右键AnimModifiers->迁移到当前项目的Content下


-
创建
Turn Left和Turn Right动画序列 -
添加
Turn In Place Rotation动画播放器,添加变得相关时函数Setup Turn In Place Rotation


添加更新时函数Update Turn In Place Rotation

- 添加
Turn In Place Recovery动画播放器,添加变得相关时函数Setup Turn In Place Recovery
绑定初始位置为4的上下文差量时间

-
Turn In pLace Rotation->Setup Turn In Place Rotation需要根据旋转角度变化来决定是Turn Left还是Turn Right- 给
Turn In Place Rotation的输出姿势,添加变得相关时绑定Setup Turn In Place Rotation State函数

- 选择动画序列

- 给
-
Turn In Place Recovery动画选择同6
创建Setup Turn In Place Recovery

-
在
ABP_PistolLayers中设置动画

原地转身动画循环播放
原因是根旋转偏移并没有改变,所以会一直满足转换条件Idle->Turn In Place Rotation(偏移大于120度)

- 新建函数
Process Turn Curve Value



Update Idle State中调用Process Turn Curve Value

瞄准偏移
- 创建瞄准偏移
动画->瞄准偏移,命名为MF_AO_Pistol


- 过滤所有的
MF Pistol AO动画,属性矩阵修改为AdditiveSettings->网格体空间叠加
基础姿势动画为MF_Pistol_Idle_ADS_AO_CC

局部空间 和 网格体空间 叠加对比

MF_AO_Pistol中,左侧设置预览基础姿势,按住ctrl预览

ALI_AnimLayerInterface中添加AimOffset层,设置输入参数

ABP_LyraCharacter->AnimGraph中
5.1 将接口添加到AnimGraph中

5.2 接口需要输入的参数,需要安全更新,创建安全更新函数Update Aim Offset Data

5.3 添加到Blueprint Thread Safe Update Animation的末尾

-
ABP_ItemLayersBase中实现AimOffset动画,将Blend Space公开引脚并提取成变量,在ABP_PistolLayers中赋值

-
回到
AimOffset实现层,给接口函数绑定参数

跳跃着陆
-
ABP_LyraCharacter中的Locomotion_SM,添加状态

-
获取动画转换数据
Update Character State Data, 添加到Blueprint Thread Safe Update Animation中




- 更新
跳到顶点的时间,Update Jum Fall Data


- 计算
掉落地面距离,(不要放到线程安全中,线程安全中只做更新,不做计算),Get Ground Distance,在事件蓝图更新函数中调用


-
添加动画转换条件
Jump Sources->Jump Selector: 直接勾选Jump Selector:勾选Jump Selector->Jump Start:Is JumpingJump Selector->Jump Apex:Is FallingJump Start->Jump Start Loop: 直接勾选基于序列...Jump Start Loop->Jump Apex:Jump Apex Time < 0.4Jump Apex->Fall Loop:勾选基于序列...Fall Loop->Fall Land:Ground Distance < 200Fall Land->End In Air&End In Air Source->End In Air:Is On Ground, 任何条约状态都可能直接接触地面End In Air:勾选End In Air->Cycle Alias:ToStart共享规则,优先级1End In Air->Idle Alias:勾选, 优先级2
-
动画部分
ALI_AnimLayerInterface添加动画层

-
ABP_LyraCharacter中将所有动画层->姿态输出 -
ABP_ItemLayerBase
- 创建
动画序列变量

-
将
动画序列变量通过序列播放器输出姿势, 涉及Fall Loop,Jump Apex,Jump Start Loop,Jump Start -
Fall Land使用序列求值器来距离匹配

变为相关时创建绑定函数Setup Fall Land Anim
更新时创建绑定函数Update Fall Land Anim
生成动画距离曲线

-
修改动画资源,过滤
Jump动画序列,属性矩阵操作
启动根运动,强制根锁定, 曲线压缩设置->Uniform...->打开Uniform...文件点击压缩
ABP_Pistol动画赋值
浙公网安备 33010602011771号