游戏中的力是交互的、无法事先预测的,运动方程(常微分方程)几乎没有解析解,所以物理引擎采用数值积分:以大致恒定的时间步长 Δt 逐步推进,由当前时刻 t1 的 r(t1)、v(t1) 和力函数 F(t,r,v) 求出 t2=t1+Δt 时的位置与速度。衡量方法好坏看收敛性、阶、稳定性三项。显式欧拉最简单但误差大、不稳定;GEA 认为交互游戏中最常用的大概是 Verlet,尤其是速度 Verlet(GEA4 卷 II 14.4.4)。
显式欧拉 (Explicit Euler)
新手最常写的方法:把"米每秒"乘以 Δt 变成"米每帧",加到当前位置上(卷 II 14.4.4.1):
r(t2)=r(t1)+v(t1)Δt(14.5),v(t2)=v(t1)+mFnet(t1)Δt(14.6)
两种理解:
- 线性外推:假设步内速度恒定,用 t1 处的斜率 v(t1) 直线外推到 t2(图 14.23)。速度大致恒定时效果尚可。
- 有限差分近似导数:把 dr/dt 换成 Δr/Δt,即 v(t1)≈t2−t1r(t2)−r(t1)。只在速度恒定或 Δt→0 的极限下精确成立。
数值方法的三项性质
(卷 II 14.4.4.2)
- 收敛性 (Convergence):Δt→0 时近似解是否越来越接近真实解。
- 阶 (Order):误差通常正比于 Δt 的某次幂,用大 O 记号表示;误差项为 O(Δtn+1) 的方法称为 n 阶方法。注意这里的 O(Δtn+1) 是单步(局部)截断误差;固定时间区间要走 T/Δt 步,累积的全局误差是 O(Δtn),这正是叫"n 阶"的原因(GEA 未区分两者;见 Wikipedia "Truncation error (numerical integration)"、Hairer/Nørsett/Wanner《Solving Ordinary Differential Equations I》II.3)。
- 稳定性 (Stability):数值解会不会随时间"平静下来"。方法往系统里加入能量,速度最终会"爆炸",系统不稳定;方法移除能量则有整体阻尼效果,系统稳定。
用泰勒展开求阶:精确解展开为
r(t2)=r(t1)+r˙(t1)Δt+21r¨(t1)Δt2+61r(3)(t1)Δt3+⋯
减去显式欧拉 r(t2)=r(t1)+r˙(t1)Δt,剩余误差 E=21r¨Δt2+⋯=O(Δt2),所以显式欧拉是一阶方法,可写成 r(t2)=r(t1)+r˙(t1)Δt+O(Δt2)。
其他方法
显式欧拉在游戏中常用于简单的积分任务(速度近似恒定时最好),但误差大、稳定性差,不用于通用动力学模拟。其他方法有后向欧拉(一阶)、中点欧拉(二阶)和 Runge-Kutta 家族,其中四阶 Runge-Kutta (RK4) 尤其流行。GEA 不展开这些方法,只建议从维基百科入手(卷 II 14.4.4.3)。
Verlet 积分
GEA 认为这是当今交互游戏中最常用的数值方法(卷 II 14.4.4.4)。普通 Verlet 的优点:阶高(误差小)、计算简单便宜、一步直接由加速度得到位置(不必先求速度再求位置)。推导:把向前和向后两个泰勒展开相加,奇次项相互抵消:
r(t1+Δt)=2r(t1)−r(t1−Δt)+a(t1)Δt2+O(Δt4)
其中 a(t1)=Fnet(t1)/m。式中没有速度;需要速度时可用一个不太精确的近似:v(t1+Δt)=Δtr(t1+Δt)−r(t1)+O(Δt)。
速度 Verlet (Velocity Verlet)
更常用。把时间步分成两半,已知 a(t1)=m1F(t1,r(t1),v(t1)),分四步(卷 II 14.4.4.5):
- r(t1+Δt)=r(t1)+v(t1)Δt+21a(t1)Δt2
- v(t1+21Δt)=v(t1)+21a(t1)Δt
- a(t2)=m1F(t2,r(t2),v(t2))
- v(t1+Δt)=v(t1+21Δt)+21a(t1+Δt)Δt
第 3 步需要下一步的位置和速度。位置已在第 1 步算出,力不依赖速度时信息就齐了;力依赖速度时(如阻尼),就要先近似下一帧速度,例如用显式欧拉。
同样的方法也用于角运动方程,见 刚体动力学。时间步长的选择与游戏循环的关系见 物理引擎与游戏的集成 和 游戏循环与更新方法。
GEA 原书中的问题
- 式 14.6 写作 v(t2)=v(t1)+mFnet(t)Δt,力的时间参数应为 t1(显式方法用的是当前时刻的力),与 14.4.5.5 二维角动力学的写法 Nnet(t1) 不一致(已核对渲染页:印刷页 378 式 14.6 确为 Fnet(t))。