- 课程主讲:闫令琪 (Lingqi Yan) | UCSB
- B站课程链接:https://www.bilibili.com/video/BV1X7411F744
- 本章对应课件:第 21 讲(Animation 1: Basic Concepts, Mass-Spring Systems, Kinematics, Rigging / Blend Shapes / Motion Capture)、第 22 讲(Animation Cont.: Solving ODEs, Rigid Body and Fluids)
说明:前面十一篇处理的都是"静态"的问题——一个场景摆在那里,我们关心怎么把它算出来、画出来。这一篇换了个维度:让场景随时间动起来。动画和模拟表面上都在"生成运动",但走的是两条完全不同的路:动画是"描述运动"(人给出关键帧或关节角度,计算机负责插值),模拟是"推导运动"(人给出物理规律,计算机负责积分)。两条路在工程上会汇合到同一个地方——都要数值求解微分方程,也都可能因为离散化而崩溃。
1 动画基础 (Animation Basics)
动画 (Animation) 即"让事物活起来"(Bring things to life)。它既是通信工具(视觉信息的传达),也是建模的扩展(把场景模型表示为时间的函数),最终输出为一串按顺序观看时产生运动感的图像序列。
不同应用对帧率的要求
| 应用场景 | 帧率 (fps) | 说明 |
|---|---|---|
| 电影 | 24 fps | 传统电影标准 |
| 视频 | 30 fps | 一般视频标准 |
| 虚拟现实 (VR) | 90 fps | 高帧率防止眩晕 |
动画的历史发展
| 时间 | 事件 | 意义 |
|---|---|---|
| 3200 BCE | 伊朗陶碗动画 | 已知最早的动画 |
| 1831 | 幻透镜 (Phenakistoscope) | 早期动画装置 |
| 1878 | Muybridge “Sallie Gardner” | 第一部电影(科学工具) |
| 1937 | 迪士尼《白雪公主》 | 首部长篇手绘动画电影 |
| 1963 | Sutherland “Sketchpad” | 首个计算机生成动画 |
| 1972 | Catmull & Parke 计算机人脸 | 早期计算机动画 |
| 1993 | 《侏罗纪公园》 | 数字恐龙 |
| 1995 | 皮克斯《玩具总动员》 | 首部 CG 长片电影 |
| 2009 | 索尼动画《天降美食》(Cloudy with a Chance of Meatballs) | 十年前(相对当时)的计算机动画水准 |
| 2019 | 迪士尼《冰雪奇缘 2》(Frozen 2) | 2019 年的计算机动画水准 |
这张表其实是一个很直观的"摩尔定律"式观察:从上到下每格之间的技术跨度,大致与时间跨度成正比,而 1963 年的 Sketchpad 到 1995 年的《玩具总动员》用了三十年,1995 到 2019 只用了二十四年。
关键帧动画 (Keyframe Animation)
核心思想是把动画的制作分两层:
- 关键帧 (Keyframes):由主动画师创作的重要帧
- 中间帧 (Tweens):由助手或计算机自动生成的过渡帧(“tweening”)

关键帧插值的做法是把每一帧看作一个参数值的向量,对每个参数分别插值。线性插值通常不够好,需要使用样条 (splines) 进行平滑、可控的插值。

物理模拟 (Physical Simulation)
物理模拟的出发点是牛顿定律:
$$ \mathbf{F} = m\mathbf{a} $$其中 $\mathbf{F}$ 为力,$m$ 为质量,$\mathbf{a}$ 为加速度。基于物理的动画即使用数值模拟生成物体运动,例如从当前状态外推下一步:
$$ \mathbf{x}^{t+\Delta t} = \mathbf{x}^{t} + \Delta t \, \mathbf{v}^{t} + \frac{1}{2}(\Delta t)^2 \mathbf{a}^{t} $$常见的应用有三类:
| 应用 | 说明 |
|---|---|
| 布料模拟 | 用质点弹簧系统模拟织物 |
| 流体模拟 | 模拟水、烟等流体效果 |
| 绳索 / 毛发 | 弹簧链或质点系统 |

2 质点弹簧系统 (Mass Spring Systems)
质点弹簧系统是建模动态系统的经典方法:用弹簧连接质点,来模拟布料、绳索、毛发等。它大概是整个图形学里"投入产出比"最高的模拟方法——原理只有一条胡克定律,却能撑起布料、头发、软体一大片应用。
点的导数表示法 (Dot Notation)
设 $\mathbf{x}$ 为某个点的位置向量,用点号表示对时间的导数:
| 符号 | 含义 | 关系 |
|---|---|---|
| $\mathbf{x}$ | 位置 | — |
| $\dot{\mathbf{x}}$ | 速度 $\mathbf{v}$ | 位置对时间的一阶导数 |
| $\ddot{\mathbf{x}}$ | 加速度 $\mathbf{a}$ | 位置对时间的二阶导数 |
理想弹簧(胡克定律)
两个端点 $a$ 和 $b$,弹簧将两点拉向一起,力与位移成正比(胡克定律 Hooke’s Law):
$$ \mathbf{f}_{a \to b} = k_s(\mathbf{b} - \mathbf{a}) $$$$ \mathbf{f}_{b \to a} = -\mathbf{f}_{a \to b} $$其中 $k_s$ 为弹簧系数(刚度 stiffness)。

问题:理想弹簧的静止长度为零,会一直把两点拉到重合。
非零长度弹簧 (Non-Zero Length Spring)
引入静止长度 $l$ (rest length),弹簧在长度为 $l$ 时不施力:
$$ \mathbf{f}_{a \to b} = k_s \frac{\mathbf{b} - \mathbf{a}}{\|\mathbf{b} - \mathbf{a}\|} \left( \|\mathbf{b} - \mathbf{a}\| - l \right) $$公式可以拆成三部分看:
| 部分 | 含义 |
|---|---|
| $\frac{\mathbf{b} - \mathbf{a}}{\|\mathbf{b} - \mathbf{a}\|}$ | 从 $a$ 指向 $b$ 的单位方向向量 |
| $\|\mathbf{b} - \mathbf{a}\| - l$ | 当前长度与静止长度之差(标量) |
| $k_s$ | 弹簧刚度系数 |
问题:这样的弹簧会永远振荡(没有能量损失),因此需要引入阻尼。
内部阻尼 (Internal Damping)
最朴素的想法是直接加一个和速度成正比的阻力:
$$ \mathbf{f} = -k_d \dot{\mathbf{b}} $$这类似于粘性阻力,但它会减慢所有运动(包括整体的平移和旋转)——而我们只希望减慢弹簧驱动的内部运动,并不希望整体下落也变慢。
弹簧内部阻尼的做法是只对弹簧长度变化方向施加粘性阻力:
$$ \mathbf{f}_{a \to b} = -k_d \left( \frac{\mathbf{b} - \mathbf{a}}{\|\mathbf{b} - \mathbf{a}\|} \cdot (\dot{\mathbf{b}} - \dot{\mathbf{a}}) \right) \frac{\mathbf{b} - \mathbf{a}}{\|\mathbf{b} - \mathbf{a}\|} $$关键点:
- 阻尼力只作用于弹簧长度变化的方向
- 不会减慢弹簧系统的整体运动(如全局平移或旋转)
- $k_d$ 为阻尼系数
值得多看一眼这个式子:$\frac{\mathbf{b}-\mathbf{a}}{\|\mathbf{b}-\mathbf{a}\|}$ 是弹簧轴向单位向量,$(\dot{\mathbf{b}}-\dot{\mathbf{a}})$ 是两端点的相对速度。两者做点积,就取出了相对速度在弹簧轴向上的分量;再乘回单位向量,就把这个标量变回沿轴向的力。垂直于弹簧方向的相对速度(也就是整体旋转)被点积直接过滤掉了——这正是"只阻尼内部形变"的实现方式。
弹簧结构 (Structures from Springs)
按用途,弹簧结构可分为三大类:Sheets(片状,如布料)、Blocks(块状,如三维体)、Others(其他,如绳链等)。
弹簧的行为由其连接结构决定,不同结构具有不同的物理特性:
| 结构 | 抗剪切 | 抗弯曲 | 特点 |
|---|---|---|---|
| 结构 1(仅横竖连接) | 否 | 否 | 无法抵抗剪切和面外弯曲 |
| 结构 2(加对角线) | 是(有各向异性) | 否 | 可抗剪切,但有方向偏差 |
| 结构 3(双对角线) | 是(偏差较小) | 否 | 抗剪切更均匀,但仍不抗弯曲 |
| 结构 4(加跳跃连接) | 是 | 是 | 完整结构,红色的跳跃弹簧应弱很多 |

对应地有三种弹簧类型:
- 结构弹簧 (Structural Springs):横竖连接,维持基本形状
- 剪切弹簧 (Shear Springs):对角线连接,抵抗剪切变形
- 弯曲弹簧 (Bending Springs):跳跃连接(隔一个质点),抵抗面外弯曲,刚度应远小于前两者
最后这点容易被忽略:弯曲弹簧跨越的距离更长,若刚度与结构弹簧相当,整块布会硬得像铁皮。正因为要弱得多,它在结构图里才被画成红色这样"次要"的颜色。
应用示例
| 应用 | 说明 |
|---|---|
| 绳索 | 质点弹簧链模拟绳索 |
| 头发 | 弹簧链模拟毛发 |
| 布料网格 | 质点弹簧网格模拟织物,可结合数据驱动的弹性模型 |
| 裙装 + 角色 | 弹簧裙装与角色身体碰撞的综合模拟 |

有限元方法 (FEM)
除了弹簧系统,还可以使用有限元方法 (Finite Element Method, FEM) 来模拟弹性体。FEM 通过将连续体离散为有限个单元,直接求解偏微分方程,比质点弹簧系统更精确,但计算也更复杂。
3 粒子系统 (Particle Systems)
基本概念
粒子系统把动态系统建模为大量粒子的集合,每个粒子的运动由一组物理(或非物理)的力定义。
优点:
- 易于理解和实现
- 可扩展:粒子少则快,多则精细
挑战:
- 可能需要大量粒子(如流体)
- 可能需要加速结构(如查找邻近粒子用于交互)
粒子系统算法
每一帧动画的更新流程:
For each frame in animation:
1. [如果需要] 创建新粒子
2. 计算每个粒子上的力
3. 更新每个粒子的位置和速度
4. [如果需要] 移除死亡的粒子
5. 渲染粒子
注意这个循环里"创建"和"移除"是可选的——正是这两步的可选性让粒子系统能表达火焰、烟雾、浪花这类有生命周期的现象:粒子被发射、存活若干帧、然后消失。
粒子受力分析
| 力类型 | 示例 |
|---|---|
| 吸引 / 排斥力 | 重力、电磁力 |
| 弹簧力 / 推力 | 弹簧连接、推进器 |
| 阻尼力 | 摩擦、空气阻力、粘性 |
| 碰撞力 | 墙壁、容器、固定物体、动态物体、角色身体部位 |
引力 (Gravitational Attraction)
粒子间的引力服从牛顿万有引力定律:
$$ F_g = G \frac{m_1 m_2}{d^2} $$其中:
- $G = 6.67428 \times 10^{-11} \, \text{N}\cdot\text{m}^2\cdot\text{kg}^{-2}$(万有引力常数)
- $m_1, m_2$ 为两粒子质量
- $d$ 为两粒子间距离
应用示例:星系模拟(盘状星系模拟,NASA Goddard)。

群体模拟 (Simulated Flocking)
把每只鸟建模为一个粒子,受简单力作用,通过数值模拟演化大型粒子系统,就能产生涌现 (emergent) 的复杂行为:
| 力 | 作用 |
|---|---|
| 吸引 (attraction) | 向邻居中心吸引 |
| 排斥 (repulsion) | 远离过近的个体邻居 |
| 对齐 (alignment) | 朝向邻居的平均轨迹方向 |

这三种力各自都极其简单,但合在一起就产生了"鸟群"这种谁也没有单独设计过的整体行为。这种涌现行为在鱼群、蜂群等自然界中也能观察到。
其他应用示例
- 基于位置的流体 (Position Based Fluids):Macklin and Müller 用大量粒子配合密度约束模拟不可压缩水体
- 分子动力学:冰晶融化模型,通过粒子间相互作用展现冰融化为水的过程
- 人群模拟:Crowds + “Rock” Dynamics,大规模人群与"摇滚"动力学结合的粒子模拟

4 运动学 (Kinematics)
关节骨架 (Articulated Skeleton)

骨架由三件事描述:
- 拓扑结构:什么连接到什么(一般是树结构,无环时)
- 几何关系:由关节定义
- 关节类型:
| 关节类型 | 自由度 | 说明 |
|---|---|---|
| 销关节 (Pin) | 1D 旋转 | 绕轴旋转 |
| 球关节 (Ball) | 2D 旋转 | 任意方向旋转 |
| 棱柱关节 (Prismatic) | 平移 | 沿轴滑动 |
正向运动学 (Forward Kinematics)

核心思想:动画师提供关节角度,计算机确定末端执行器 (end-effector) 的位置。
以二维两段臂为例(注意:这里是 Z 轴向上的坐标系):
$$ p_x = l_1 \sin(\theta_1) + l_2 \sin(\theta_1 + \theta_2) $$$$ p_z = l_1 \cos(\theta_1) + l_2 \cos(\theta_1 + \theta_2) $$其中 $l_1, l_2$ 为两段臂的长度,$\theta_1, \theta_2$ 为关节角度。动画描述则是把这些角度参数值写成时间的函数。
| 优点 | 缺点 |
|---|---|
| 直接控制,方便 | 运动可能与物理不一致 |
| 实现简单 | 对动画师耗时 |
注意"Z 轴向上"这个前提很重要:由于 $\theta$ 是从 Z 轴量起的,第一段臂的分量写成 $(\sin\theta_1, \cos\theta_1)$ 而不是常见的 $(\cos\theta_1, \sin\theta_1)$。照抄习惯写法会让整个骨架躺倒 90°。

逆向运动学 (Inverse Kinematics)
核心思想:动画师提供末端执行器的位置,计算机必须确定满足约束的关节角度——正好和正向运动学反过来。

解析求解(两段臂):对两段臂这种简单结构,可以直接解析求解。由余弦定理可得:
$$ \theta_2 = \cos^{-1}\left(\frac{p_z^2 + p_x^2 - l_1^2 - l_2^2}{2 \, l_1 \, l_2}\right) $$数值求解方法:对于更复杂的骨架结构,通常无法解析求解,需要使用数值方法(如梯度下降、雅可比矩阵等迭代方法)。
| 方法 | 适用场景 |
|---|---|
| 解析法 | 简单结构(如两段臂) |
| 数值法 | 复杂结构,通用性强 |
IK 的难点:
- 可能存在多个解
- 可能无解(目标不可达)
- 数值方法可能收敛到局部最优
上面那个 $\cos^{-1}$ 的形式本身就暗示了第一个难点:$\theta_2$ 和 $-\theta_2$ 给出同一个 $\cos$ 值,对应"肘向上"和"肘向下"两个不同的姿势,计算机无从判断该选哪个——这通常要靠额外约束(比如关节角度范围)来消歧。
Style-Based IK(基于风格的逆运动学)
基于风格的逆运动学(Grochow et al., Style Based Inverse Kinematics, 2004)的思路是:不在原始关节空间里求解 IK,而是在从数据中学习得到的姿态空间里求解,使解符合特定角色的运动风格。这样"像不像这个人"就被编码进了求解的约束里。
Rigging(骨骼绑定)
Rigging 是角色上的一组高级控制,用于更快速、直观地修改姿势、变形和表情等。
| 要点 | 说明 |
|---|---|
| 类比 | 如同提线木偶上的线 |
| 覆盖范围 | 能捕获所有有意义的角色变化 |
| 因角色而异 | 每个角色需要单独绑定 |
| 创建成本 | 高——纯手工制作,需要艺术与技术的双重训练 |

Blend Shapes(变形形状)
Blend Shapes 不使用骨架,而是直接在不同表面之间插值:
- 典型应用:为一组面部表情建模,在表情表面之间直接插值
- 最简单方案:取对应顶点位置的线性组合
- 权重控制:权重随时间的变化可用样条控制

Motion Capture(动作捕捉)
定义:数据驱动的动画创作方法——记录真实世界的表演(如人物执行一项活动),并从采集的数据中提取姿态随时间的变化。
| 优点 | 缺点 |
|---|---|
| 可快速捕获大量真实数据 | 设备复杂、成本高昂 |
| 真实感可以很高 | 采集的动画可能不符艺术需求,需要再加工 |
设备分三类:
| 类型 | 原理 | 特点 |
|---|---|---|
| 光学 (Optical) | 反光标记 + 红外相机 | 主流方案,精度高 |
| 磁学 (Magnetic) | 感应磁场推断位置 / 朝向 | 需要系绳 (tethered) |
| 机械 (Mechanical) | 直接测量关节角度 | 限制运动 |

光学动捕细节:
- 在表演者身上粘贴回射反光标记 (retroreflective markers)
- 配合红外照明与红外相机
- 位置由多台相机三角测量确定
- 通常需要 8 台以上相机,采样率 240 Hz
- 遮挡 (occlusions) 难以处理

运动数据提取并非平凡任务:从采集的行走运动中提取出运动曲线的一个子集,就已经能看出其复杂性(Witkin and Popovic, 1995)——拿到一堆点云和拿到"可用的动作"之间隔着相当多的工作。
恐怖谷 (Uncanny Valley):在机器人与图形学中,当人工角色的外观接近人类真实感时,观众的情绪反应反而会变差,直到角色的表现力达到足够令人信服的真实水平。课件对比了卡通风格(《勇敢传说》,皮克斯)与半真实风格(《极地特快》,华纳兄弟)两类角色。
面部动作捕捉:《阿凡达》将面部动捕用于把演员表情映射到虚拟角色上。
The Production Pipeline(动画制作流程)
整部动画的工业流程是:先建模 (Modeling),再做绑定 (Rigging),随后通过动画 (Animation) 与模拟 (Simulation) 生成运动,最终渲染 (Rendering) 输出成品。

5 常微分方程求解 (Solving ODEs)
单粒子模拟
先研究单个粒子的运动,再推广到多粒子。
假设粒子的运动由速度向量场 $\mathbf{v}(\mathbf{x}, t)$ 决定(位置和时间的函数)。计算粒子随时间的位置,就是在求解一个一阶常微分方程 (ODE):
$$ \frac{d\mathbf{x}}{dt} = \dot{\mathbf{x}} = \mathbf{v}(\mathbf{x}, t) $$- “一阶”:只取一阶导数
- “常”:没有偏导数,$\mathbf{x}$ 只是 $t$ 的函数
给定初始位置 $\mathbf{x}_0$,通过前向数值积分求解。

显式欧拉法 (Explicit Euler / Forward Euler)

方法:简单迭代方法,常用但不精确,多数情况下不稳定。
$$ \mathbf{x}^{t+\Delta t} = \mathbf{x}^{t} + \Delta t \, \dot{\mathbf{x}}^{t} $$$$ \dot{\mathbf{x}}^{t+\Delta t} = \dot{\mathbf{x}}^{t} + \Delta t \, \ddot{\mathbf{x}}^{t} $$即用当前时刻的速度和加速度直接外推下一步的位置和速度。
误差与不稳定性
数值积分使用有限差分会导致两个问题:
1. 误差 (Errors):
- 每个时间步的误差累积
- 精度随模拟进行而下降
- 在图形学应用中,精度可能不是最关键的
2. 不稳定性 (Instability):
- 误差可以复合,导致模拟发散(即使底层系统不发散)
- 不稳定性是模拟中的根本问题,不可忽略
- 灾难性实例:PUBG(绝地求生)中载具物理因数值不稳定而发散的演示
误差来源:时间步 $\Delta t$ 越大,误差越大,越容易发散。
显式欧拉法简单但精度低(一阶),且对刚性方程和振荡系统容易不稳定。物理模拟中常用半隐式欧拉或 Verlet 替代,刚性场景则需要隐式方法。
对抗不稳定性的方法
| 方法 | 核心思想 |
|---|---|
| 中点法 / 修正欧拉 | 取起点和终点速度的平均 |
| 自适应步长 | 比较一步和两半步,递归直到误差可接受 |
| 隐式方法 | 使用下一时间步的速度(更难但更稳定) |
| 基于位置 / Verlet 积分 | 时间步后约束粒子位置和速度 |
中点法 (Midpoint Method)

步骤:
- 延伸最初的位置,计算欧拉步(得到中间预测位置)
- 计算中点处的导数
- 用中点导数更新位置
修正欧拉 (Modified Euler)
取步长起点和终点速度的平均,效果更好:
$$ \mathbf{x}^{t+\Delta t} = \mathbf{x}^{t} + \frac{\Delta t}{2}\left(\dot{\mathbf{x}}^{t} + \dot{\mathbf{x}}^{t+\Delta t}\right) $$$$ \dot{\mathbf{x}}^{t+\Delta t} = \dot{\mathbf{x}}^{t} + \Delta t \, \ddot{\mathbf{x}}^{t} $$代入消元后得到:
$$ \mathbf{x}^{t+\Delta t} = \mathbf{x}^{t} + \Delta t \, \dot{\mathbf{x}}^{t} + \frac{(\Delta t)^2}{2} \ddot{\mathbf{x}}^{t} $$这与物理中匀加速运动的位移公式完全一致。
自适应步长 (Adaptive Step Size)
自适应步长根据误差估计选择步长,非常实用但可能需要很小的步长。

算法:
重复直到误差低于阈值:
1. 用大小为 T 的欧拉步计算 x_T
2. 用两个大小为 T/2 的欧拉步计算 x_{T/2}
3. 计算误差 ||x_T - x_{T/2}||
4. 如果误差 > 阈值,减小步长并重试
优点:自动适应不同区域的精度需求。
缺点:可能需要极小的步长,计算量不可预测。
隐式欧拉法 (Implicit Euler / Backward Euler)
隐式欧拉法用下一时刻的导数更新状态,因此需要解隐式方程。它的精度只有一阶,但具有无条件稳定性,特别适合刚性方程和需要大步长的场景。与显式欧拉法的唯一区别就在于:用的是下一时刻的导数,而不是当前时刻的。
$$ \mathbf{x}^{t+\Delta t} = \mathbf{x}^{t} + \Delta t \, \dot{\mathbf{x}}^{t+\Delta t} $$$$ \dot{\mathbf{x}}^{t+\Delta t} = \dot{\mathbf{x}}^{t} + \Delta t \, \ddot{\mathbf{x}}^{t+\Delta t} $$求解方法:需要求解关于 $\mathbf{x}^{t+\Delta t}$ 和 $\dot{\mathbf{x}}^{t+\Delta t}$ 的非线性方程组,通常使用求根算法(如牛顿法)。
稳定性分析:使用局部截断误差(每步)和总累积误差(整体)来衡量:
| 误差类型 | 隐式欧拉 |
|---|---|
| 局部截断误差 | $O(h^2)$ |
| 全局截断误差 | $O(h)$ |
其中 $h$ 为步长(即 $\Delta t$)。$O(h)$ 的含义:如果步长减半,误差也大致减半。
显式和隐式在这里形成了一个很典型的权衡:隐式方法的每一步都贵得多(要求解非线性方程组),但允许的步长可以大得多;显式方法每一步便宜,但步长稍大就会炸。工程上选哪个,取决于问题有多"刚性"。
Runge-Kutta 方法 (RK4)
经典四阶 Runge-Kutta 方法 (RK4) 是数值求解常微分方程最常用的方法之一。它通过在一步内计算四次斜率并加权平均,达到四阶精度,在精度、稳定性和计算量之间取得了很好的平衡,特别擅长处理非线性问题。
初始条件:
$$ \frac{dy}{dt} = f(t, y), \quad y(t_0) = y_0 $$RK4 解:
$$ y_{n+1} = y_n + \frac{h}{6}(k_1 + 2k_2 + 2k_3 + k_4) $$$$ t_{n+1} = t_n + h $$其中四个斜率为:
$$ k_1 = f(t_n, \, y_n) $$$$ k_2 = f\left(t_n + \frac{h}{2}, \, y_n + h\frac{k_1}{2}\right) $$$$ k_3 = f\left(t_n + \frac{h}{2}, \, y_n + h\frac{k_2}{2}\right) $$$$ k_4 = f(t_n + h, \, y_n + h \, k_3) $$| 斜率 | 含义 |
|---|---|
| $k_1$ | 起点斜率 |
| $k_2$ | 中点斜率(用 $k_1$ 估计) |
| $k_3$ | 中点斜率(用 $k_2$ 估计) |
| $k_4$ | 终点斜率(用 $k_3$ 估计) |
RK4 的精度:局部截断误差 $O(h^5)$,全局截断误差 $O(h^4)$,远高于欧拉法。
权重的 $1:2:2:1$ 很有意思:两个中点斜率各占两倍权重,起点和终点各占一倍——这和辛普森积分公式的权重完全一样,并非巧合,两者都来自同一类高阶近似思想。
基于位置的积分 / Verlet 积分 (Position-Based / Verlet Integration)
思想:
- 在修正欧拉前向步之后,约束粒子位置以防止发散和不稳定行为
- 用约束后的位置反推速度
- 这两种操作都会耗散能量,从而稳定模拟
| 优点 | 缺点 |
|---|---|
| 快速简单 | 非物理基础,耗散能量(引入误差) |
6 刚体模拟 (Rigid Body Simulation)
刚体模拟是粒子模拟的简单扩展,只需考虑更多属性。
状态向量:
$$ \frac{d}{dt} \begin{pmatrix} \mathbf{X} \ \theta \ \dot{\mathbf{X}} \ \omega \end{pmatrix}
\begin{pmatrix} \dot{\mathbf{X}} \ \omega \ \mathbf{F}/M \ \Gamma/I \end{pmatrix} $$
| 符号 | 含义 |
|---|---|
| $\mathbf{X}$ | 位置 |
| $\theta$ | 旋转角度 |
| $\dot{\mathbf{X}}$ | 速度 |
| $\omega$ | 角速度 |
| $\mathbf{F}$ | 力 |
| $\Gamma$ | 力矩 (torque) |
| $M$ | 质量 |
| $I$ | 转动惯量 (moment of inertia) |
与粒子模拟的对比:
- 粒子只有位置和速度
- 刚体增加了旋转角度、角速度、力矩和转动惯量
- 求解方法与粒子完全相同(还是那些 ODE 求解器)
也就是说,第 5 节里辛苦学的那些积分器,在这里能原封不动地复用——只是"状态"从一个向量变成了一个更长的向量。
7 流体模拟 (Fluid Simulation)
基于位置的简单流体方法
核心思想:
- 假设水由小刚体球组成
- 假设水不可压缩(即密度恒定)
- 只要密度在某处发生变化,就通过改变粒子位置来"修正"
- 需要知道密度对每个粒子位置的梯度
- 更新方法:梯度下降

欧拉方法 vs 拉格朗日方法
模拟大量物质有两种不同视角,可以用一个摄影的类比来讲清楚:
| 方法 | 别名 | 核心思想 | 类比 |
|---|---|---|---|
| 拉格朗日方法 | 质点法 | 跟随每个粒子的运动 | 摄影师跟随同一只鸟飞过整个路程 |
| 欧拉方法 | 网格法 | 在固定网格上观察场的变化 | 摄影师固定不动,拍摄经过某一帧的所有鸟 |

拉格朗日方法:
- 模拟每个粒子(质点)的运动
- 自然追踪物质边界
- 适合粒子系统、SPH 等
欧拉方法:
- 在固定网格上观察物理量(密度、速度等)的变化
- 适合网格化的流体求解(如 Stable Fluids 方法)
- 不追踪具体物质,关注空间中的场
一句话总结两者的取舍:拉格朗日天然知道"水的表面在哪"(因为粒子在哪就画到哪),但粒子会散乱、难以维持均匀采样;欧拉天然保证网格均匀、便于求导,但要额外做界面追踪(如 level set)才知道自由表面在哪。
光滑粒子流体动力学 (SPH)
SPH (Smoothed Particle Hydrodynamics) 是一种拉格朗日方法:
- 用粒子表示流体
- 每个粒子携带质量、密度、速度等属性
- 通过核函数 (kernel function) 对粒子属性进行光滑插值
- 求解流体方程(Navier-Stokes 方程的离散形式)
优点:天然处理自由表面,并行性好。
Stable Fluids 方法
Stable Fluids 是一种欧拉方法,由 Jos Stam 提出:
- 在固定网格上求解流体方程
- 使用半拉格朗日方法对流
- 无条件稳定(任意大时间步都不会发散)
- 广泛用于游戏和视觉效果
物质点方法 (Material Point Method, MPM)
MPM 是一种混合方法,结合了欧拉和拉格朗日两种视角:
| 阶段 | 方法 | 操作 |
|---|---|---|
| 1. 粒子到网格 | 拉格朗日 | 粒子携带材料属性,转移至网格 |
| 2. 网格更新 | 欧拉 | 在网格上进行数值积分 |
| 3. 网格到粒子 | 插值 | 将更新后的属性插值回粒子 |

应用:雪、沙、弹性体等复杂材料的模拟。迪士尼《冰雪奇缘》中的雪效果即基于该方法。
(顺带一提,“粒子携带材料 → 搬到网格上积分 → 再搬回粒子”,这个来回的逻辑,正是它同时继承了两种方法的优点:粒子负责记住"这是什么材料"、天然处理拓扑变化,网格负责给出稳定、便于求导的数值环境。)
总结
这一篇覆盖了从"人描述运动"到"计算机推导运动"的完整谱系,可以按两条线索回顾:
按"谁来负责运动"分:
| 层次 | 方法 | 人负责 | 计算机负责 |
|---|---|---|---|
| 描述层 | 关键帧动画 | 关键帧与切线 | 插值中间帧 |
| 描述层 | 正向运动学 | 关节角度 | 末端位置 |
| 描述层 | 逆向运动学 | 末端位置 | 关节角度 |
| 数据层 | 动作捕捉 / Blend Shapes | 真实表演 / 表情基 | 重定向与混合 |
| 推导层 | 质点弹簧 / 粒子系统 | 力与约束 | 积分出运动 |
| 推导层 | 刚体 / 流体模拟 | 物理规律 | 数值求解 |
按"数值积分"分(这是本篇的技术核心):
- 显式欧拉:最简单,一阶精度,容易不稳定
- 中点法 / 修正欧拉:取平均斜率,明显改善
- 自适应步长:用误差估计动态调整 $\Delta t$
- 隐式欧拉:一阶但无条件稳定,代价是要解非线性方程
- RK4:四阶精度,精度与稳定的最佳平衡点
- Verlet / 基于位置:用约束和能量耗散换取稳定性
一个贯穿全文的结论:动画里"看得对"往往比"算得准"更重要。无论是 Verlet 主动耗散能量,还是 MPM 在两种视角间来回搬运,都在用物理精确性换取稳定性与可控性。这也解释了为什么图形学偏爱隐式和基于位置的方法,而科学计算偏爱高精度显式方法。
第 12 篇笔记
