AdvanceLocomotionSystem总结

前言

本文再次对ALS进行一个总结, 重点看动画状态机部分, 数据结构和计算部分不重点关注

本文含有大量动图, 加载比较慢

image-20211009152453736

骨骼分层与动画叠加

ALS的一大特色就是基于基础动作及Pose,通过叠加、混合等方式实现基础动作的复用和灵活的扩展, 同时用骨骼分层结合大量曲线来控制不同身体部位的混合情况

一般的动画叠加

image-20211009150617724

image-20211009151142804

上面就是多数情况我们使用的动画叠加方式

录制_2021_09_30_14_30_38_692 + image-20211009150933899 = 录制_2021_10_09_09_06_45_546

如果按照上面所示简单暴力的叠加, 那么结果很奇葩, 下面我们看一下ALS的实现方案

MakeDynamicAdditive

ALS并没有大量的把动画序列改成Additive模式,而是程序化的生成叠加数据, 这里保存了局部空间和模型空间的2个叠加数据缓存

image-20211008165102735

image-20211008165120365

骨骼分层

image-20211008165148667

image-20211008165151805

以左手臂举例
通过曲线Layering_Arm_L来选择是使用默认动画还是使用叠加动画(ALS里这条曲线非0即1)
再通过变量ArmLAdd(从曲线获取)来选择是使用单帧动作还是叠加上基础运动动画
上图两个几乎完全一样的节点区别是使用局部/模型旋转

翻译成人话就是如下

image-20211009151343926

看一下效果

录制_2021_10_09_09_32_24_117


当然, 如果按照传统的方式也能做出来, 只不过不论是逻辑还是资源方面都没啥优势

image-20211009151435478

再举个例

image-20211008165304636+录制_2021_09_30_14_30_38_692 =录制_2021_09_30_14_31_49_884

上图所展示的是基础单帧Pose + 走路动作 = 最后的动作


屏幕捕获_2021_09_30_14_37_09_399 + 录制_2021_09_30_14_30_38_692 =

录制_2021_09_30_14_37_47_252

上图所展示的是双手持手枪单帧Pose + 走路动作 = 最后的动作
什么变化?
我们看到手臂的颜色是白色的,这里代表着手臂使用了另外的方式参与了全身动画的实现

颜色说明:
红色:完全叠加
白色:使用单帧动画
黑色:不使用分层动画(即使用基础层的动画,这里暂时没有)


屏幕捕获_2021_09_30_15_25_01_128 + 录制_2021_09_30_14_30_38_692 = 录制_2021_09_30_15_16_40_582

上面所展示的是双手持步枪单帧Pose + 走路动作 = 最后的动作
什么变化?
左手是粉色的,意味着左手叠加了一部分基础动作


下面我们来对比一下叠加与否的效果

录制_2021_09_30_15_17_32_569

手臂使用单帧Pose动作,其余叠加上基础层的运动数据


录制_2021_09_30_15_18_50_693

右手叠加上基础层的运动数据


录制_2021_09_30_15_16_40_582

ALS的方案,右手稍微叠加了一点运动数据


录制_2021_09_30_15_44_16_235

测试一下蒙太奇的播放, ALS本身没有换弹动作,借用其他项目的动作测试(动作本身不匹配)

可以看到左手可以正常播放蒙太奇动画,但是无法正确保持Aim角度,这是因为ALS的ArmSlot在Aim处理的外层,这是问题


其他动画叠加测试

  • Epic初始射击动画包

录制_2021_10_09_13_40_24_582

  • Mage动画包

录制_2021_10_09_14_53_31_277

  • TwoHandSword动画包

录制_2021_10_09_14_53_54_271

ALS没有单独的上半身分层, 而是拆开了左右手臂, 有些时候反而不太方便, 如果有需要可以单独加一个上半身分层

另外Rootmotion动画播放时需要视情况在蒙太奇动画里设置相应的曲线, 可以参考ALS的Roll动画

分层状态机

image-20211008170135584

  • 一张图概括所有状态机分层

image-20211008170417614

Locomotion Cycles层

实现了8方向的移动, 以及移动Lean效果的叠加

录制_2021_10_08_09_40_46_621

关注点

  • 六变形的状态机
  • RB和LB实际上是过渡节点, 目的是完成pelvis的转向
  • ALS的一个小技巧: 45度的移动在刚开始使用了两个方向的混合动作, 但是逐步的会单独使用F/B的动画结合角色的旋转来实现

缺陷

录制_2021_10_08_09_53_55_267

如上图, LF到B的过程, 因为没有单独的pelvis翻转动画, 导致腿部有明显的穿帮现象, 同样的也会出现在RF到B的过程

Locomotion Detail层

实现起步的动画叠加效果

image-20211008170713506

录制_2021_10_08_10_11_58_328

ALS没有起步动作, 即通过混合完成Idle->Run的过程, Walk -> Run 的过渡中叠加了一个上图所示的动作

对比一下叠加前后的区别

录制_2021_10_08_10_23_26_691

录制_2021_10_08_10_23_55_919

Locomotion States层

实现停步和循环转身动画, 这里我们重点讲一下停步

image-20211008170831251

实现停步比较复杂, 需要关注下面几个技术点

  • 脚步曲线
  • IK锁脚
  • 停步动画

脚步曲线

image-20211008170903029

ALS通过曲线设定是否有脚踩到地面, 或者哪只脚更靠近地面
有些简单的实现方案会使用动画通知来设定当前是哪只脚落地, 但并没有考虑两脚都腾空的情况

IK锁脚

image-20211008170930765

IK锁脚需要根据脚步曲线来分2种情况

  1. 有脚踩到地面
  2. 双脚腾空状态

停步动画

录制_2021_10_08_10_58_15_857

image-20211008170958834

如果右脚踩地
那么播放左图动画, 结合动画曲线来控制脚步IK (ALS 脚步IK计算较为复杂,这里暂不具体展开)


image-20211008171020411

如果双脚腾空但是右脚靠近地面
那么同样播放右脚踩地动画, 同时右腿快速混合至左图的单帧动画

演示

录制_2021_10_08_11_10_54_97

Ground层

Ground层主要做了一件事, 即 姿势切换

image-20211008171124876

关注点
状态切换中间加了管道保护,判定当前没有Action执行的时候才进行姿态跳转

image-20211008171136433

States层

最外层的状态机,用于切换姿势,后期扩展游泳/攀爬等可以放到这里

image-20211008171157709

  • ALS用一个来自角色设置的bJump来判定是Falling还是Jump
  • 落地以后根据速度和输入情况叠加了下蹲姿势

对比一下

录制_2021_09_30_16_27_43_334

录制_2021_09_30_16_28_36_718

FootIK层

image-20211008171243884

虚拟骨骼

image-20211008171254672

  • ALS使用了很多虚拟骨骼来辅助计算TwoBoneIK
  • ik_foot骨骼用于锁脚
  • VB_foot_offset作为TwoBoneIK的效应器
  • VB_foot_target用于判断脚步是不是距离期望位置有偏差, 如有就播放单脚过渡动画(看上去像把这只脚收回来)
  • ALS的移动动画的ik_foot骨骼都有数据, IK效应器的位置计算依赖此骨骼的位置信息, 所以在此方案下无法使用UE4自带的移动动画, 理论上有替代方案, 额外的VB? 否则需要对动画制作提出要求

录制_2021_10_08_15_23_41_720

设置FootIK

image-20211008171354650

image-20211008171359397

ALS在Ground层直接通过ModifyCurve开启了FootIK, 部分动画比如攀爬动作通过曲线动态开启/关闭FootIk

Ragdoll层

进入Ragdoll

录制_2021_10_08_13_55_02_287

执行顺序

  • 修改移动状态为None
  • 状态机进入Ragdoll(播放Flail动画)
  • 设置碰撞
  • SetAllBodiesBelowSimulatePhysics
  • 停止当前蒙太奇
  • 根据模型位置持续设置当前Actor的位置(图中的胶囊碰撞是渲染问题,真实的胶囊体跟随着角色)

退出Ragdoll

录制_2021_10_08_13_57_26_826

  • 保存当前快照(SnapShot)
  • 恢复移动状态
  • 播放起身动画(根据pelvis朝向)
  • 恢复碰撞
  • 恢复物理效果
  • 基于快照混合至其他动画层

攀爬

检测

image-20211008171627452

  • 向前射线检测,检查前方是否有角色无法直接走上去的障碍物
  • 从上一个碰撞点上方向下进行射线检测,并确保该碰撞位置角色能行走
  • 检查攀爬点是否有足够空间容纳胶囊体,如果有则将该位置设为目标变换(Target Transform)并且计算障碍物相对高度(Mantle Height)
  • 通过当前的Movement State以及障碍物高度决定攀爬的类型
  • 传递参数,开始攀爬(Mantle Start)

攀爬

image-20211008171704410

image-20211008171707898

  • 将世界坐标系中的攀爬目标的Transform转换成以障碍物Component为基准的局部坐标系
  • 初始化攀爬目标(Mantle Target)和攀爬实际偏差量(Mantle Actual Start Offset)
  • 初始化攀爬动画偏差量(Mantle Animated Start Offset)
  • 设置Timeline,关键是让Timeline的长度和曲线实际长度(曲线总长减去起点位置)相同, Timeline的PlayRate和动画的PlayRate也必须相同;设置完毕后,开启Timeline
  • 从预设曲线中获取XYZ的Alpha值做插值计算(ALS这里用了4个lerp)

演示

录制_2021_10_08_14_46_10_531

录制_2021_10_08_11_11_51_847

相机系统

一个没有动画的动画蓝图

主要做了如下几件事

  • 自定义CameraManager代替默认第三人称模板的SpringArm+Camera的方式
  • 重写BlueprintUpdateCamera
  • CameraManager挂载骨骼模型相机,创建动画蓝图,用曲线来控制相机位置信息

image-20211008171832050

image-20211008171842911

参考文献

我之前的旧文

知乎老王