AdvancedLocomotionSystemV4分析(一):移动和脚步IK

最近对UE4商城AdvancedLocomotionSysemV4进行了一波初步分析,感觉这个项目已经包含了大多数情况能用得到的动画表现,从移动表现中比较容易出问题的脚步问题到IK、攀爬、翻滚、布娃娃以及动作叠加等模块都有讲到

打算参考这个项目的思路重新实现一边动画逻辑,顺便对其中重要的模块和知识点记录一下

这一篇先从基础的移动逻辑,包括转身、起跳等,再顺带看一下脚步IK的实现

AdvancedLocomotionSystem分析(二):攀爬系统

AdvancedLocomotionSystemV4分析(三):动作叠加

AdvancedLocomotionSystemV4分析(四):布娃娃和起身

AdvancedLocomotionSystemV4分析(五):镜头

数据结构

首先先把移动和姿态相关的数据结构拎出来看一看,会用到很多枚举和结构体

Enum

MovementState/移动状态
  • Grounded
  • InAir
  • Mantling(攀爬)
  • Ragdoll
MovementAction/移动行为
  • LowMantle
  • HighMantle
  • Rolling
  • GetUp
RotationMode
  • LockingDirection
  • VelocityDirection
  • Aimming
Gait/步态
  • Walking
  • Running
  • Sprinting
ViewMode
  • FirstPerson
  • ThirdPerson

Struct

FDynamicMontage

用于动态播放蒙太奇,这个是鼠标拖动视角后的脚步的蒙太奇动画

image-20201027150639437

FLean

倾斜参数

image-20201027150817198

FMovementSetting

移动数据,配置各种移动速度和移动旋转相关的曲线参数

image-20201027150903150

这边还包括了2层,分别对应3种旋转模式和2种视角的数据

image-20201027151004574

image-20201027151010318

然后到表格里配置3种形式的参数

image-20201027151037012

FTurnInPlaceAssets

转身参数,也是用于播放蒙太奇,这个是移动视角到一定角度以后的转身动作

image-20201027151249527

FVelocityBlend

4方向的权重值(混合值),非常不同于一般理解的用一个方向的概念,这里用了一4方向单独的浮点值来控制混合

image-20201027151312094


角色逻辑

Tick

image-20201027151612359

现关的tick逻辑就以上几个

设置必要参数/SetEssentialValue

这个函数主要目的是计算并设置一些动画蓝图必要的参数,比如加速度、速度等

image-20201027151724768

  • 加速度

并非直接去移动组件拿实时加速度,而是自己计算2帧之间的速度差来计算加速度

image-20201027151822567

  • 速度

这个比较简单

image-20201027151856919

  • 移动输入值

image-20201027151931872

一个用当前加速度来设置的移动输入浮点值和布尔值,在动画蓝图里也是蛮重要的

  • 视口旋转速率

2帧之间的朝向插值来得到的旋转速率

image-20201027152033799

步态设置/UpdateMovement

主要设置枚举Gait,这里需要提一下,按键得到的步态并不一定是最终的步态

DesiredGait期望步态来自于事件输入,可以自定义

image-20201027152208555

image-20201027152353930

上图对不同姿态不同视口等做了一定约束/筛选,比如在Aimming姿势下不能出现Sprint

image-20201027152515614

上图种,根据实际速度来决定真实的步态,跟期望步态可能会不同,因为有加速减速的存在,直到这个过程到达所需的速度才真的设置步态

image-20201027152613123

然后根据不同的情况设置不同的真正的速度、加速度、摩擦力等参数

更新旋转/updateRotation

说到角色旋转,我们要看一下角色几个很关键的参数

  • bUseControllerRotationYaw : false
  • CharacterMovement.bOrientRotationToMovement:false

以上2个参数都是false,意味着我们角色的朝向全靠我们逻辑来控制了

先看一个简单的插值计算函数

image-20201027153053725

基本上大多数的角色旋转都是用这个函数实现的,做了2步插值计算

image-20201027153221577

然后对于地面的速度做了一个计算,读取了配置参数的曲线信息,我们任意打开一个曲线看一下

image-20201027153330854

上图是不同状态下的旋转速率,0=5,3=20

移动数据是BeginPlay的时候读表获取的

然后根据不同视角、旋转模式等进行不同的插值计算

image-20201027154624163

image-20201027153809298


然后还有一种旋转方式稍微不容易理解一点,需要注意的是如果动画制作的时候不是用30帧的,下图中的30帧处需要替换为对应的帧数

image-20201027154033617

从曲线等到值来动态设置旋转值

这个曲线挂在转身动画里面,比如右转90度的曲线

image-20201027154357794

动画修改器:添加根骨骼运动曲线

根骨骼旋转信息的曲线我们用修改器来制作,思路就是对比2帧之间的旋转插值然后添加数据点

image-20201023175214668

缓存数据/CacheValus

就是存一下2个旧的数据,上述逻辑中用到的对比2帧数据差的

image-20201027154830956

数据接口

image-20201027154851355

image-20201027154857475

如图所示,把必要参数都通过接口得到

动画蓝图

逻辑视图

主要逻辑就是Tick和通知两部分

在Tick中主要是如下几个方法

UpdateCharacterInfo

从角色要到必要的参数

image-20201027161533966

UpdateMovementValues

image-20201027161738837

这里比较有用的是计算VelocityBlend的思路

image-20201027161814570

image-20201027161826756

如上图,重点是把世界速度转换成本地的归一化速度


然后是计算本地加速度和倾斜角度,加速度直接决定了倾斜角度

image-20201027162041292

image-20201027162048573

然后是计算步长,跟速度挂钩,从曲线中获取信息,下图中表示了曲线对应的大概的速度范围

image-20201027162222030

计算站立动画播放速率:跟曲线Weight_Gait有关联,一般设置2为跑步,3为冲刺的速率

image-20201027162326824

UpdateRotation

旋转相关的参数,下图所示比较简单

image-20201027162423055

image-20201027162444761

image-20201027162457635

后面还有关于转身的方法和通知,留到下面单独讲

动画视图

先来看一下动画视图的跟移动和IK有关系的主视图,原版工程还有很多层级,现在先不拿进来

image-20201027162753661

BaseLayer

image-20201027163331816

LocomotionCycles

image-20201027163407630

这里就直接进入对应的动画层

image-20201027163438437

第一下有点难以理解,为什么要分6个,一般理解上要么4个要么8个

理性分析以后,我们需要考虑一个穿帮问题,拿我们一般用的单个混合空间,横竖轴分别对应移动方向和移动速度来说,经常在4个斜角中的2个斜角会出现脚步严重穿插问题,用过的应该都能理解,现在这个设计思路就是几乎完美的解决了这个问题

比如走路一共有6个动作

image-20201027163809113

我们如果的移动顺序是 前->右->后

那么动画的播放顺序是 F->RF->RB->B

如果是前->左->后

动画顺序是F->LF->LB->B

我们再去看动画具体表现

LF和RB都是右脚在前左脚在后,如下图

image-20201027164541218image-20201027164555146

RF和LR如下图

image-20201027164629282image-20201027164640634

而前和后都是正面朝向的就不贴图了

所以这种混合方式就避免了左右脚前后问题的混合,当然也意味着动画师得多做几份动画了

image-20201028090323058

上图是MoveRF的状态机,需要注意的是RF对立面混合的就是前面所说的,脚步前后一致的LB,当然一般情况下,VelocityBlend的R值和L值也不会同时大于0


每个状态机的进入都有一个通知,直接设置了方向枚举,这个枚举变量用于停步的逻辑,后面细讲

image-20201027165201291

在这个动画层还有一些逻辑,如下图所示比较容易理解

image-20201027165436452

LocomotionDetail

image-20201027170302476

run add

主要叠加了走路到跑步或者冲刺的启动动画叠加,如上面的动图

image-20201027171642190

image-20201027171649329

2个类似的状态机区别主要就是直接从静态到跑步还是从完整的走路姿势切换到跑步,从叠加上区别就是StartPostion的不同

LocomotionStates

image-20201027171904903

这里主要实现了2部分内容

  1. 原地/移动/停步的切换
  2. 原地转身动画
  • Stop

image-20201027172526588

image-20201027172418385

用动画曲线来判定脚的位置,如下图

image-20201027172622022

上图是跑步的位置曲线,重定向过来的曲线信息会有些许区别,比如直线变曲线,但是大致相同

基本上是右脚踩下=1,左脚踩下=-1

对于脚没有完全踩下的节点会复杂一些,先看一个全图

image-20201027173024455

看一下骨骼分层

image-20201027173037908

那么下面的混合大概思路就是根据不同的移动方向和不同的方向枚举,这2个变量之前都讲过,这里分别处理

混合的动作都是各个方向的走路动画的某个时间点的单帧动画

  • 转身

转身动作是特殊情况的拖动,循环播放的形式

image-20201027173516992

动画速率跟镜头旋转速度有关系

看一下具体的判定条件

image-20201027173619244

言下之意就是瞄准方式或者第一人称的模式都是这样旋转的

MainMovement

此状态机用来控制地面和空中的姿势切换

image-20201027173736606

MovementStateJumped分别判断是主动起跳和是被动自由落体

逻辑上主动起跳是先修改布尔值再更新枚举值

image-20201027174004729

  • 起跳

image-20201028094937513

几个必要的变量计算

思路是在下落过程中计算得到速度和地面预判值

预判值用射线检测得到,最后得到效果是落地的瞬间叠加了手臂上扬的动作

image-20201028093655072

image-20201028094318721

image-20201028094405280

内部状态机如上图

根据起跳时脚的位置来决定起跳初始动画,即一般意义上的JumpStart的动作,此动作为过渡性动作,结束以后自动跳转到下一个状态机

下一个状态机是空中循环,虽然是循环播放,但是无条件跳转到Flai动作(一个手舞足蹈的下落动作)

脚步IK

脚步IK和停步其实要放一起说,因为停步的时候也用到了IK的一部分功能用来把脚收回去

image-20201027174115844

这里加了很多虚拟骨骼

  • foot_target_r:用来判断跨步是否比较大
  • ik_foot_r_Offset:控制TwoBoneIKEffector,即IK效果的主要控制节点
  • ik_knee_target_r:膝盖位置,TwoBoneIKJoint节点,即IK效果的方向参考点

image-20201027174459766


  • IK动画视图

image-20201027174715349

动画视图比较简单,难点是计算方式

找到Tick逻辑里的UpdateFootIK方法

从里面一点点分析

SetFootLocking

image-20201027174825245

image-20201027174845182

这里不细究了,思路就是得到当前动画的FootLock曲线信息,有权重就意味着需要锁定脚步位置,锁定的时候即抵消了TwoBone IKEffector骨骼的影响

SetFootOffset

image-20201027175052583

image-20201027175148982

这里会一直打射线计算地面点,得到具体的脚步的位置,然后插值计算放置跳帧

脚步IK逻辑不是很多,但是我这里重新实现的时候发现了很多细节问题,效果很难到达预期,具体可以详细参考工程