在使用UE5游戏开发过程中,会经常使用到动画,只要涉及到动画就绕不开根运动动画,本文就来挖掘一下UE5中根运动的实现原理。
一、什么是根运动(RootMotion)?
根运动是基于角色骨架中根骨骼的动画驱动的运动。这意味着角色的整体位置(不仅仅是其四肢或身体部分)可以在动画过程中改变。
二、为什么需要根运动?
1.为了解决动画和位移更加完美的匹配。
动画艺术家会在一个攻击动作中加入先快后慢再快的动画位移,从显得动作更加的自然和符合常识。而如果没有根运动则可能位移和动画并不能很好的匹配导致表现效果较差,例如出现滑步效果。
2.为了解决人物动画移动过程中与场景碰撞交互问题。
没有根运动时,播放一个具有位移的动画,角色的胶囊体和网格体分离,在动画播放结束时,角色网格体将被拉回胶囊体的位置
但不仅仅是被拉回的问题,因为胶囊体和网格体分离,产生实际碰撞的胶囊体并未移动,若前方存在一面墙,就会出现角色网格体穿过这面墙的问题。
有根运动时,角色的胶囊体会随着动画一同移动。
就能在移动过程中保证角色能够被沿途的物理物体阻挡,避免产生不合理的穿墙问题同时解决动画结束后角色被拉回的表现。
三、在UE5中怎么使用根运动?
- 在所需动画资产详情中勾选EnableRootMotion。
- 在角色所使用的动画蓝图中设置RootMotionMode为RootMotionFromMontagesOnly,表示根运动只来源于Montage动画。
四、UE5根运动的基础原理
- 首先说说我们正常的移动,输入源是玩家按下键盘的上下左右,移动组件再获取到玩家的输入数据,计算出场景中的加速度,最终将移动应用于角色。
- 而根运动说来也简单,输入源改为了动画资源中根骨骼的位移信息,移动组件获取到解压后的输入数据,从而控制移动。
五、在UE5中根运动是如何接管人物移动的?(源码解析)
Ⅰ.赋值当前根运动
- 首先从最常见的蓝图入口开始,我们常常会在角色蓝图中播放某个带根运动的Montage动画,例如:攻击技能
- 从蓝图结点一路进来发现其主要是通过角色蓝图上骨架网格体组件获得其配置的动画实例
- 接下来,我们关心AnimInstance->Montage_Play这个方法
- 接着进入Montage_PlayInternal
- 发现如果播放的是一个含有根运动的montage,则将刚创建的AnimMontageInstance实例赋值给RootMontionMontageInstance这个字段,我们跟踪一下这个RootMotionMontageInstance这个字段
Ⅱ.解包根运动数据
- 这时我们在AnimInstance.cpp中搜寻该字段,发现在Montage_Advance中获取后判断是否需要解压根运动参数
- Montage_Advance是每帧都在调用的,如下图,其在对RootMotionParams进行赋值,而数据是通过引用赋予了ExtractedRootMotion字段中,接着跟踪一下这个字段的使用情况。
- 而在AnimInstance.cpp里封装了一个方法可以获取该ExtractedRootMotion转换后的数据,也就是根据进度值(Alpha)获取当前累积的根运动。
Ⅲ.根运动数据使用
- 跟踪AnimInstance.cpp中ConsumeExtractedRootMotion方法的使用,发现其在SkeletalMeshComponent.cpp中的ConsumeRootMotion_Internal方法调用。
- 继续往上寻找,即可发现ConsmeRootMotion方法,可以从Mesh中获得当前待处理的根运动参数
- 再继续往上寻找,果然来到了最熟悉的CharacterMovementComponent.cpp中,存在两处调用,分别是在TickCharacterPose和TickComponent中两处调用,并且看起来一摸一样,都累积给RootMotionParams字段了
- TickComponent中
- TickCharacterPose中
- 在CharacterMovementComponent.cpp的PerformMovement方法进行,先调用TickCharacterPose更新根运动数据
- 再将RootMotion的数据转为世界坐标,并赋值给CharacterComponent的Velocity字段用于更新物理
六、总结
最后,在UE5游戏开发中,根运动经常会被应用于技能等较为特殊的动作中便于动作更加协调和自然,同时最重要的是他可以避免在技能释放过程中出现严重穿墙的行为。