动画与模拟(求解常微分方程,刚体与流体)
上一章我们把动画与模拟放到了时间轴上:物体有位置、速度、质量、力和约束,系统会一帧一帧推进状态。本章继续往里走,看看“推进状态”到底意味着什么。
物理模拟的核心通常不是直接求出“未来某一刻的完美位置”,而是在当前状态已知的情况下,根据变化率一步步向前走。这会引出常微分方程、数值积分、稳定性、刚体和流体这些概念。
状态与变化率
Section titled “状态与变化率”在模拟里,状态可以是一组数字。例如一个二维质点可以用位置和速度描述:
状态 y = (x, v)如果知道力,就能得到加速度:
a = F / m于是状态的变化率可以写成:
dx / dt = vdv / dt = a这类“未知量随时间变化,变化率又由当前状态决定”的问题,就是常微分方程。图形学模拟大量依赖这种形式:弹簧、刚体、关节、粒子、布料、流体都可以看作状态随时间演化。
为什么不能总是直接求解析解
Section titled “为什么不能总是直接求解析解”有些简单运动可以写出精确公式,比如匀加速直线运动。但真实模拟往往更复杂:
- 力会随位置、速度和时间变化。
- 物体之间会发生碰撞。
- 系统里有大量相互连接的质点或刚体。
- 约束会反复修正状态。
- 用户输入和动画目标会不断改变。
因此实际系统通常使用数值积分。数值积分不追求一次性写出完整解,而是用很多小步近似连续运动。
已知当前状态根据变化率估计下一小步重复很多次得到随时间变化的运动这就是为什么同样的力学模型,换一个积分方法、时间步长或阻尼设置,画面观感可能完全不同。
显式欧拉方法
Section titled “显式欧拉方法”显式欧拉方法是最直观的积分方法。它用当前时刻的速度和加速度,直接估计下一时刻:
v_next = v + a * Δtx_next = x + v * Δt它的优点是简单、便宜、容易理解。缺点是稳定性较差,尤其是弹簧较硬或时间步长较大时,能量可能被错误地放大,系统会越抖越厉害。
显式欧拉适合教学和非常简单的效果,但在高刚度弹簧、布料、约束链条和碰撞密集场景中很容易出问题。
半隐式欧拉方法
Section titled “半隐式欧拉方法”半隐式欧拉也叫辛欧拉。它先用当前加速度更新速度,再用新速度更新位置:
v_next = v + a * Δtx_next = x + v_next * Δt这个小小的顺序变化会带来更好的能量表现。它仍然很便宜,却比显式欧拉更适合实时物理。很多游戏物理和粒子系统都偏爱这种思路。
它不是万能的。时间步长过大、刚度过高或约束处理不当时,仍然会发散。但在“成本、稳定性、实现复杂度”的平衡上,它非常常用。
Runge-Kutta 方法
Section titled “Runge-Kutta 方法”Runge-Kutta 方法会在一个时间步内多次估计变化率,再把这些估计组合起来。常见的四阶 RK4 可以理解成:
看一眼当前斜率看一眼半步后的斜率再看一眼另一个半步后的斜率最后看一眼整步后的斜率把这些信息加权平均RK4 通常比欧拉方法精度高,但每一步要多次计算变化率,因此更贵。它适合离线计算、镜头路径、较小规模系统或需要较高精度的场景。
在实时大规模模拟中,积分方法的选择经常不是“哪个数学上最好”,而是“在目标帧率和可接受误差下哪个最稳”。
隐式方法会使用下一时刻的信息来求解当前时间步。例如隐式欧拉可以粗略理解成:
下一状态要满足下一时刻的力和速度关系它通常更稳定,特别适合硬弹簧、布料和刚性约束。但代价是每一步可能要解方程组,实现和计算成本都更高。
在图形学里,隐式方法常用于离线模拟、电影级布料、大规模柔体或需要强稳定性的系统。实时系统有时会使用近似隐式、位置约束或多次迭代来换取稳定性。
交互辅助:积分方法与稳定性
Section titled “交互辅助:积分方法与稳定性”下面的小程序用同一个弹簧系统对比三种积分方式:显式欧拉、半隐式欧拉和 RK4。你可以调节时间步长和弹簧刚度,观察轨迹是否稳定、是否积累过多能量。
可以尝试:
- 增大时间步长,观察显式欧拉更容易把轨迹推大。
- 增大刚度,观察系统频率提高,对积分方法更挑剔。
- 切换是否显示参考圆,观察理想运动与数值轨迹之间的偏差。
- 把阻尼调低,观察数值误差更容易长期保留下来。
刚体是不会变形的物体。无论它如何运动,物体内部任意两点之间的距离都保持不变。
刚体状态通常包括:
- 位置。
- 线速度。
- 旋转姿态。
- 角速度。
- 质量和惯性张量。
质点只需要关心平移,刚体还要关心旋转。一个盒子被推到边缘时,不仅会移动,还会绕某个轴转起来。这个旋转来自力矩。
力影响线速度力矩影响角速度刚体模拟的核心是同时更新平移和旋转,并在碰撞时合理处理接触点、法线、摩擦和反弹。
同样大小的力,作用在不同位置会产生不同旋转效果。离质心越远,越容易让物体转动。
力矩 = 力臂 × 力惯性描述物体抵抗旋转变化的能力。质量分布越远离旋转轴,越不容易转起来,也越不容易停下来。一个细长杆和一个实心球即使质量相同,旋转响应也会不同。
在渲染和动画中,刚体模拟经常用于:
- 盒子、石块、碎片和道具掉落。
- 车辆、轮子和机械结构。
- 破碎效果中的刚体碎片。
- 角色和环境之间的物理交互。
碰撞与约束求解
Section titled “碰撞与约束求解”刚体模拟中,碰撞不仅要发现相交,还要计算如何修正速度和位置。
常见处理思路包括:
- 先用简单碰撞体快速筛选可能接触的物体。
- 计算接触点、接触法线和穿透深度。
- 根据质量、速度、摩擦和弹性计算冲量。
- 用冲量改变线速度和角速度。
- 通过迭代约束让多个接触同时趋向合理。
刚体求解器很少一次得到完美答案。它更像是在有限时间内不断修正错误,让结果足够稳定、足够可信。
流体模拟的直觉
Section titled “流体模拟的直觉”流体和刚体不同。刚体保持形状,流体会持续变形、混合和流动。水、烟、火焰、云雾都属于这一类问题。
流体模拟通常关注几个核心量:
- 速度场。 空间中每个位置的流动方向和速度。
- 密度或颜色。 烟雾浓度、墨水颜色或水体表面信息。
- 压力。 用来维持不可压缩流体的体积感。
- 粘性。 描述流体内部运动被平滑的程度。
- 边界条件。 墙面、容器、障碍物和开放边界如何影响流动。
流体比刚体难,是因为它不是少量物体的状态,而是空间中大量位置的状态。
欧拉视角与拉格朗日视角
Section titled “欧拉视角与拉格朗日视角”流体模拟常见两种视角。
欧拉视角把空间划分成网格,在每个格点或格子里保存速度、压力和密度。它像是在固定地点观察河水如何流过。
拉格朗日视角跟随粒子移动,每个粒子携带质量、速度和其他属性。它像是在给水滴贴上标签,观察它们去了哪里。
欧拉视角:空间固定,物质流过网格拉格朗日视角:粒子移动,空间随粒子采样烟雾和火焰常用网格方法,水花、沙粒和颗粒流常用粒子方法。现代系统也常混合二者,例如用粒子追踪细节,用网格求解压力。
不可压缩与压力投影
Section titled “不可压缩与压力投影”许多水体模拟会假设流体不可压缩,也就是局部体积不应凭空变大或变小。数学上,这通常要求速度场没有散度。
直观地说:
流入一个小区域的量 ≈ 流出这个小区域的量如果速度场让某些区域不断堆积或抽空,就需要通过压力修正速度。这个过程常叫压力投影。
- 加入外力。
例如重力、风力、浮力或用户扰动。 - 搬运速度和密度。
根据速度场把烟雾、水和颜色向前移动。 - 扩散或粘性处理。
让局部差异逐渐平滑。 - 求解压力。
找到能抵消压缩或膨胀趋势的压力场。 - 修正速度。
从速度场中去掉会造成体积变化的部分。 - 处理边界。
让流体不能穿墙,或按照开放边界流出场景。
模拟中的取舍
Section titled “模拟中的取舍”动画模拟很少只有一个“正确答案”。同一个场景可能有多种可接受方案:
- 想要稳定,就可能牺牲一些精度。
- 想要真实,就可能增加计算成本。
- 想要可导演,就可能加入非物理约束。
- 想要实时,就可能简化碰撞体、网格分辨率或迭代次数。
图形学模拟的目标通常不是复刻完整现实,而是在视觉、性能和控制之间找到合适平衡。
常见模拟问题
Section titled “常见模拟问题”调试模拟时,可以优先观察这些现象:
- 能量越积越多。 可能是显式积分、时间步长过大或约束注入能量。
- 物体抖动。 可能是碰撞法线变化、约束迭代不足或阻尼不合适。
- 物体穿透。 可能是时间步长过大、速度过高或碰撞检测太粗。
- 布料爆开。 可能是弹簧太硬、积分不稳定或约束没有收敛。
- 流体体积丢失。 可能是搬运误差、压力求解不足或边界处理不对。
- 结果每次不同。 可能是随机数、帧率依赖更新或并行求解顺序导致。
排查时不要只盯最终画面。要分别查看位置、速度、力、约束误差、碰撞点和每步 Δt,这样更容易找到问题来自哪里。
本章继续深入动画与模拟的数值基础:
- 模拟中的状态变化通常可以写成常微分方程。
- 数值积分用离散时间步近似连续运动。
- 显式欧拉简单但容易不稳定,半隐式欧拉常用于实时系统,RK4 精度更高但成本也更高。
- 隐式方法更稳定,但往往需要解方程组。
- 刚体保持形状不变,需要同时处理平移、旋转、力和力矩。
- 碰撞和约束求解通常依靠有限迭代逐步修正状态。
- 流体模拟关注空间中的速度、密度、压力和边界条件。
- 欧拉网格和拉格朗日粒子是理解流体的两种基本视角。
到这里,这套图形学主线已经完成了从“如何描述空间中的点和方向”,到“如何把几何、材质、光照、相机、颜色和时间组织成画面”的完整路径。后续如果继续自学,可以沿着角色动画、实时全局光照、物理仿真、GPU 计算和渲染器工程这些方向继续深入。