动画是赋予3D模型生命力的关键技术。本章深入探讨网格动画的核心概念,从传统的骨骼动画系统到现代基于学习的方法。我们将详细分析权重计算、蒙皮算法、形变技术以及物理模拟,为读者提供完整的动画技术栈。无论是游戏角色、电影特效还是虚拟人,这些技术都是实现高质量动画的基础。
骨骼动画的核心是定义一个层次化的关节系统。每个骨骼(bone)实际上是两个关节(joint)之间的连接,通过父子关系形成树状结构。
根节点(Root)
├── 骨盆(Pelvis)
│ ├── 脊椎1(Spine1)
│ │ ├── 脊椎2(Spine2)
│ │ │ ├── 脊椎3(Spine3)
│ │ │ │ ├── 颈部(Neck)
│ │ │ │ │ └── 头部(Head)
│ │ │ │ ├── 左肩(LeftShoulder)
│ │ │ │ │ └── 左上臂(LeftUpperArm)
│ │ │ │ │ └── 左前臂(LeftForearm)
│ │ │ │ │ └── 左手(LeftHand)
│ │ │ │ └── 右肩(RightShoulder)
│ │ │ │ └── ...
│ ├── 左大腿(LeftThigh)
│ │ └── 左小腿(LeftCalf)
│ │ └── 左脚(LeftFoot)
│ └── 右大腿(RightThigh)
│ └── ...
每个骨骼维护两类变换矩阵:
全局变换通过递归计算得到: \(M_{global} = M_{parent\_global} \cdot M_{local}\)
对于根节点:$M_{root_global} = M_{root_local}$
绑定姿态(Bind Pose) 是网格与骨骼初始关联时的姿态,也称为T-Pose或A-Pose。在此姿态下,计算每个骨骼的逆绑定矩阵:
\[B_i^{-1} = (M_{bind\_global}^i)^{-1}\]动画时,顶点的最终变换为: \(v' = \sum_{i} w_i \cdot M_{current\_global}^i \cdot B_i^{-1} \cdot v\)
其中 $w_i$ 是骨骼 $i$ 对该顶点的影响权重。
解剖学准确性:人体骨骼应遵循真实的解剖结构,关节位置要准确。例如,肘关节应位于上臂和前臂的连接处,而非中间位置。
动画友好性:
拓扑优化:
辅助骨骼:不直接对应解剖结构,用于改善形变质量。如肩部的锁骨辅助骨、肘部的形变修正骨。
程序化骨骼:通过算法驱动的骨骼,如:
约束骨骼:受物理或逻辑约束的骨骼,如:
蒙皮权重决定了每个顶点受哪些骨骼影响以及影响程度。高质量的权重分布是实现自然形变的关键。
对于顶点 $v$,其权重向量 $\mathbf{w} = [w_1, w_2, …, w_n]$ 需满足:
最近骨骼法: 最简单的方法,将顶点分配给最近的骨骼: \(w_i = \begin{cases} 1 & \text{if } i = \arg\min_j d(v, bone_j) \\ 0 & \text{otherwise} \end{cases}\)
距离反比加权: \(w_i = \frac{1/d_i^p}{\sum_j 1/d_j^p}\) 其中 $d_i$ 是顶点到骨骼 $i$ 的距离,$p$ 是幂次参数(通常取2-4)。
热扩散法(Heat Diffusion): 通过求解热方程来计算权重分布: \(\Delta u + \lambda u = 0\) 边界条件:在骨骼 $i$ 上 $u = 1$,其他骨骼上 $u = 0$。 最终权重通过归一化各骨骼的热值得到。
测地距离考虑了网格的曲面结构,比欧氏距离更准确:
\[d_{geodesic}(v, bone) = \min_{p \in bone} \text{shortest\_path}(v, p)\]使用Dijkstra算法或Fast Marching Method计算测地距离,然后应用距离反比加权。
Voxel权重: 将网格体素化,通过洪水填充(flood fill)从骨骼开始扩散:
有界双调和权重(Bounded Biharmonic Weights): 求解约束优化问题: \(\min_W \sum_i \int_\Omega |\Delta w_i|^2 dV\) 约束条件:
手动绘制工具:
权重传递: 从高精度模型传递权重到低精度模型:
权重优化: 基于示例姿态优化权重分布: \(\min_W \sum_{pose} \sum_{vertex} ||v_{deformed} - v_{target}||^2\) 使用梯度下降或其他优化算法调整权重。
为了减少内存占用,常对权重进行压缩:
稀疏表示: 只存储非零权重及其索引:
struct SparseWeight {
uint8_t boneIndices[4]; // 骨骼索引
uint8_t weights[4]; // 量化权重(0-255)
};
权重量化: 将浮点权重量化为8位或16位整数: \(w_{quantized} = \text{round}(w \times 255)\) 反量化:$w = w_{quantized} / 255$
LBS是最广泛使用的蒙皮算法,通过线性组合变换矩阵来计算顶点位置。
基本公式: \(v' = \sum_{i=1}^{n} w_i M_i v\)
其中:
矩阵分解优化: 将变换矩阵分解为旋转、缩放和平移: \(M = TRS = \begin{bmatrix} R & t \\ 0 & 1 \end{bmatrix}\)
分别插值各分量可获得更好的效果:
Candy-wrapper效应: 当关节大角度旋转(如扭转180度)时,LBS会产生体积塌陷:
扭转前: 扭转后(LBS): 理想效果:
|||| >< ||||
|||| >< ||||
|||| >< ||||
体积损失: 在关节弯曲处,线性插值导致体积收缩:
DQS使用对偶四元数表示刚体变换,避免了LBS的某些缺陷。
对偶四元数表示: 一个对偶四元数 $\hat{q} = q_0 + \epsilon q_\epsilon$ 编码了旋转和平移:
DQS公式: \(\hat{q}_{blend} = \frac{\sum_i w_i \hat{q}_i}{||\sum_i w_i \hat{q}_i||}\)
变换顶点: \(v' = \hat{q}_{blend} \cdot v \cdot \hat{q}_{blend}^*\)
优势:
局限:
Optimized Centers of Rotation (CoR): 为每个顶点计算优化的旋转中心: \(c_v = \sum_i w_i c_i\) \(v' = c_v + R_{blend}(v - c_v)\)
Spherical Blend Skinning: 使用指数映射进行旋转插值: \(R_{blend} = \exp\left(\sum_i w_i \log(R_i)\right)\)
顶点着色器实现(GLSL示例):
attribute vec4 boneWeights;
attribute vec4 boneIndices;
uniform mat4 boneMatrices[MAX_BONES];
vec4 skinVertex(vec4 position) {
mat4 skinMatrix =
boneWeights.x * boneMatrices[int(boneIndices.x)] +
boneWeights.y * boneMatrices[int(boneIndices.y)] +
boneWeights.z * boneMatrices[int(boneIndices.z)] +
boneWeights.w * boneMatrices[int(boneIndices.w)];
return skinMatrix * position;
}
性能优化技巧:
Blend Shapes(也称为Morph Targets或Shape Keys)通过线性组合预定义的形状来实现形变,特别适合面部表情和精细变形。
基本公式: \(v' = v_0 + \sum_{i=1}^{n} w_i (v_i - v_0)\)
其中:
增量表示: 存储差异而非完整形状以节省内存: \(\Delta v_i = v_i - v_0\) \(v' = v_0 + \sum_{i=1}^{n} w_i \Delta v_i\)
面部动作编码系统(Facial Action Coding System): 基于解剖学的表情分解系统,定义了基本动作单元(Action Units):
每个AU对应一个或多个Blend Shape,复杂表情通过组合AU实现。
关键形状设计:
校正形状(Corrective Shapes): 当多个blend shapes同时激活时,简单线性组合可能产生不自然的结果: \(v_{corrective} = v_0 + w_A \Delta v_A + w_B \Delta v_B + w_A w_B \Delta v_{AB}\)
其中 $\Delta v_{AB}$ 是校正项。
主成分分析(PCA): 通过PCA降维减少存储需求:
稀疏编码: 许多顶点在特定blend shape中不移动,使用稀疏表示:
struct SparseBlendShape {
uint32_t vertexCount;
uint32_t* vertexIndices;
vec3* displacements;
};
流压缩: 对时间序列的blend shape权重进行压缩:
混合管线:
注意顺序很重要:先Blend Shapes后骨骼变换。
分区系统:
基于标记点的方法:
基于深度学习的方法:
ARKit/FaceTracking标准: Apple ARKit定义了52个标准blend shapes,包括:
物理模拟为动画增加真实感,特别是对于次要运动(如头发、衣物)和软体形变。
基本模型: 将网格表示为质点和弹簧的网络:
弹簧力计算: \(F_{spring} = -k(|x_i - x_j| - L_0)\frac{x_i - x_j}{|x_i - x_j|}\)
阻尼力: \(F_{damping} = -c(v_i - v_j)\)
运动方程: \(m_i \frac{d^2x_i}{dt^2} = F_{spring} + F_{damping} + F_{external}\)
PBD直接操作位置而非力,更稳定且易于控制:
预测步骤: \(x_i^* = x_i + \Delta t \cdot v_i + \Delta t^2 \cdot F_{ext}/m_i\)
约束投影: 迭代满足约束条件 $C(x) = 0$: \(\Delta x = -\frac{C(x)}{\sum_j \frac{1}{m_j}|\nabla_{x_j} C|^2} \nabla_x C\)
常见约束:
| 距离约束:$C = | x_i - x_j | - L_0$ |
FEM提供物理准确的弹性体模拟:
连续体力学基础: 应变张量:$\varepsilon = \frac{1}{2}(\nabla u + \nabla u^T)$ 应力张量:$\sigma = \mathbf{C} : \varepsilon$(胡克定律)
离散化: 使用四面体网格离散化物体,每个元素的弹性能量: \(E = \frac{1}{2}\int_{\Omega} \varepsilon : \mathbf{C} : \varepsilon \, dV\)
共旋转线性FEM: 处理大旋转的改进方法:
Verlet积分: 位置更新:$x_{t+\Delta t} = 2x_t - x_{t-\Delta t} + a_t \Delta t^2$
约束类型:
碰撞处理:
多段刚体链: 将每根头发建模为连接的刚体段:
引导曲线方法:
Level of Detail:
解剖学模型:
体积保持: 肌肉收缩时长度减少但体积不变: \(V = A \cdot L = \text{constant}\)
激活函数: \(F_{muscle} = f_{active}(\alpha) \cdot F_{max} \cdot g(l, \dot{l})\) 其中 $\alpha$ 是激活度,$g$ 考虑长度和速度关系。
问题定义: 传统LBS的局限性促使研究者探索基于神经网络的蒙皮方法。神经蒙皮学习从骨骼配置到顶点位置的非线性映射。
网络架构:
输入:骨骼变换矩阵 {M_i} + 顶点静态特征
隐藏层:多层MLP或图神经网络
输出:顶点偏移量 Δv 或直接输出变形后位置
训练数据生成:
损失函数: \(L = \lambda_1 L_{position} + \lambda_2 L_{smooth} + \lambda_3 L_{volume}\)
运动VAE(Motion VAE): 将动作序列编码到低维隐空间,实现:
条件动作生成: 给定高级控制信号(如路径、速度),生成相应动作: \(\theta_{t+1} = G(\theta_t, c_t; \phi)\) 其中 $G$ 是循环神经网络,$c_t$ 是控制信号。
可微物理模拟器: 将物理约束嵌入神经网络:
强化学习控制器: 训练策略网络控制角色运动:
Neural Blend Shapes: 使用神经网络表示blend shape基函数: \(v = f_{base}(x) + \sum_i w_i f_i(x; \theta_i)\)
动态NeRF: 时变辐射场表示动画: \(F(x, d, t) \rightarrow (c, \sigma)\) 添加时间维度 $t$ 捕捉动态变化。
神经纹理动画: 将动画信息编码在神经纹理中:
混合表示: 结合传统方法与神经网络:
端到端可微管线: 从动作捕捉到最终渲染的完全可微系统。
跨模态动画生成:
自适应细节层次: 根据视角、距离自动调整动画复杂度。
物理-神经混合模拟: 结合物理准确性和神经网络效率。
本章系统介绍了3D动画与绑定的核心技术:
关键概念回顾:
核心公式汇总:
| DQS蒙皮:$\hat{q}_{blend} = \frac{\sum w_i \hat{q}_i}{ | \sum w_i \hat{q}_i | }$ |
| PBD约束:$\Delta x = -\frac{C(x)}{\sum \frac{1}{m_j} | \nabla C | ^2} \nabla C$ |
实践要点:
练习14.1:骨骼层次遍历 给定一个骨骼层次结构,实现前序、后序遍历算法,并计算每个骨骼的全局变换矩阵。
Hint:后序遍历适合从叶节点向根传递信息(如IK),前序适合从根向叶传递变换。
练习14.2:权重归一化 一个顶点受5个骨骼影响,原始权重为[0.3, 0.25, 0.2, 0.15, 0.05]。如果限制每个顶点最多4个骨骼,如何处理?
Hint:考虑丢弃最小权重并重新归一化。
练习14.3:Blend Shape插值 有3个blend shapes:微笑(smile)、皱眉(frown)、张嘴(open)。当权重为[0.5, 0.3, 0.2]时,如何计算最终顶点位置?
Hint:使用线性组合公式。
练习14.4:简单弹簧系统 两个质点通过弹簧连接,原始长度L0=1.0,当前长度L=1.5,弹簧刚度k=100。计算弹簧力。
Hint:使用胡克定律F = -k * (L - L0) * dir。
练习14.5:DQS实现 推导对偶四元数插值公式,并分析为什么DQS能避免candy-wrapper效应。
Hint:考虑对偶四元数如何保持刚体变换特性。
练习14.6:校正形状设计 设计一个肘部弯曲的校正形状系统,解决90度弯曲时的体积损失问题。
Hint:分析弯曲时的形变模式,在关节内侧添加膨胀。
练习14.7:物理模拟稳定性 分析为什么显式欧拉积分在刚性弹簧系统中会不稳定,如何选择合适的时间步长?
Hint:考虑数值稳定性条件和CFL条件。
练习14.8:神经蒙皮架构 设计一个神经网络架构,输入骨骼变换和顶点特征,输出校正后的顶点位置。考虑如何保证时间连续性和物理合理性。
Hint:考虑使用残差连接和物理约束。
零长度骨骼:
循环依赖:
坐标系不一致:
权重和不为1:
负权重:
权重突变:
Gimbal Lock:
插值方向错误:
Blend Shape顺序依赖:
过多骨骼影响:
动态批处理失效:
CPU蒙皮:
时间步过大:
刚度过高:
穿透问题:
通过本章学习,读者应掌握从基础骨骼动画到高级物理模拟的完整技术栈,能够为不同需求选择合适的动画方案,并避免常见的实现陷阱。动画技术仍在快速发展,特别是AI驱动的方法,建议持续关注最新研究进展。