GPU Gems 1 · Chapter 4. Animation in the "Dawn" Demo

用 morph target 和索引蒙皮把 Dawn 的表情与身体变形卸载到可编程顶点流水线。

学习目标

  • 能解释为什么 Dawn 的网格变形通常放进顶点流水线,并判断哪些场景仍适合留在 CPU
  • 能用带权差分向量叠加 morph target,并说明位置、法线和遮蔽项为什么要同步变形
  • 能用四骨骼矩阵和归一化权重实现索引蒙皮,并说明累积矩阵如何减少重复矩阵乘法
  • 能调整表情差分与骨骼权重实验,预测两类参数各自会改变的几何结果

为什么 Dawn 的动画适合放到顶点流水线

Dawn 的展示目标是让高分辨率角色在实时画面中保持表情和身体动作。传统 CPU 变形会和物理模拟、AI 以及其他应用逻辑争夺预算;可编程顶点流水线可以在 GPU 上并行处理每个顶点,直接把变形后的姿态送进光栅化。

先预测:如果同一角色要被画入主画面、阴影缓冲区和辉光缓冲区,GPU 变形一定更便宜吗?不一定。若每次绘制都重复做顶点工作,或 CPU 必须遍历变形后的网格来找轮廓边,CPU 预变形可能更合适。本章的重点是建立一个可测量的选择模型,而不是把“GPU”当成答案。

网格变形放 CPU 还是 GPU?GPU 顶点阶段CPU 变形重复绘制、卸载 CPU需遍历网格、避免顶点瓶颈蒙皮 + morph target轮廓边、阴影体、特殊 pass按应用、对象与绘制次数测量,而不是凭口号选择
把网格变形放到 GPU 是默认方向,但阴影轮廓和多次重复绘制会改变成本模型。

1. morph target:把表情保存成差分

角色艺术家先制作一个中性头部,再制作许多目标头部。Dawn 的中性头部约有 27,000 个三角形,目标集合包含约 50 个副本:大约 30 个表达开心、悲伤、思考等情绪,另外约 20 个是抬眉、撇嘴等局部修饰。运行时不必把所有目标同时送进顶点寄存器,只需选择当前活跃的一小组。

可以写成中性位置加差分:

p=p0+iwiΔpi.p = p_0 + \sum_i w_i\Delta p_i.

权重不必加到 1。0.8 × happy + 1.0 × ear_wiggle 仍然是合理的叠加,因为它表达的是两个独立控制器的贡献,而不是二选一的插值。只有在两个关键帧之间插值时,才使用 p=(1-t)p_a+t p_b 这类互补权重。

Neutral + 加权差分 = 表情中性头部position + normal活跃差分happy × 0.8brow × 1.0smirk × 0.4ear × 0.2最多五个同时有效目标表情position + normal + occlusion每个目标存差分,`.w` 通道还能承载遮蔽差分
把表情存成相对中性姿态的差分向量,运行时按权重叠加;目标数量多不等于同时激活得多。

位置和属性必须一起变形

如果目标只保存位置差分,表情虽然改变了几何轮廓,却仍使用中性脸的法线;结果就是嘴角和眉毛的光照不跟随形状。原书让 morph target 同时影响位置与法线,再对中性切线做正交化,用新法线和切线的叉积恢复双切线。

当硬件只有有限的顶点输入寄存器时,数据布局必须和画质取舍一起设计。Dawn 最终选择最多五个同时修改位置和法线的活跃目标;50 个目标都存放在网格里,但每帧只把当前需要的通道映射为有效输入。

2. 在着色器中叠加 morph target

线性差分的实现很直接:先加载中性位置,再逐个执行 multiply-add。法线也做同样的差分叠加,最后归一化。切线不必为每个目标都单独存一份;如果模型不会绕法线发生严重扭转,可以将中性切线投影到新法线的正交平面:

t=normalize(t0(t0n)n),b=normalize(n×t).t' = \operatorname{normalize}\left(t_0 - (t_0\cdot n)n\right), \qquad b = \operatorname{normalize}(n\times t').

这里 不是数学装饰,而是让切线空间法线贴图继续有一致的基。缺少它时,表情越大,切线越可能和法线共线,片段阶段的细节光照就会扭曲。

原书还利用了差分向量 .w 分量通常不需要存几何信息这一事实,把基础自遮蔽和目标遮蔽差分塞进这些通道。这样眼睛或嘴巴开合时,遮蔽项也能随表情变化,而不必增加额外指令。

Dawn Animation Lab

先猜:表情差分和骨骼权重谁在改变什么?

可交互
morph target 表情同一顶点流水线左:差分叠加;右:矩阵加权

观察:表情滑杆只叠加形状差分;骨骼滑杆只改变关节矩阵的权重分配。

实验顺序:先把笑容差分调到 0,再只提高眉毛差分,最后调整肘部骨骼混合。观察几何改变的区域是否符合预期;点“显示权重”后,再解释右侧的数值为什么必须保持总和为 1。

3. 索引蒙皮:每个顶点由多根骨骼共同驱动

先为网格建立绑定姿态,再为每个顶点记录若干骨骼索引和对应权重。肩膀附近可能几乎只受肩骨影响;肘部则由肩和肘共同影响,使关节弯曲更连续。每个顶点的权重通常归一化为 1。

Dawn 使用 98 根骨骼驱动超过 180,000 个三角形的网格;单个顶点只需携带四个活跃骨骼索引和四个权重。 一起作为顶点属性传入,顶点着色器查出矩阵并加权相乘。

float4 skinPosition(float4 position, float4 indices, float4 weights,
                     float4x4 bones[98]) {
  float4 result = weights.x * mul(bones[indices.x], position);
  result += weights.y * mul(bones[indices.y], position);
  result += weights.z * mul(bones[indices.z], position);
  result += weights.w * mul(bones[indices.w], position);
  return result;
}

这段代码也必须用于法线、双切线和切线,但向量变换不能带平移。若层级含非均匀缩放,应对拼接矩阵使用 ;Dawn 的引擎选择禁止非均匀缩放,因此可以采用更简单的处理。

四骨骼加权蒙皮骨骼0.25骨骼0.50骨骼0.25顶点Σ weight = 1p′ = Σ wᵢ · (Mᵢ · p)位置、法线、双切线必须保持同一姿态,否则光照会滑脱
蒙皮不是选一根骨骼,而是让多个关节矩阵按权重共同决定顶点位置。

4. 累积矩阵:用一次变换换掉多组属性计算

直接蒙皮时,位置、法线、双切线和切线都要分别经过四根骨骼矩阵;这会重复很多点积和加法。原书介绍的 先计算:

Macc=iwiMi,M_{acc}=\sum_i w_iM_i,

之后每个属性只需乘一次 M_acc。构建累积矩阵本身要付出 16 次乘法和 12 次加法,但当同一顶点要变换多种属性时,可以减少重复的矩阵乘法。它不是无条件更快:若只变换位置,或者矩阵构建结果无法复用,额外的构建成本可能不值得。

5. 输入布局和性能取舍

当需要提高顶点性能时,可以按骨骼权重排序,截断很小的影响,再重新归一化剩余权重。这样改变的是近似精度,必须用关节边缘、肩膀和面部等高敏感区域做视觉验收。与其盲目把每个顶点从四骨骼减到两骨骼,不如先确认瓶颈是否真的在顶点阶段。

动画工具链也会影响实现:Dawn 的建模、贴图和动画主要在 Maya 中制作,同类方法也可迁移到其他内容工具。头部单独拆网格,让表情目标只作用于需要它的区域;头部边缘与身体共享相同的蒙皮权重,就能保持接缝无裂缝。

本章回顾:把变形拆成可验证的契约

  • morph target 用差分权重叠加表达表情,活跃数量受输入寄存器限制。
  • 位置、法线、切线和遮蔽项要保持同一变形姿态,才能继续正确着色。
  • 索引蒙皮用骨骼索引与归一化权重共同驱动顶点,四骨骼通常已够用。
  • 累积矩阵通过预先加权矩阵,减少多种顶点属性的重复变换。
  • CPU/GPU 位置要按对象和绘制场景测量,不能把展示 Demo 的选择当成通用规则。

练习

问题 1 改 Demo 代码:把实验中的笑容差分和眉毛差分都设为 0.8,再把肘部骨骼混合设为 0.5。说明哪些变化来自 morph target,哪些变化来自 skinning,并用“显示权重”验证。

问题 2 推导题:一个顶点受两根骨骼影响,权重为 0.250.75。若第一根矩阵把点变为 (2,0,0,1),第二根矩阵把点变为 (0,4,0,1),求线性蒙皮后的点。

问题 3 场景选型题:一个角色只在主画面绘制一次,另一个角色每帧还要被 CPU 遍历以生成阴影体轮廓。分别说明你会优先选择 GPU 变形还是 CPU 预变形,以及要测量什么。

名词解释

本章出现的专业名词,用大白话再讲一遍。

morph target
相对于中性姿态保存的差分形状,用权重叠加形成表情或局部修饰。
正交化
把切线中沿法线的分量去掉并重新归一化,让切线与新法线保持垂直。
索引蒙皮
用骨骼索引查矩阵,再按每个顶点的权重混合多个变换。
骨骼权重
表示一个顶点受某根骨骼影响程度的数值,通常所有权重加起来为 1。
骨骼索引
指向骨骼矩阵数组中某一根骨骼的编号。
逆转置矩阵
变换法线时保持垂直关系的矩阵,非均匀缩放时尤其重要。
累积矩阵蒙皮
先把多根骨骼矩阵按权重相加,再用一个结果变换多个顶点属性。
绑定姿态
给网格分配骨骼和权重时使用的中性参考姿态。
差分向量
目标姿态与中性姿态相减得到的位移或法线变化,运行时乘权重使用。
顶点输入寄存器
顶点着色器一次能直接读取的属性槽位,决定同时传入多少目标数据。

资料与写作方式声明

本章以GPU Gems 1 · Chapter 4. Animation in the "Dawn" Demo公开完整正文核定章节范围、事实坐标与时代语境,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…