Advanced Locomotion System V3是虚幻商城的一款第三方插件。它相比UE4的基础走跑跳表现,实现了更多动作游戏里常用的运动特性,虽然价格定价不菲,依然备受关注。笔者试用了这款插件,确实很强大,适合作为基础插件来做FPS,ACT游戏,因此简单学习分析下这款插件。
插件特点:
- 具备动作游戏的常见特性,支持多种移动模式,步行,奔跑,冲刺,下蹲,Ragdoll
- 运动细节做得很到位,包括原地转身,奔跑急停转向,移动中身体倾斜,落地腿部缓冲,头部Aim Offset(AO),腿部IK
- 支持网络同步
- 纯蓝图实现,适合策划、开发学习应用
动画树分析
插件用了两颗动画树,Mannequin_AnimBP和Mannequin_IK_AnimBP,前者挂载在人物Blueprint上,用来处理人物主体动画;后者挂载在人物的Skeletal Mesh上,用作动画后处理来实现脚部IK动画。Mannequin_AnimBP动画树大体分为地面动作、空中动作两部分的处理。其中地面Locomotion的表现需求是最多的。
地面Locomotion
地面Locomotion算是动画树最复杂的状态机了,可以简单分为3层:
可以看到第一层状态机只是对第二层状态机输出动画做了一个呼吸动画的叠加。第二层状态机输出的Idle动画其实是静止Pose,在这一层才统一叠加上呼吸动画。
第二层状态机只定义了几种Locomotion状态的过渡逻辑,可以看到Locomotion有走停转站四种状态。
第三层状态机分别是走停转站的动画实现,其中走(Moving)的实现是最为复杂的。可以看到状态机有很多动画分支,全部是用BlendSpace,以Direction,Gait Value作为输入值来输出移动动画的。在此简单解释Gait Value,插件设计该变量将Walk/Run/Sprint三类状态的速度值映射为[1,3],动画机内只关注跟Walk/Run/Sprint状态相关的Gait Value,无须关注具体速度值。
人物有两种转身模式,一种是根据人物速度方向转身(Velocity Direction Mode),一种是根据镜头方向转身(Looking Direction Mode),这两种转身模式也造就了两种移动模式,通常适用于在ACT/FPS游戏里切换格斗/射击和自由移动两种移动模式。转身模式通过变量ALS_RotationMode控制。
八方向移动
以人物速度方向转身的移动动画比较简单,基本只需要对朝前的Walk/Run/Sprint动画做BlendSpace融合即可。以镜头方向转身的移动动画则要做八方向移动动画,简单的八方向动画(前/后/左/右/左前/左后/右前/右后方向移动)其实用一个BlendSpace就可以实现,但插件做了更复杂的八方向动画。左右移动进一步细分出了左移姿势前进,左移姿势后退,右移姿势前进,右移姿势后退等四个动作,用了两个BlendSpace来实现这种八方向移动。
状态机根据人物移动方向切换使用两个BlendSpace,当镜头与速度方向夹角处于[-90,90]范围内用前进BlendSpace,否则用后退BlendSpace。上图红框部分是两个BlendSpace实际采用区域。
该状态机还有个分支用于输出下蹲移动动作,移动速度是恒定的,所以用了1D BlendSpace做输出,比较简单,不展开细说。
另外整个状态机很多分支都有RF变量身影,该变量意思是移动动画是以左脚还是右脚在前,因此以RF变量可以分出了两种BlendSpace。
移动倾斜
根据Lean Gounded X/Lean Gounded Y变量可以BlendSpace出一个身体向左右,前后倾斜一定角度的Pose,将其与移动动画做融合,就能表现出角色倾斜奔跑的效果。这个融合主要是为了体现角色速度感。角色速度,每帧速度角度变化值决定左右倾斜度,每帧角色速度变化值决定前后倾斜度。
正常停止移动动画
从Moving到NotMoving有两种过渡,一种是正常停止移动的Stop动画,一种是奔跑急停的Pivot动画。Stop动画细分了多种状态下的Stop动画,这里只看普通跑动下的Stop动画。
可以看到Stop动画是由2个BlendSpace输出的,根据左脚在前,还是右脚在前,决定使用哪一个BlendSpace。两个BlendSpace都接收Feet Position X和Feet Position Y作为输入。
Feet Position X:表示Foot Direction,Foot Direction的范围是[-90,90],表示移动方向。
Feet Position Y:表示Foot Position。Foot Position的范围为[-1,1],其中左脚迈到最前时为-1,右脚迈到最前时为1,两腿刚好交叉时为0。看上图可知当Foot Position>0时,即右脚迈在前面时,用ALS_N_Stop_RF BlendSpace,否则用ALS_N_Stop_LF BlendSpace。
Feet Position X、Feet Position Y两个变量值的更新很巧妙:所有的移动Animation Sequence上,都添加了名为FootDirection,FootPosition的Curve,记录了每一帧的脚步位置和移动方向。当进入Stop状态时,通过GetCurveValue接口获取FootDirection,FootPosition的Curve值,再设置给Feet Position X、Feet Position Y。
Stop的BlendSpace基本就是采样了人物在左移,右移,前行3个方向下,左脚或右脚在前的脚步回收动画,可以让人物在停止移动时,有一个明显收住脚部,回撤站立的表现,增强人物运动真实感。
奔跑急停动画
增加奔跑急停的Pivot动画用于人物跑动中大幅度转向的过渡,进一步强化运动速度感。判断移动输入方向与人物移动方向的Yaw角度大于100(基本就是反向移动)时,人物在地面上且速度处于一定范围内,即进入Pivot过渡。
原地转身动画
插件没有在AnimGraph里播放原地转身动画,而是在EventGraph里调用Play Montage接口播放TurnInPlace的Montage动画,在AnimGraph里添加TurnInPlace Slot输出转身动画。
看下动画树的EventGraph里调用转身动画的接口:
决定是否播放转身动画主要靠以下3个变量:
Turning In Place:当前是否正在转身
Turning Right:当前是否正在向右侧转身
Aim Yaw Delta:当前帧镜头朝向与人物朝向的Yaw角变化值
基本逻辑是转动镜头Yaw角大于90度转身或180度转身阈值时,且当前没有在转身,则播放转身动画;当前已在转身中,只可以打断往相反方向转身。这样避免持续往一侧转动镜头时,播转身动画过程中,出现打断动画,重头播转身动画的情况。
转身动画只有腿部动作,不带人物转向,人物转向通过TurnInPlace_AnimNotifyState动画事件每帧设置。
每帧设置转向用一个EaseInOut曲线来控制,获取上一帧跟当前帧的曲线差值,即为当前帧人物转向Yaw角偏移值。
最后,TurnInPlace_AnimNotifyState动画事件还需每帧判断当前人物是否有移动,移动则打断转身动画。
空中动作
起跳动作
起跳动作用了基础起跳动作,融合BlendSpace,让起跳呈一定程度的Lean倾斜,表现出人物往对应方向起跳的感觉。其中Lean In Air值由跳跃Z轴速度和移动速度决定,Direction为移动速度方向。
下落动作
下落动作有两个阶段动作,一开始是正常腾空下落,随着下降速度变大,逐渐Blend为手脚胡乱摆动的动作,用一个EaseInOut曲线控制Blend速度。
下落动作同样融合BlendSapce做Lean倾斜,并且会计算着地时机,在快着地前融合一个人物手臂上扬再下落的动作,强化落地冲击感。该融合靠Land Prediction Alpha变量控制。该变量在人物下落过程中,每帧以脚部为圆心做球形检测,得出球形与地面的相交最短距离,归一化到[0,1]的范围值来做动画融合。
落地动画
人物跳跃着地后播放一个着地过渡动画,当然如果在此期间人物移动则打断过渡动画。
头部AO
头部AO比较简单,在MainStateMachine动画输出后,根据人物朝向和摄像机朝向计算出AimOffset值,做一个[-180,180] Yaw角,[-90,90] Pitch角范围的AO处理。
Ragdoll系统
人物死亡后会切换为Ragdoll状态,动画状态机比较简单,根据人物是否处于奔跑,播放手脚乱摆或者身体蜷缩的动画。Ragdoll系统更多在于蓝图里的逻辑处理。
切换Ragdoll状态
进入Ragdoll状态,做以下处理:
- 角色骨骼运动改由Skeletal Mesh,pelvis节点下的骨骼自行进行模拟物理
- 角色MovementMode切为None,让MovementComponents不再更新角色位置逻辑
- 开启角色网格碰撞,禁用角色胶囊体碰撞
每帧Update做以下处理:
- 判断人物Z轴速度小于-4000时,关闭重力模拟,防止下落速度过快导致刚体穿透
- 更新Ragdoll的速度,更新pelvis bone的位置和旋转
- 更新Actor的位置和旋转。因为Ragdoll状态下MovementComponent不再更新角色位置逻辑了,得根据pelvis bone的位置和旋转计算并设置Actor的位置和旋转,否则摄像机就不能正确跟随角色Ragdoll了。
这里还要注意一些细节,不能直接以Pelvis Bone来设置Actor位置,如果直接设置,当角色Ragdoll倒地后,胶囊体其实有一半嵌入了地面。当退出Ragdoll时,胶囊体会瞬间弹出地面,导致人物抖动。解决办法是从Pelvis Bone往Z轴负方向(地面)做SapsuleHalfHeight距离的射线检测,SapsuleHalfHeight减去射线碰撞距离得出Z轴补偿值,再取Pelvis Bone位置作为Actor位置,目的就是保证胶囊体不嵌入地面。
角色胶囊体始终只旋转Yaw角,Roll、Pitch角为0,因此Actor旋转只取Pelvis旋转的Yaw角,这里注意角色正面/背面倒地后,起身的朝向刚好是相反的,通过判断Pelvis的Roll角是否大于0,翻转Yaw角180度即可。
退出Ragdoll状态
退出Ragdoll则要恢复进入Ragdoll时所作的改动,并且播放起身动画:
- 取消骨骼模拟物理
- 视乎角色是在地面还是空中,将Movement Mode切换为Walking/Falling
- 开启角色胶囊体碰撞,禁用角色网格碰撞
- 设置角色Movement当前速度为Ragdoll速度
- 调用Anim Instance的Save Pose Snapshot接口,给当前角色动画保存快照,在动画机的退出Ragdoll状态里,输出这个快照
- 判断角色面部朝上/朝下,播放对应起身动画,角色以快照Pose开始起身站立
腿部IK
插件的腿部IK实现也挺不错,单独用了一个后处理动画树来实现,跟前面其他功能解耦,实现逻辑很清晰,也设计了一些变量来控制调整腿部IK效果。
插件的腿部IK实现了两个基本功能:
- 左右腿自适应不同地面高度。站立在凹凸不平的地表上,左右腿能贴着地面站立,避免出现腿部悬空问题。
- 左右脚掌自适应不同地面角度。站立在斜坡上,人物脚掌要转至与斜坡保持平行,紧贴地表。
简单介绍下IK(Inverse Kinematics,逆向运动学)原理,它是与FK(Forawrd kinematics,正向运动学)
截然相反的一种骨骼定位技术。FK通过自顶向下确定每根骨骼的位置和旋转,确定整个骨架形态。IK则是给某根骨骼指定位置旋转,并自动计算其父骨骼的位置旋转,从而确定骨架形态。
IK计算需要两个参数,Joint Target和Effector。简单理解,Effector其实就是我们想要修改的骨骼的目标点,由此引发的其父骨骼到Base骨骼之间的位置变动,则由IK自动计算出来。已知Base骨骼位置不变,如果只有Effector参数,IK计算出来的骨骼位置,在三维空间是有无数解的。因此还需要Joint Target参数,它相当于是一个参考点,让IK计算得出的各骨骼位置尽量靠近这个参考点。
UE4的Anim Graph提供了Two Bone IK节点用于处理IK,需要设置进行IK的目标骨骼、Effector、Joint Target。
- 目标骨骼自然是两条腿部骨骼:foot_l,foot_r。
- Effector以两条腿部IK骨骼作为参考:ik_foot_l,ik_foot_r,这是官方骨架本身自带的IK骨骼。除了腿部IK骨骼,官方骨架还自带了手部IK骨骼,ik_hand_l,ik_hand_r。IK骨骼只是用于定位IK目标点的,并没有绑定动画。
- 由于脚部屈伸时,膝盖肯定是朝前弯曲的,所以插件给Skeleton的左右脚各添加了从thigh(大腿)到calf(小腿肚)的虚拟骨骼:VB thigh_l_calf_l,VB thigh_r_calf_r,并将骨骼设置在膝盖正前方30个单位的位置,作为Joint Target。
下图就是Two Bone IK节点的对应设置:
游戏里随着人物的运动,腿部IK Effector是一直在变的。因此需要每帧计算Effector值,动画蓝图的计算过程如下:
- 首先双腿分别向Z轴负方向(地面)做射线检测,得出双腿距离地面距离,看哪条腿距离地面更远,将其距离值作为Pelvis Offset,把Pelvis(盆骨)骨骼向下移动Pelvis Offset单位,实际上也就是将整体人物骨骼下移,这样靠下面的那条腿就站立在地面上了
- 接着计算两条腿的Effector坐标,从而让腿抬到地面位置。双腿距离地面的距离,分别设为两根IK骨骼的Z轴值,即可得出两条腿Effector点的坐标
- 接着计算两条腿的Effector旋转,从而让脚掌旋转到适合角度,紧贴地面站立。根据射线与地面的碰撞点法线,可计算出碰撞地面的朝向,只取地面朝向的Roll角,Pitch角分量设给IK骨骼(Yaw角不用调整,让脚掌始终朝前)。
得出以上关键数值后,Anim Graph里通过Transform(Modify)Bone节点修改各个关键骨骼数据,最后再通过Two Bone IK节点做IK计算:
这里还有个细节,每帧计算得出的数值与上一帧的数值进行插值后,再设置给骨骼,不做插值的结果就是人物上下楼梯会明显抖动,就像下图一样:
结语
插件本身的功能已经挺丰富了,拿来做简单的FPS、ACT游戏已经足够。插件本身的设计架构也比较清晰合理,适合在此基础上做重构,增加诸如持枪、匍匐等动作。就算不直接使用插件,插件诸如原地转身、脚部IK的实现也是值得参考借鉴的。