GASP笔记03

之前说过GASP的主要动画流程,就是运动匹配,这也是GASP这个项目主要要表达的核心技术,而在中间的动画输出主要是为了微调,让整体的效果变得更好,比如角色在跑步转弯的时候会有一个小幅度的倾斜,模拟现实中跑步绕圈时人会倾斜的效果,以及角色在瞄准的时候面朝瞄准方向,腿部IK,人物在斜坡的时候脚会正确接触地面,这些中间的微调本质上都是为了让人物的动作效果更加自然。

人物倾斜

人物倾斜的原理是使用1D的混合空间,使用一个浮点值作为调整值,然后附加在当前的角色动画上, 是一种 非破坏性的动画叠加技术 ,通过在基础动画上叠加相对偏移量来实现复杂的动画组合效果。

首先GASP创建了一个BlendSpace1D,使用一个LeanLR浮点数作为调整值,1和-1分别代表向左和向右倾斜

然后需要选取对应的锚点动画,BlendSamples里,对三种值分别设定了三种锚点动画,当输入参数位于两个采样点之间时,例如:

最终动画 = 采样点1动画 × 权重1 + 采样点2动画 × 权重2采样点布局:

  • 采样点1: 站立动画 (速度=0)

  • 采样点2: 慢走动画 (速度=3)

  • 采样点3: 快走动画 (速度=6)

  • 采样点4: 跑步动画 (速度=10)

输入速度=4.5时:

系统自动在慢走和快走动画之间进行平滑混合

点击任意一个动画,我们可以看到其所锚定的动画,这就意味着在不同的值的情况下,它能与锚定动画进行混合,然后这些锚点动画又包含一个Additive Settings,其是动画序列的 叠加动画配置 ,定义了动画如何作为叠加层应用到基础动画之上。Additive动画存储的是 相对于基准姿势的偏移量 ,而不是完整的绝对变换。

最终姿势 = 基础姿势 + (叠加姿势 - 参考姿势) × Alpha

例如,当我们想让角色在移动中进行瞄准的时候,BlendSpace1D设定了移动速度值,然后BlendSamples就是不同速度情况下的瞄准强度动画,比如从腰射到机瞄,而Addtive Settings就是确保瞄准动画正确的叠加到移动动画上

plain 复制代码
// 基础层: 角色移动动画 (BlendSpace1D控制)
// 叠加层1: 武器瞄准动画 (Additive Settings配置)
// 叠加层2: 面部表情动画 (Additive Settings配置)  
// 结果: 角色可以同时进行移动、瞄准和表情表达

可以在需要叠加和锚定动画截取的原动画(比如跑步,倾斜跑步)截取一帧作为需要锚定的动画和需要叠加的动画

完成以后进行应用即可,GASP将其限制在了当角色开始移动的时候才应用

另外在之前的倾斜程度值这里写了一个Getter函数,主要根据角色的移动速度和角色在Y轴上的加速度方向的乘积来计算

瞄准视角跟随

和人物倾斜一样,瞄准视角跟随同样也是使用BlendSpace,不同的是使用的是2D的方案,也就是两个轴向的浮点值,范围是-90到90度,用来模拟人在观察时头部能旋转的最大角度,分别代表上下左右,隔45°一个区间。

然后也定义了锚点动画,锚点动画也是根据值来配置对应的头部转向动画,在最后节点连接的时候,通过布尔开关来切换是使用锚点动画来混合还是通过计算玩家视角旋转来混合,二者混合的值不一样

Additive Identity Pose 是Additive动画系统中的 基准参考姿势 ,定义了叠加动画的"零点"或"中性状态",Additive动画不是存储完整的绝对变换,而是存储 相对于某个参考姿势的偏移量 。

最终姿势 = 基础姿势 + (Additive姿势 - Identity Pose)

Dead Blending是确保处理参数超出有效范围的特殊混合技术,参数主要包含动画混合参数(速度,角度,强度等),BlendSpace坐标参数,输入设备参数,游戏状态参数等,还确保系统在异常情况下仍能提供合理的动画表现

例如:

plain 复制代码
// 正常范围:-90°到+90°
// Dead Blending处理超出范围的角度
if (角度 < -90°) 播放左极限动画;
if (角度 > 90°) 播放右极限动画;

// 正常速度:0-10米/秒  
// Dead Blending处理异常速度
if (速度 < 0) 播放反向移动动画;
if (速度 > 10) 播放极限奔跑动画;

然后是如何取混合空间的调整值,除了上面的Addtive Identity Blend方案,还有手动计算角色视角控制的方案,也就是获取Yaw 和Pitch的值,同样构建了一个Getter函数

首先判断当前是否属于本地控制器,因为还有AI控制器的情况

如果是本地玩家控制的则获取玩家摄像机旋转,因为玩家控制角色的时候可以控制摄像机,所以就可以获取摄像机看向的旋转,反之获取角色实际看向的方向

RootTransform变量来自角色的根运动偏移,从中获取偏移的transform并返回,"-90度默认旋转" 是Unreal引擎中骨骼网格体的标准朝向设置

根骨骼偏移

Offset Root Bone主要是为了解决胶囊体移动和动画数据不匹配的问题,固定半径内的位置偏移,运动时偏移,静止时归位,具体表现为:

当启动时:角色突然向前移动,但是动画还没开始

当停止时:角色已经停住,但动画还在继续

转向时:身体已经转向,但脚还在原来的方向滑动

移动时:脚步与地面接触不自然,像是在滑行

注意:这里的角色指的是Pawn,其内涵角色移动组件的功能

plain 复制代码
// 物理系统:玩家按下W键 → 胶囊体立即向前移动
// 动画系统:需要0.2秒播放"启动动画"
// 结果:角色身体已经移动了,但脚还在原地 → 滑冰!

这个节点需要五个参数导入,分别是平移模式,旋转模式,平移半衰期,旋转半衰期,和一个控制开关

首先是平移模式(Translation Mode),该枚举分别有:Accumulate(累积),Interpolate(插值),LockOffsetAndConsumeAnimation(锁定偏移消耗动画),LockOffsetIncreaseAndConsumeAnimation(锁定偏移增加消耗动画),LockOffsetAndIgnoreAnimation(锁定偏移忽略动画),Release(释放模式)

Accumulate(累积模式)

工作原理:偏移量会一直累计,不会自动消失,类似滚雪球一样越滚越大

比如:

plain 复制代码
// 角色启动时:身体前倾 → 保持前倾姿势
// 角色停止时:身体后仰 → 保持后仰姿势  
// 角色转向时:身体倾斜 → 保持倾斜姿势

适用于需要保持某种姿势的特殊效果,比如模拟惯性很大的物体(搬运重物),或者像是特殊动画效果,比如醉酒状态。

Interpolate(插值模式)

工作原理:平滑过渡,自动恢复,偏移量会自动平滑地回到中心点,使用半衰期控制恢复速度,类似弹簧一样,拉开会自动弹回

plain 复制代码
// 角色启动时:身体前倾 → 慢慢恢复直立
// 角色停止时:身体后仰 → 慢慢恢复平衡
// 角色转向时:身体倾斜 → 慢慢转回正面

LockOffsetAndConsumeAnimation(锁定偏移消耗动画)

工作原理:锁定位置但继续播放动画,锁定当前的偏移位置,但继续消耗动画中的跟运动,位置不动,但动画继续播放

plain 复制代码
// 角色启动时:身体前倾 → 锁定在这个位置
// 动画继续:脚部动画正常播放,但身体位置固定
// 效果:像在跑步机上跑步

LockOffsetIncreaseAndConsumeAnimation(锁定偏移增加消耗动画)

工作原理:只允许减少偏移,不允许增加,可以回到中心点,但不能超过当前偏移,类似于"单向阀"的效果

plain 复制代码
// 当前偏移:身体前倾10cm
// 允许:回到中心(0cm)或前倾5cm
// 不允许:前倾到15cm

LockOffsetAndIgnoreAnimation(锁定偏移忽略动画)

工作原理:完全锁定,忽略动画,完全锁定当前偏移位置,忽略所有跟动画运动,类似定在地上的效果

plain 复制代码
// 角色启动时:身体前倾 → 完全锁定
// 动画播放:但身体位置纹丝不动
// 效果:像被定身法术困住

Release(释放模式)

工作原理:逐渐释放,回到中心,停止累加新的偏移,主键释放现有的偏移,平滑回到中心位置

plain 复制代码
// 当前状态:身体前倾20cm
// 释放过程:20cm → 15cm → 10cm → 5cm → 0cm
// 最终效果:回到直立姿势

适用于从特殊状态回到正常状态的效果,恢复平衡的过渡阶段

然后GASP为其单独创建了一个Getter函数去根据具体的情况选举这些枚举值

根据角色的移动组件,如果角色此时在空中,则输出"释放",即

plain 复制代码
// 当前效果:假设跳跃前角色正在奔跑
当前偏移:身体前倾20cm(奔跑惯性)


// 检测到In Air = true
切换为:Release模式

// 效果:
- 停止累积新的前倾偏移
- 开始逐渐释放现有的20cm偏移
- 身体慢慢恢复直立姿势

如果是在地面上则输出插值,插值虽然也是缓慢恢复,但是区别在于,插值在恢复的同时也在接受新的输入,就类似于玩家在奔跑时身体会前倾,如果此时停止奔跑会恢复,但是如果此时再次奔跑还是会前倾,但是恢复的话就不会有个再次允许输入的情况

Rotation Mode则是旋转的情况,思路与移动的相似。

TranslationHalflife(平移半衰期)和RotationHalfLife(旋转半衰期)主要是控制上面两个枚举的指数级衰减速度。

FootPlacement

智能脚步放置,这个节点专门解决角色移动时的"脚步漂浮"的问题,某些情况下,角色移动的时候可能会脚步悬空在地面上放,或是穿入地面下方,在不平的地形上脚步不贴合

这个节点包含两个核心参数,一个种植设置,主要是用于判断脚步是否可以"种植"的速度临界点,还有一个是插值设置,控制脚步解除"种植"时位置调整的"硬度"

何为"++种植++ "?其实就是指脚部与地面建立稳定接触的过程 ,类似植物无论如何都要扎根到地面那种效果,该节点围绕这个方式进行计算调整,确保在不完整平面的情况角色的脚部能够稳定地与地面进行接触

Plant Setting是一个结构体,其内部包含:

  1. Speed Threshold(速度阈值) 作用:判断脚部是否可以种植的速度临界点

++脚部速度 = |根运动位移| ÷ 时间增量++

具体步骤是提取当前帧的根运动数据,计算根运动的位移向量长度,除以时间增量就得到了脚部速度。

脚部数据不一定是取决于根运动属性获取,也可以是根据动画中的曲线获取速度值 ,这个判断取决于Plant Speed Mode是否为Graph模式

  1. Distance To Ground(到地面距离) 作用:脚部距离地面的最大种植触发距离

从角色脚部上方开始向下扫描,扫描长度就是取决于这个数值

  1. Lock Type(锁定类型)

①:Unlocked(未锁定) 效果:脚部可以自由移动和旋转,虽然最终会贴合地面,但是会保留原有的旋转,不进行任何调整

②:Pivot Around Ball(围绕脚球旋转) 旋转中心在脚球位置 效果:模仿真人行走,脚后跟可以抬起,前脚掌保持地面接触

③:Pivot Around Ankle(围绕脚踝旋转)旋转中心在脚踝位置 效果:模仿机器人行走,整个脚部都会转动

④:Lock Rotation(锁定旋转)效果:脚部像磁铁一样吸附在地面上,但不改变朝向

  1. Unplant Radius(解除种植半径)作用:脚部离开该预设的距离的时候会解除种植

Interpolation Settings(插值设置)是一个结构体,其内部包含:

  1. Unplant Linear Stiffness(解除种植线性刚度)作用:控制脚部解除种植时的位置调整速度,当角色的脚部解除种植的时候会有一个恢复的速度,不同的数值大小就是恢复的速度大小,数值参考:
plain 复制代码
低刚度(100-200):缓慢解除,像在泥泞中
中等刚度(200-300):自然解除,像正常行走
高刚度(300-400):快速解除,像在冰面上
  1. Unplant Angular Stiffness(解除种植角度刚度) 作用:控制脚部解除种植时的旋转调整速度,和上面一样,只不过调整的是旋转

  2. Floor Linear Stiffness(地面线性刚度)作用:控制脚部贴合地面的调整速度,也就是贴合地面的快速响应速度

GASP同样为两个参数设定了Getter函数,首先是种植设置部分,在MotionMatching节点里绑定的每选择一次就调用的函数中,从MotionMatching选择的动画的结果中筛选"Stop"标签的动作数据库

筛选完毕以后根据是否选择纯运动匹配/状态机+运动匹配的开关来选择不同的种植设置结构体(默认配置好的)

插值设置结构体也是同样的这里不多赘述。

LegIK

LegIK节点是一个专门用于腿部逆向运动学(Inverse Kinematics)的动画节点。让角色的脚部精确到达想要的位置,和footplacement的区别在于,LegIK是手动控制的,让脚精确地踩到某个特定的位置上,比如踩在石头上,踩在棍子顶端这种,

LegIK节点有一个 LegDefinitions,IKFoot Bone 和 FKFoot Bone分别是让IK和FK分别控制哪个骨骼点,NumBonesInLimb(肢体骨骼数量)是告诉腿部包含几段骨骼,通常来说,数值为2:大腿+小腿(最常见),数值为3:大腿+小腿+脚部(更复杂)。

MinRotationAngle(最小旋转角度),目的是防止腿部过度弯曲,确保膝盖不会"反关节",一般来说保持15度左右足矣,效果呈现为腿部可以弯曲但是弯曲程度受限

FootBoneForwardAxis(脚部前向轴)目的是告诉脚部应该朝哪个方向,分为X,Y,Z轴,GASP的话是选择Y轴

HingeRotationAxis(铰链旋转轴)目的是控制腿部在哪个平面上(X,Y,Z)弯曲

bEnableRotationLimit(启用旋转限制)作用是限制最小角度

bEnableKneeTwistCorrection(启用膝盖扭曲校正) 作用是自动校正膝盖扭曲

TwistOffsetCurveName(扭曲偏移曲线名称)通过动画曲线控制额外膝盖扭曲

Local To Component 和 Component To Local

Local To Component:

作用:将局部空间姿势转换为组件空间姿势

Component To Local

作用:将组件空间姿势转换为局部空间姿势

局部空间就是相对于父级骨骼的坐标系,特点是每个骨骼都有自己的局部坐标系,组件空间就是相对于整个骨骼网格体的坐标系,也就是全局统一的坐标系。

当需要与"外部世界"进行交互的时候,比如抓东西,踩地面,物理碰撞,因为外部世界在组件空间,所以我们需要知道骨骼在组件空间的位置才能计算距离,旋转,位置这些

然后骨骼本身的位置经过例如IK计算,FK计算以后,计算结果在组件空间,需要转换回局部空间,简单来说就是当外部计算完成后,需要回到动画系统时需要Component To Local

比如:

不进行空间转换的情况:

plain 复制代码
假设:
- 手臂局部位置:(0, 0, 50)  // 相对于肩膀
- 杯子组件位置:(100, 200, 80)  // 世界坐标

直接计算:手臂(0,0,50) vs 杯子(100,200,80)
结果:完全错误!因为坐标系不同

进行空间转换的情况:

plain 复制代码
步骤1:手臂局部(0,0,50) → Local To Component → 手臂组件(150,100,60)
步骤2:计算手臂组件(150,100,60)到杯子(100,200,80)的距离
步骤3:IK计算结果 → Component To Local → 应用回动画
结果:手臂正确伸向杯子

GASP到此的笔记就做的差不多了,接下来我尝试把该动画蓝图移植到我自己的项目并适配,如果过程发现了一些值得记录的东西我会再出一篇。

相关推荐
后来后来啊2 小时前
2026.1.20学习笔记
笔记·学习
wdfk_prog2 小时前
[Linux]学习笔记系列 --[drivers][base]devtmpfs
linux·笔记·学习
DS随心转小程序2 小时前
【技术前瞻】Edge 浏览器深度集成 DS随心转:AI 搜索与笔记流转的一站式生产力革命
人工智能·笔记·edge·deepseek·ds随心转
June bug2 小时前
【实习笔记】埋点测试
笔记
培小新2 小时前
运维高级课笔记(RHCSA复习)
笔记
汤姆yu2 小时前
基于android的云笔记系统
笔记
代码游侠2 小时前
学习笔记——文件传输工具配置与Makefile详解
运维·前端·arm开发·笔记·学习
lkbhua莱克瓦242 小时前
Apache Maven全面解析
java·数据库·笔记·maven·apache
云边散步2 小时前
godot2D游戏教程系列一(6)
笔记·学习·音视频