← ALL ARTICLES
动画系统4 MIN READ

动画压缩

全库目录221
本文目录9

同一段动作删掉一半关键帧,躯干可能看不出变化,手指却离开了握持点。局部旋转的微小误差会沿骨骼层级放大,所以动画压缩先定义哪些部位容许多大误差,再决定删轨道、删关键帧还是降低位宽。包体之外,解码速度和随机访问也决定它能否用于运行时。

动画存储规模

假设 100 个关节,每个关节每帧保存平移、四元数和缩放共 10 个 Float,30 FPS、10 秒动画的原始数据约为:

100×300×10×4 bytes≈1.2 MB100\times 300\times 10\times 4\text{ bytes}\approx 1.2\text{ MB}

单个动画片段看似不大,但角色、武器、表情、过场和多语言口型叠加后会迅速增长。运行时还关心解压后的内存访问和缓存,不只是包体。

恒定轨道与关键帧抽取

一条缩放轨道的全部采样若都是(1,1,1),运行时只需取默认值;固定在(0,0.3,0)的局部平移只需保存一个常量。先按轨道误差阈值判断是否恒定,再尝试删除时间点,可以避免为从未变化的数据建立查找表。

对一维平移轨道,设时间为0、0.5、1秒,位置为0、0.5、1米。删掉中点以后,端点线性插值在0.5秒仍得到0.5米,误差为零。若中点是0.8米,同一重建产生0.3米误差;容许误差0.01米时必须保留中点。旋转轨道用同样思路,只是重建采用约定的四元数插值,并把结果放回骨架测量。

一种贪心抽取法从当前保留点向前扩大区间,每次重建区间内全部候选采样。第一次超过误差阈值,就保留前一个安全端点,再从那里继续。只检查区间末尾会漏掉中间的突变,因为区间端点总能精确重建。输出时间不再均匀,解码器因此需要查找包围当前时间的两个关键帧。

误差不能只看单个关节的局部角度。手指根部很小的旋转,在长层级末端可能产生明显位置误差。更可靠的压缩器会评估末端或整条骨架的对象空间误差。

旋转误差的放大可以用两节骨链理解。上臂长 0.3 米、前臂长 0.3 米,根关节偏转 1°,伸直时手部位移约为 0.6 m×sin⁡(1°)≈10.5 mm0.6\,\mathrm{m}\times\sin(1°)\approx10.5\,\mathrm{mm};同样误差落在末端短骨时影响小得多。因此压缩器在采样时刻重建完整姿态,用末端位置和接触误差筛选候选,单看局部角度无法保证握持质量。抽样只覆盖有限时刻,关键帧之间也要加密检查,尤其是非均匀采样和高曲率动作。

数值量化

动画值可映射到有限位宽。平移在动画片段或区段的最小值和最大值范围内量化;单位四元数可保存最大绝对值分量的索引、其余三个分量及必要符号。解码时由单位长度约束求缺失分量的绝对值:sqrt(max(0,1-x*x-y*y-z*z)),再恢复符号;编码也可先把最大分量翻为正数,省略该符号。量化可能让平方和略超一,截零只是数值回退,解码后仍需归一化并检查误差。

分段量化比整段动画片段使用一个范围更精确,但每段需要额外 Header。压缩是在精度、随机访问、解码速度和元数据之间取舍。

四元数还要统一半球。qq 与 −q-q 表示同一旋转,但直接插值会走长路径。编码前可先保证相邻关键帧点积非负。若每个压缩记录又独立把最大分量翻成正数,最大分量身份改变时仍可能重新翻转整体符号;解码后插值必须再次按两端点积选择等价短弧,不能把预处理的符号连续当作所有压缩格式都能保留的保证。

平移轨道解码

轨道将每个分量编码为 16 位归一化整数,输入是轨道范围与量化值,输出使用与原轨道相同的长度单位。

cpp
Vec3 DecodeTranslation(U16Vec3 quantized, Vec3 minimum, Vec3 maximum)
{
    Vec3 normalized = Vec3(quantized) / 65535.0f;
    Vec3 extent = maximum - minimum;
    return minimum + normalized * extent;
}

常量轨道单独编码。一个轴的最大舍入误差约为范围除以 2 * 65535,但骨骼层级会放大旋转误差,因此运行验收仍需看末端位置和根运动。分段量化缩小范围,也增加元数据和解码寻址成本。

采样率与变长时间轨道

固定帧率采样访问简单,也便于 SIMD 解码。可变关键帧时间能删除更多冗余帧,却需要查找相邻关键帧。

动作快慢不同,不应全库使用相同压缩误差。手部交互、武器轨迹和面部口型通常比远景 NPC Idle 更敏感。压缩配置应按动画类型、角色 LOD 和目标平台分级。

流送与运行时解压

长过场或大量动作不一定全部常驻。动画片段可按区段流送,只保留当前和即将播放区间。

运行时关注:

  • 解压是否产生临时分配;
  • 关节数据是否按遍历顺序连续;
  • 多角色是否重复解压相同动画片段时间;
  • Job/Task 粒度是否足够大;
  • 动画 LOD 是否降低更新频率、骨骼数和面部通道。

降更新频率后可以在渲染帧间插值姿态,但快速动作和根运动不能简单跳帧。

验证方法

  • 比较压缩前后的手脚末端、根运动和关节旋转误差。
  • 分别测量解码 CPU 时间、临时分配、动画片段包体和运行内存。
  • 固定帧率与变帧率路径用同一播放时刻对比。

相关主题

参考资料

  • Animation Compression Library:Goals 与 Performance metrics:质量、解码速度和存储的评估维度。链末端误差算例由正文独立推导。