UE5.8 动画压缩与重定向:让小怪物跳起骑士的舞蹈

📑 目录

UE5.8 动画压缩与重定向:让小怪物跳起骑士的舞蹈

1. 小队的窘境:一套动作,三种骨架

老陈的独立项目里有一支三人小队:人类骑士格雷、绿皮兽人塔克、还有一团永远保持微笑的史莱姆波波。策划希望他们能共用同一套剑盾动作库,原因是预算有限,美术没有时间给每个角色单独手 K 一百多段动画。

格雷的骨架是标准的 UE5 Mannequin,四肢比例匀称。塔克肩膀更宽、手臂更长,手指骨数量还多两根。波波没有明确的四肢,躯干是一堆柔软的骨骼链,骨盆位置几乎贴着地面。把同一套骑士挥剑动画直接拖到三个角色身上,场面一度非常尴尬:格雷的动作刚健有力,塔克的手肘反折到身后,波波则像一块被风吹动的果冻,盾牌直接插进了自己的脸里。

问题的根子出在两个地方。第一,原始动画数据量很大,不做压缩内存会爆炸。第二,三套骨架的骨骼层级、比例、休息姿势都不一样,必须先把动画重定向到目标骨架,才能谈得上共用。UE5.8 把这两件事整合进了一条相对顺畅的管线,本文就沿着这条管线往下走。

architecture-beta
    group raw[原始资源]
        service mocap[动捕数据] in raw
        service handkey[手K动画] in raw
    group engine[UE5 处理管线]
        service compress[动画压缩] in engine
        service retarget[IK 重定向] in engine
        service runtime[运行时采样] in engine
    group output[输出]
        service skeletal_mesh[骨骼网格] in output
    mocap:B --> T:compress
    handkey:B --> T:compress
    compress:B --> T:retarget
    retarget:B --> T:runtime
    runtime:R --> L:skeletal_mesh

2. 动画压缩到底在压什么

动画序列在磁盘上通常由逐帧的旋转、位移、缩放曲线组成。假设一段奔跑动画有 N=240N=240 帧,骨架有 B=72B=72 根骨骼,每根骨骼每帧需要存储一个四元数旋转和一组三维位移,原始数据量轻松超过几十 MB。手游包体里如果塞进去几百段这样的动画,玩家还没进游戏就已经被下载体积劝退了。

压缩的本质是在可接受的视觉误差范围内,用更少的采样点和更低的数值精度来表示这些曲线。可以把误差写成一个简单的约束:

e=maxt,i(qtiq^ti,ptip^ti)<εe = \max_{t,i} \left( \| q_t^i \ominus \hat{q}_t^i \|, \| p_t^i - \hat{p}_t^i \| \right) < \varepsilon

这里 qtiq_t^iptip_t^i 是第 tt 帧第 ii 根骨骼的原始旋转与位移,带帽子的是压缩后的近似值,\ominus 表示四元数之间的角距离,ε\varepsilon 是项目允许的最大误差。只要每一帧、每一根骨骼的误差都小于阈值,肉眼通常就很难分辨。

UE5 里常用的压缩思路分成三类:

  • 逐帧有损压缩:降低旋转或位移的数值精度,去掉对视觉影响不大的高阶信息。
  • 关键帧重采样:只在姿势变化剧烈的帧保留关键帧,平缓区间用线性或曲线插值。
  • 基于统计/学习的压缩:利用大量动画数据的统计特征,构造更紧凑的表示,比如 ACL 插件。

下面介绍三种在具体项目中经常碰到的算法。

2.1 Additive 动画

Additive 并不是严格意义上的位级压缩,它解决的是复用问题。开发者可以把一段差异动画叠加到基础姿势上,例如“头部受伤后仰 15 度”或“持枪瞄准时的肩部抬起”。基础姿势和 Additive 差异可以分别压缩,差异曲线通常变化范围小,数值精度可以压得更狠。

在项目中,老陈把骑士的 idle 呼吸做成 Additive,基础姿势用普通压缩,叠加层用更低的采样率。这样在 Radditive=0.3R_{additive} = 0.3 的存储比例下,肉眼没有看出区别。UE5 的 AnimInstance 里通过 Apply Additive 节点把差异混合到最终姿势,运行时开销很低。

2.2 FACS 面部编码

FACS(Facial Action Coding System)把人脸表情拆成若干 Action Unit,例如眉头上扬、嘴角下拉、眼睑闭合。每个 AU 是一个 0 到 1 的权重,运行时再把权重映射到 Blend Shape。对于 MetaHuman 这类高面数角色,直接用 FACS 驱动比逐帧存储全脸骨骼曲线省得多。

UE5.8 对 FACS 工作流做了增强, Sculpt 刷、镜像目标、权重锁定这些功能让美术能在引擎里直接修 Blend Shape。老陈虽然做的是兽人和史莱姆,没有用到人脸,但他把史莱姆的蠕动拆成了六个“身体 AU”,用曲线权重控制不同区域的起伏,思路完全一样。

2.3 ACL:Animation Compression Library

ACL 是 Nicolas Fournier 主导的开源压缩库,后来以插件形式集成到 UE5。它的核心想法是把一段动画看成一条时空曲线,用球面插值和误差驱动的关键帧选择来逼近原始数据。ACL 通常在相同误差下比 UE 自带压缩小 10% 到 30%,解压速度也更快。

ACL 的代价是需要为每个平台单独测一遍误差。对于移动平台,老陈会把 Max Pos Error 设为 0.1 cm、Max Rot Error 设为 0.25 度;在主机上则可以放宽到 0.5 cm 和 1 度,因为大屏幕距离和动作幅度会掩盖微小抖动。

flowchart TD
    A[导入原始动画] --> B{目标平台与角色类型}
    B -->|PC / 主机 / 高精度角色| C[优先 ACL 或自动]
    B -->|移动 / 风格化 / 远景| D[Additive + 低精度]
    C --> E[设置 Max Pos Error / Max Rot Error]
    D --> E
    E --> F[烘焙并对比原始与压缩曲线]
    F -->|误差超过阈值| E
    F -->|通过| G[进入 IK Retargeter 或直接使用]

3. UE5 的动画压缩设置

在内容浏览器里双击任意 Animation Sequence,Details 面板里有一组 Compression 设置。老陈第一次打开时会被一堆参数吓到,其实日常只需要关注几条。

Compression Algorithm 决定用哪套压缩器。默认的 Automatic 会在内置算法里挑一个,项目如果装了 ACL 插件,也可以手动指定 ACL。手动指定的好处是同一类资产有稳定的误差上限,方便批量检查。

Translation CompressionRotation Compression 分别控制位移和旋转的编码方式。旋转通常用四元数的最高精度选项,位移如果骨骼本身很短,可以用较低精度。Scale 曲线在大多数角色里不变,直接勾选 Remove Trivial Scale Keys 能省不少空间。

Max Pos ErrorMax Rot Error 是误差天花板。数值越小,文件越大;数值越大,越可能看到抖动或滑步。老陈的测试方法很朴素:把阈值拉大,看角色身上哪里先出现 artifacts,再把该区域的误差收紧,其余骨骼保持默认。

Additive Anim Type 在 Additive 资产里必须正确填成 Additive Type,否则叠加节点会拿到错误的基础姿势。UE5 支持 Local Space Additive 和 Mesh Space Additive 两种,前者适合局部细节,后者适合需要跟随世界方向的表情或受伤反馈。

Force Root Lock 会把根骨骼锁定在原点,适合原地循环动画;需要根运动的 locomotion 则要关闭,否则角色会在原地跑步。

项目设置里还有 Per-Platform Overrides。主机端可以用更高的采样精度,移动端则允许更大的误差。老陈在 Android 包体里把位移误差放宽到 0.3 cm,旋转误差放宽到 1.5 度,包体减了 18%,战斗场景里没人看出区别。

4. 骨架重定向:让三种比例共用一套动作

动画序列在 UE 里绑定到一个 Skeleton 资产。Skeleton 不仅记录骨骼名字和层级,还保存了最初生成它时的网格比例。当塔克和波波想借用格雷的动画时,直接复用 Skeleton 已经不够,必须进行重定向。

4.1 同一 Skeleton 不同比例

如果三个角色共用同一个 Skeleton 资产,只是身体比例不同,UE 提供了简单的 Bone Translation Retargeting 选项。在 Skeleton Editor 的骨骼树上,每根骨骼可以设为 Animation、Skeleton 或 AnimationScaled。

  • Animation:位移直接来自动画数据,不做任何调整。适合根骨骼或需要精确位置的末端骨骼。
  • Skeleton:位移完全使用目标骨架绑定姿势里的长度。适合身体中段,避免长腿角色被压短。
  • AnimationScaled:把动画里的位移按目标与源骨架的骨骼长度比例缩放。

缩放比例就是:

R=LtargetLsourceR = \frac{L_{target}}{L_{source}}

LtargetL_{target} 是目标骨骼长度,LsourceL_{source} 是源骨骼长度。这个模式最常用,它既保留了动画的相对运动,又适配了目标角色的腿长和臂长。老陈把塔克的四肢都设成 AnimationScaled,躯干用 Skeleton,根骨骼用 Animation,基础移动立刻变得正常。

4.2 不同 Skeleton 需要 Rig

波波的情况更麻烦。它的骨架层级和格雷完全不同:没有明显的锁骨,手臂是触手状骨骼链,腿只有两根骨头模拟弹跳。UE 自带的同 Skeleton 重定向已经无能为力,必须引入 Rig 资产。

Rig 是一个抽象的中间层,它定义了“头、颈、脊柱、手臂、腿”这些语义链,而不是具体的骨骼名字。源 Skeleton 和目标 Skeleton 都挂载同一个 Rig 后,动画数据先从源骨骼映射到 Rig 链,再从 Rig 链映射到目标骨骼。这个过程就像先把中文翻译成世界语,再翻译成英文,前提是两种语言都能表达相同的意思。

graph LR
    subgraph source[源骨架 格雷]
        S_R[根]
        S_P[骨盆]
        S_S[脊柱]
        S_A[手臂]
        S_L[腿]
    end
    subgraph rig[抽象 Rig]
        R_P[骨盆链]
        R_S[脊柱链]
        R_A[手臂链]
        R_L[腿链]
    end
    subgraph target[目标骨架 波波]
        T_R[根]
        T_P[骨盆]
        T_S[软体脊柱]
        T_A[触手]
        T_L[弹跳腿]
    end
    S_R --> R_P
    S_P --> R_P
    S_S --> R_S
    S_A --> R_A
    S_L --> R_L
    R_P --> T_R
    R_P --> T_P
    R_S --> T_S
    R_A --> T_A
    R_L --> T_L

5. IK Retargeter 工作流

UE5 的 IK Retargeting 系统把 Rig 的概念进一步工程化,变成了 IK RigIK Retargeter 两种资产。前者描述单个骨架的链结构,后者把两套 IK Rig 连起来并执行重定向。

老陈的操作顺序如下:

  1. 给格雷创建 IK Rig,把脊柱、左右手臂、左右腿、头部分成独立的 Retarget Chain,并设置骨盆为 Pelvis。
  2. 给波波创建 IK Rig,把柔软的触手和弹跳腿也划分成对应的链。链的名字最好和格雷保持一致,UE 会自动做模糊匹配;不一致就要手动指定 Source Chain。
  3. 创建 IK Retargeter,Source 选格雷的 IK Rig,Target 选波波的 IK Rig。
  4. 在 Retarget Pose 里把两个角色摆成一致的姿势。格雷是 A-pose,波波也要临时掰成 A-pose,否则手臂角度会整体偏掉。
  5. 在 Asset Browser 里双击源动画预览效果,调整 Chain Mapping 和 Op Stack 里的参数。
  6. 满意后批量 Export Selected Animations,生成绑定到波波骨架的新 Animation Sequence。
sequenceDiagram
    participant S as 源角色 IK Rig
    participant R as IK Retargeter
    participant T as 目标角色 IK Rig
    S->>R: 发送骨骼链定义
    T->>R: 发送对应链定义
    R->>R: 匹配骨盆 Pelvis 与根运动
    R->>R: 对齐 Retarget Pose
    R->>R: 执行操作栈 Op Stack
    R->>T: 输出目标骨架姿势
    R->>R: 预览源动画并批量导出

IK Retargeter 的优势在于它支持不同骨骼数量、不同命名、不同朝向的骨架。UE5 Mannequin 和 MetaHuman 之间就自带一套预置的 RTG_UE5Mannequin_To_MetaHuman, indie 团队可以直接把 Mannequin 动画库搬到 MetaHuman 上。

Op Stack 里常见操作包括 Copy BoneRetarget ChainFK/IK 切换Pelvis MotionFloor Constraint 等。老陈的经验是:先把每条链用默认的 Retarget Chain 跑通,再对脚部和骨盆加 Floor Constraint,最后处理手指和触手末端。末端骨骼数量不一致时,可以取消映射,让它们在目标绑定姿势里保持原样,避免触手乱飞。

6. 重定向里的常见病

即便管线搭好,预览窗口里依然会出现各种诡异现象。老陈把问题分成三类:滑步、扭曲、比例失调。

6.1 滑步

滑步最常见的原因是根运动没对上。源动画里角色向前跑了 D=300D=300 cm,目标角色腿更长,步幅更大,如果直接拷贝根位移,脚就会在地面上漂移。修复办法有几种:

  • 在 IK Retargeter 里开启 Stride Warping,根据腿长比例自动缩放步幅。
  • 把腿部链改为 IK 模式,脚跟着地时强制贴合地面。
  • 导出后手工修根运动曲线,让位移增量与目标角色的步频匹配。

老陈给塔克用了 Stride Warping,把他的步幅系数调到 k=1.15k = 1.15,滑步基本消失。

6.2 扭曲

扭曲通常来自休息姿势不一致。格雷是 A-pose,波波默认是蜷缩姿态,直接重定向会让手臂绕肩关节翻转 90 度。解决办法是在 Retarget Pose 面板里把波波掰成和格雷一致的 A-pose,并保存为 Retarget Base Pose。如果已经保存了还是扭,可以检查 Chain Mapping 里的骨骼朝向,必要时加 Rotation Offset

脊柱扭曲也很常见。源角色有三节脊柱骨骼,目标角色只有一节,重定向时旋转会被平均分配,导致腰部像麻花。老陈把波波的软体脊柱拆成更多骨骼,并用 Copy Bone 逐个绑定,扭曲才缓解。

6.3 比例失调

比例失调包括手臂过长、手够不到剑柄、头埋进胸口等。它的数学表现是链长度比 RR 与动画幅度不匹配。塔克的剑比格雷长 20%,如果只是缩放手臂,握剑点还是偏移。老陈的做法是给武器单独做 Socket,握持时用 IK 把右手锁定到 Socket,左手做辅助对齐。这样武器动画和角色动画解耦,重定向只负责身体,握持由 IK 保证。

flowchart TD
    A[预览重定向结果] --> B{出现哪种 artifact}
    B -->|脚在地面上滑动| C[检查根运动与 Stride Warping]
    B -->|手臂或躯干螺旋| D[对齐 Retarget Pose 并检查骨骼朝向]
    B -->|手够不到道具或肢体比例异常| E[加 IK 约束或调整链长度比]
    C --> F[再次预览]
    D --> F
    E --> F
    F -->|仍有问题| B
    F -->|通过| G[批量导出]

7. 内存与加载优化

动画压缩只解决了磁盘和内存中的数据大小问题,运行时还要考虑加载时机和采样开销。老陈在手机上测试时发现,关卡里同时刷出十二个敌人后,帧率会周期性掉一下。Profiler 显示瓶颈不是渲染,而是动画采样和姿态混合。

一条简单的经验是:不要把所有动画都塞进默认加载组。UE5 支持把 Animation Sequence 放到 Streamable Asset 里,按关卡或敌人种类异步加载。远处的小怪只需要 idle 和 run,近战攻击动画可以等玩家靠近再加载。这样做能显著降低一次性内存峰值。

姿态混合的开销和骨骼数量成正比。如果某些敌人距离摄像机很远,可以用 Bone LODUAnimInstance::SetBoneFilter 跳过手指、面部、披风等细节骨骼的采样。老陈给远景敌人关闭了手指和面部曲线,采样开销降了约 40%。

Additive 动画虽然省空间,但运行时要额外做一次姿势叠加。把多个 Additive 链合并成一条 Additive,或者把常驻的呼吸、瞄准偏移直接烘焙到基础动画里,可以减少每帧的混合次数。

重定向本身也有开销。运行时通过 Retarget Pose From Mesh 节点做实时重定向,适合主角和少数精英敌人;普通小兵最好在内容浏览器里先 Export Retargeted Animation,把重定向结果烘焙成新的 Animation Sequence。烘焙后的资产在运行时和普通动画一样快。

内存预算可以用下式估算:

M=k=1KnkCkFkBkM = \sum_{k=1}^{K} n_k \cdot C_k \cdot F_k \cdot B_k

KK 是动画类别数,nkn_k 是同时驻留的该类动画数量,CkC_k 是单帧单骨骼压缩后字节数,FkF_k 是帧数,BkB_k 是参与采样的骨骼数。老陈用这个公式把同时驻留动画从 80 段压到 35 段,内存占用从 187 MB 降到 94 MB。

下面是一段在 DefaultEngine.ini 里启用 ACL 并设置全局默认误差的示例:

[/Script/ACLPlugins.ACLAnimBoneCompressionCodec]
+DefaultErrorThreshold=(MaxPosError=0.1,MaxRotError=0.25,MaxScaleError=0.01)
bSkipBone=0

[/Script/Engine.AnimBoneCompressionSettings]
+Codecs=/Script/ACLPlugins.ACLAnimBoneCompressionCodec

实际项目中建议先在几条代表性动画上跑 Compress Animation 命令,对比文件大小和曲线误差,再把参数写进 ini。

8. UE5.8 的新改进

UE5.8 在动画和绑定这块加了大量工具,跟压缩和重定向直接相关的有三点。

第一,Foot Definition Options for Retargeting。重定向时脚部的定义不再只有一套默认规则,可以为不同比例和风格化角色指定脚跟、脚趾、脚掌的相对位置。塔克这种脚掌特别宽的兽人角色,重定向后脚掌能正确贴合地面,而不是悬空或者插进地里。

第二,Retarget Override Sets。同一套 IK Retargeter 可以保存多组覆盖配置,每组覆盖可以修改操作栈属性、启用或禁用某些操作。老陈给主角和 NPC 分别建了一个 Override Set:主角保留高精度 IK 和手指链,NPC 关闭手指映射并放宽骨盆约束。切换时不需要复制 Retargeter 资产,直接在节点或变量里选 Set 就行。

第三,变量与 Anim Curve 绑定。Override Set 里可以声明蓝图变量,也可以在运行时把动画曲线值绑定到重定向属性。例如角色手持武器时,一条 IsHoldingWeapon 曲线可以动态调整手臂 IK 权重,重定向结果会随状态自然过渡,不用在 AnimBP 里写复杂的分支。

除了这些,UE5.8 还新增了自动化烘焙、Control Rig Physics Beta、Control Rig Dynamics 和 Direct Mesh Controls。这些工具主要面向绑定和镜头修形,和压缩重定向不在同一条管线,但能让动画资产的生产效率整体提高。

9. 结尾

老陈最后用了一周时间把骑士、兽人、史莱姆的动画管线跑通。格雷继续用原始动作,塔克通过 AnimationScaled 和 Stride Warping 解决了比例和滑步,波波靠 IK Retargeter 把触手和身体链映射到了骑士动画上。三套角色共用同一份动作库,美术只做了少量 Additive 修正和武器 Socket 对齐。

动画压缩和重定向不是一次性开关,而是一组需要反复测量的参数。先用压缩算法把数据量控制住,再用重定向把姿势适配到不同骨架,最后用 Profiler 验证运行时开销,才是比较稳的做法。UE5.8 把重定向的覆盖配置和脚部定义做得更细,独立团队也能在不用写大量自定义代码的前提下,做出多角色共用动画的方案。

希望这套思路能帮你在自己的项目里少踩几个坑。