实时物理模拟讲解 · 写给图形程序、技术美术和想自己动手的人

从 PBD
到 GNN + XPBD

布料、绳子、软体,本质上都是一堆点和一堆规则:这两点之间的距离要保持,这几点围成的体积要守恒。这门课从“为什么硬的东西难模拟”讲起,推出 PBD 和 XPBD,讲完约束、碰撞、子步和并行,带你写一个自己的 XPBD 布料;然后引入图神经网络,讲清楚网络和求解器怎样分工。

7 个页签 · 10 章 + 两个附录 · 61 节 · 10 个可以动手调的交互图

交互图这片珠帘是在你的浏览器里用 XPBD 实时算出来的。用指针推它,再调柔度和子步数。

00比喻

这片珠帘每一帧在做什么

封面那片珠帘是 17 根绳子、204 个质点。它没有任何关于“绳子”的知识,只有两条规则:每个质点受重力往下掉;相邻两点之间的距离要保持静止长度(打开弯曲约束时,隔一个点的两点之间也要保持距离)。

每一帧,程序做三件事。第一,预测:假装没有任何边,每个点按自己的速度和重力往前走一步。第二,修正:挨个检查每一段,被拉长了就把两端往里拉,被压短了就往外推,碰到球就推出球外。第三,反推速度:用这一帧的实际位移除以时间,作为下一帧的速度。

这就是基于位置的动力学(Position Based Dynamics,PBD)和它的改进版 XPBD 的全部骨架。整门课都在回答这三步里藏着的问题:为什么不直接算力?修正量怎么分给两端?“硬”和“软”怎么控制?修正的顺序有没有关系?一帧算不完怎么办?

你在封面上调的两个参数,正好对应后面两个关键概念:柔度(第 3 章)决定一段绳子有多容易被拉长;子步(第 4 章)决定一帧被切成几小段来算。

预测、按约束修正、用位移算速度:XPBD 的一帧就这三步,其余都是细节。

要点

预测、按约束修正、用位移算速度:XPBD 的一帧就这三步,其余都是细节。

00速查

术语表:这门课会反复出现的词

词一句话在哪一章展开
质点有位置、速度、质量的点。布料、绳子、软体都被离散成质点2.1 节
逆质量 w1/m。固定点的 w = 0,修正量按 w 分配2.3 节
约束 C(x)一个标量函数,等于 0 表示规则被满足,比如 |x₁ − x₂| − L2.2 节、第 5 章
投影把位置挪到满足约束的地方,挪动量尽量小、按质量分配2.2 节
迭代把所有约束挨个投影一遍叫一次迭代2.4 节
柔度 α刚度的倒数,单位 m/N(距离约束)。α = 0 表示完全不可伸长3.1 节
拉格朗日乘子 λ每个约束在这一步里累积的“力 × 时间²”,XPBD 靠它记住已经施加了多少力3.2 节
子步把一帧切成 n 段,每段完整地预测、投影、更新速度第 4 章
残差当前解离方程的解还差多少,用来判断收敛3.6 节
高斯-赛德尔 / 雅可比逐个投影并立即使用新位置 / 全部算完再一起应用2.4 节、7.1 节
图神经网络(GNN)在图上运行的网络:节点沿边交换消息,更新自己的状态第 8 章
滚动(rollout)把网络的输出当作下一帧的输入,连续推很多帧8.5 节

表里的公式符号不需要现在记住。每个词第一次正式出场时,都会先用一句白话说清楚它是什么。

看到不认识的词,回到这张表;看到“x.y 节”,点目录就能跳过去。

要点

看到不认识的词,回到这张表;看到“x.y 节”,点目录就能跳过去。

00路线

怎么读:三条路线

全课 7 个页签,前 5 个讲 XPBD,后 2 个讲 GNN 和组合。按你的目标选一条路线:

只想弄懂原理:页签 1 → 2 → 3,读完第 3 章就能讲清楚 XPBD 比 PBD 好在哪里。交互图都动手拖一拖,比读公式快。

要自己写一个:按顺序读完页签 1 到 5,然后照着附录 A 的八个里程碑写。每个里程碑都有完成标准,附录末尾有坑表和验证清单。

关心学习方法:至少读完第 2、3 章和第 7.1 节(理解迭代和并行),再读页签 6、7。第 9 章的每一种组合,都默认你知道 XPBD 的投影和 λ 是什么。

每节末尾有一句加粗的收束句。只想快速复习,可以只看这些句子。公式可以用右上角的“公式”按钮隐藏,白话解释始终保留。

先 XPBD 后 GNN:不懂求解器在保证什么,就分不清网络该负责什么。

只想弄懂原理

:页签 1 → 2 → 3,读完第 3 章就能讲清楚 XPBD 比 PBD 好在哪里。

要自己写一个

:按顺序读完页签 1 到 5,然后照着附录 A 的八个里程碑写。

关心学习方法

:至少读完第 2、3 章和第 7.1 节(理解迭代和并行),再读页签 6、7。

要点

先 XPBD 后 GNN:不懂求解器在保证什么,就分不清网络该负责什么。

01

为什么难:刚度和时间步

硬的东西难模拟,不是因为算得慢,而是因为显式积分在大刚度、长步长下会发散。

3 节

开场那片珠帘里,每一段绳子都想保持自己的长度。最直接的写法是把每条边当成弹簧:拉长了就产生拉力,按牛顿定律算加速度,再一步步积分。

这一章说明这种写法为什么在游戏里走不通:越硬的弹簧需要越小的步长,而游戏一帧只有 16 毫秒。然后引出另一种思路:不算力,直接改位置。

1.1交互图

一根弹簧怎样把模拟炸掉

最直观的模拟写法:把每条边当成弹簧,拉长了产生拉力 F = −k·Δx,按 a = F/m 算加速度,然后积分。最简单的积分叫显式欧拉:用这一刻的速度更新位置,用这一刻的加速度更新速度。

下面这个交互图只有一根弹簧、一个质点,初始拉开 1 个单位放手。真实的答案是永远以振幅 1 来回振动。三种积分方法各算 3 秒:

交互图调大刚度 k,看哪条线先失控;再加子步,看失控的线能不能被救回来。ω·h 是“每一步转过的相位”,它决定了稳定性。

显式欧拉不管刚度多小都会慢慢放大振幅,因为它每一步都在用“过时”的信息往前冲,能量只增不减。半隐式欧拉(先更新速度,再用新速度更新位置)好得多:只要 ω·h < 2 就稳定,其中 ω = √(k/m) 是弹簧的固有角频率,h 是步长。

问题在于游戏里的布料。一块布的质点只有几克重,边长几厘米,要“几乎拉不长”,k 得非常大。算一下:m = 0.01 kg,k = 10⁴ N/m,ω = 1000 rad/s。h = 1/60 秒时 ω·h ≈ 17,远超 2。要稳定,步长得小于 2 毫秒,一帧至少要切九次;k 再大十倍,就要切二十七次以上。

弹簧越硬、步长越长,显式积分越容易发散:硬度和帧率直接冲突。

数值积分的稳定性条件为标准结论;交互图为本页的数值实验

1.2推导

隐式积分:稳定,但每步要解一个大方程

经典的解法是隐式欧拉:用这一步结束时的力来更新速度,而不是开始时的力。

下一步的速度 = 这一步的速度 + 步长 × 下一步位置上的加速度;下一步的位置 = 这一步的位置 + 步长 × 下一步的速度。

vn+1 = vn + h · M−1 f(xn+1)  xn+1 = xn + h · vn+1

M
质量矩阵(对角线上是每个质点的质量)
f(x)
位置 x 上的总力,未知量 xn+1 出现在等号两边

未知量出现在等号两边,没法直接算,要解一个方程组。Baraff 和 Witkin 1998 年把它用在布料上,从此大步长布料模拟成为可能。它的优点是无条件稳定:步长再大也不会炸。

代价有两个。第一,每一步都要解一个规模等于自由度数量的线性方程组(非线性还要牛顿迭代),实现复杂,求解成本高。第二,隐式欧拉有数值阻尼:步长越大,能量损失越多,布料看起来像在糖浆里。你在 1.1 节的交互图里已经看到了:XPBD 那条线稳定但振幅在衰减,因为 XPBD 本质上就是在近似解隐式欧拉。

游戏需要的是:稳定、实现简单、每一步的成本可控,最好还能并行。这就引出了基于位置的思路。

隐式积分用解方程换来稳定;游戏需要更便宜、更简单的稳定方法。

Baraff & Witkin, Large Steps in Cloth Simulation, SIGGRAPH 1998;隐式欧拉的性质为标准结论

vn+1 = vn + h · M−1 f(xn+1)  xn+1 = xn + h · vn+1

下一步的速度 = 这一步的速度 + 步长 × 下一步位置上的加速度;下一步的位置 = 这一步的位置 + 步长 × 下一步的速度。

要点

隐式积分用解方程换来稳定;游戏需要更便宜、更简单的稳定方法。

1.3比喻

换个问题:不算力,直接改位置

回到那块布。我们其实并不关心每条边上的力具体是多少牛顿,我们关心的是结果:每条边的长度别偏离静止长度太多。

Müller 等人 2007 年的 PBD 论文就是从这个观察出发的:既然要的是“位置满足约束”,那就不经过“力 → 加速度 → 速度 → 位置”这条链,直接把位置挪到满足约束的地方,然后用位置的变化反推速度。

这样做有三个直接的好处。一,无条件稳定:投影只会把点往约束允许的方向挪,挪动量有界,不会像弹簧力那样越积越大。二,可控:想让某个点跟着骨骼走,直接把它的位置设过去,逆质量设为 0 就行。三,简单:每个约束独立处理,不需要组装和求解大矩阵。

代价也很明确,后面会一个个讲:硬度取决于迭代次数(2.5 节)、修正的顺序会影响结果(2.4 节)、速度是“反推”出来的,所以修正过的位移会变成速度(9.3 节会再遇到这个问题)。

PBD 跳过力,直接把位置投影回约束:稳定、可控、简单,代价是“硬度”变得不那么物理。

Müller et al., Position Based Dynamics, 2007

要点

PBD 跳过力,直接把位置投影回约束:稳定、可控、简单,代价是“硬度”变得不那么物理。

1 / 1