想象你经营着一家“未来台球厅”,每颗台球都内置芯片,顾客击球后,球的位置、转速、碰撞、弹跳全部由电脑实时计算。球被球杆击中的瞬间,它会前进、旋转、撞到另一颗球后改变方向——顾客只会觉得“手感真棒”,但作为开发者,你看到的是另一幕:一个不断被拆解、计算、再拼装起来的世界。这颗球是刚体,那个镜头是物理引擎,而它背后要回答的问题,正是刚体动力学:如何描述不形变的物体,如何让力改变它的运动,如何检测碰撞、计算反冲,如何用离散的帧模拟连续的时间,以及怎样让整个场景在几十毫秒内算完。本文就用这颗台球做导游,带你走完游戏物理引擎最核心的那条主线。理解它之后,再看 Havok、PhysX 或 Bullet,你会发现它们只是“用了同一套台球规则的不同品牌球桌”。

岗位关联

对 AI 从业者而言,刚体动力学是读懂主流物理引擎、构建仿真环境、训练具身智能与自动驾驶策略的底层能力,是让 AI 从“看得见”走向“摸得着”的关键桥梁。

目录
  1. 可视化演示
  2. 刚体状态表达
  3. 牛顿欧拉方程
  4. 碰撞检测算法
  5. 碰撞响应与约束
  6. 数值积分方法
  7. 引擎优化选型
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

平动:F = m*a (牛顿第二定律) 6自由度:3平动(质心位置) + 3转动(绕质心旋转) 碰撞检测:宽相AABB + 窄相SAT 碰撞检测算法对比 转动:tau = I*alpha + omega x (I*omega) (欧拉方程) 冲量公式:J = -(...

刚体状态表达

台球游戏开场前,你要给摄像机一张特殊的“状态表”:每颗球现在的位置、朝哪个方向、有没有在旋转、下一秒大概往哪走。顾客看到的是流畅画面,但在引擎看来,世界是一帧一帧的快照,而快照的核心就是每个刚体的状态。

刚体是理想化的“不会形变的硬球”。现实中的台球碰撞时会有一点点凹陷,游戏中我们忽略这种弹性形变。因此,只要记住位置、朝向、线速度、角速度四个信息,就能完整描述一颗球“在哪儿、往哪儿去、转得多快”。

位置 p 是球心在三维空间中的坐标;朝向 q 常用四元数表示,可以避开欧拉角带来的“万向锁”问题;线速度 v 是球心每秒移动多少米;角速度 ω 是每秒绕自身轴旋转多少弧度。除了状态,物体还有质量 m 和惯量张量 I,它们不随状态改变,是“这台球有多沉、多难被转起来”的天生属性。

有了这张状态表,台球厅的电脑才知道该把球画在哪、往哪个方向滚。但状态不会自己变化,下一步我们要给球施加力——这就是牛顿欧拉方程的舞台。

s=(pqvω)\displaystyle \mathbf{s} = \begin{pmatrix} \mathbf{p} \\ \mathbf{q} \\ \mathbf{v} \\ \boldsymbol{\omega} \end{pmatrix}
状态向量就是引擎脑海里那颗球的“身份快照”:知道 p 和 q 就知道它在哪,知道 v 和 ω 就知道它怎么动。
  1. 位置向量 p记录球心在世界坐标中的三维位置,这是刚体的平移状态。
    p=(px,py,pz)\mathbf{p} = (p_x, p_y, p_z)
  2. 朝向四元数 q记录球的旋转姿态,四个分量可避免欧拉角的顺序歧义。
    q=(qx,qy,qz,qw)\mathbf{q} = (q_x, q_y, q_z, q_w)
  3. 线速度 v记录球心单位时间内位置的变化快慢。
    v=dpdt\mathbf{v} = \frac{d\mathbf{p}}{dt}
  4. 角速度 w记录绕自身旋转轴单位时间转过的角度。
    ω=dθdtu\boldsymbol{\omega} = \frac{d\theta}{dt}\mathbf{u}

牛顿欧拉方程

当你用球杆击中一颗台球,如果击在正中心,球只会直直滑出去;如果击在边上,球会带着旋转飞出去。区别不在球本身,而在于“力”是作用在质心,还是偏离质心。

物理引擎里的刚体运动由牛顿欧拉方程统治:所有外力合成为 F,F 决定线加速度;所有外力矩合成为 τ,τ 决定角加速度。线运动只关心质心,旋转运动则要抵抗惯量张量 I。惯量张量越大,就越难让物体转起来,就像同样推一个门轴,推门把手比推门中间更容易让门转动。

实际引擎每一物理帧干的事就是:收集重力、弹簧力、推进力等所有外力,累加成 F 和 τ,再用质量和惯量算出加速度,交给后面的积分器去更新速度。无论是台球、汽车还是机器人,这一套“合力到线加速度、合力矩到角加速度”的流程都通用。

球杆的每一次击打,都能拆成“质心平移力 + 改变旋转的力矩”。在代码里,这只是两次向量更新;在玩家眼里,却是台球被“打活”的瞬间。

a=Fm,α=I−1τ\displaystyle \mathbf{a} = \frac{\mathbf{F}}{m}, \qquad \boldsymbol{\alpha} = \mathbf{I}^{-1}\boldsymbol{\tau}
质量是“不愿意被推动”的程度,惯量张量是“不愿意被转动”的程度。
  1. 合力求线加速度把刚体受到的合外力除以质量,得到质心加速度。
    a=Fm\mathbf{a} = \frac{\mathbf{F}}{m}
  2. 合力矩求角加速度用惯量张量的逆矩阵乘以合力矩,得到角加速度。
    α=I−1τ\boldsymbol{\alpha} = \mathbf{I}^{-1}\boldsymbol{\tau}
  3. 线速度与角速度不断更新加速度要被积分成速度,速度再被积分成位置。
    v←v+aΔt,ω←ω+αΔt\mathbf{v} \leftarrow \mathbf{v} + \mathbf{a}\Delta t, \quad \boldsymbol{\omega} \leftarrow \boldsymbol{\omega} + \boldsymbol{\alpha}\Delta t

碰撞检测算法

台球桌上最让裁判紧张的时刻是两球相撞。如果裁判只看最终画面,球可能已经互相穿过;真正的流程是在物理步内提前发现“它们要撞了”。

引擎把碰撞检测分成两阶段:宽相先用粗糙包围盒把不可能的物体成对剔除,比如比较 AABB,或用空间哈希划分区域;窄相再对剩下的候选对做精确计算,得到接触点和法向。这就像台球裁判先扫一眼全场,只盯可能撞上的球对,再弯腰仔细看两个球是否真的碰到了。

对于两颗圆形球,窄相只需计算两球心距离是否小于半径和。对于 3D 凸体,常用 GJK 算法判断是否相交并返回最近点,再生成接触点。宽相追求“快”,窄相追求“准”,两者配合,才能让一个真实场景在上百个物体中快速找到有效碰撞。

拿到接触点和法向后,台球裁判就能判罚:这颗球该弹向哪里。接下来就是碰撞响应的工作。

∥c1−c2∥<r1+r2\displaystyle \|\mathbf{c}_1 - \mathbf{c}_2\| < r_1 + r_2
两圆心距离小于两个半径之和,就是球与球相撞的标志,像两个人的伞边碰到一起。
  1. 求圆心差向量从第一颗球球心指向第二颗球球心的向量。
    d=c2−c1\mathbf{d} = \mathbf{c}_2 - \mathbf{c}_1
  2. 取向量长度把差向量的长度作为两球之间的距离。
    d=∥d∥d = \|\mathbf{d}\|
  3. 与半径和比较若距离小于两半径之和,说明两球发生重叠。
    d<r1+r2d < r_1 + r_2

碰撞响应与约束

裁判不能只喊“碰了”,还要决定碰撞如何改变球。现实里两球在极短时间互相推挤,物理引擎不想模拟这种微观形变,它直接用一个“冲量”——力在极短时间内的累积效果——瞬间改变速度。

冲量大小由恢复系数 e 控制:e=1 是完美反弹,e=0 是撞上就粘住。公式里的 v_rel·n 是两球在法线方向上的相对靠近速度。除此之外,切向还要计算摩擦力,让球在碰撞后产生旋转和减速。摩擦与旋转,是台球“会走位”而不是像两块冰一样互滑的关键。

当桌上同时有十几颗球挤在一起时,接触点有几十个,它们彼此影响,不能一次解完。引擎使用接触约束求解器,例如 Projected Gauss-Seidel,迭代多轮,每轮把每个接触当成一个约束来修正速度,逐步逼近一个稳定解。

这一套“冲量 + 迭代约束”就是台球厅裁判手里的秒表:每次碰撞都掐表给一个干脆利落的速度修正。搞定单次碰撞后,剩下的问题是如何把连续时间切成物理帧。

j=−(1+e)(vrel⋅n)m1−1+m2−1,v′=v±jmn\displaystyle j = \frac{-(1+e)(\mathbf{v}_{\mathrm{rel}}\cdot\mathbf{n})}{m_1^{-1}+m_2^{-1}}, \qquad \mathbf{v}' = \mathbf{v} \pm \frac{j}{m}\mathbf{n}
冲量像裁判在接触瞬间吹了一声哨:它不改变位置,只改变速度方向。
  1. 计算法向相对速度把两球相对速度投影到接触法线 n 上,得到“相互靠近”的速度分量。
    vn=(v2−v1)⋅nv_n = (\mathbf{v}_2 - \mathbf{v}_1)\cdot\mathbf{n}
  2. 计算冲量大小 j负号表示推开,e 控制反弹程度,分母让质量小的球更容易被弹开。
    j=−(1+e)vn1m1+1m2j = \frac{-(1+e)v_n}{\frac{1}{m_1}+\frac{1}{m_2}}
  3. 应用冲量更新速度沿法线方向给两球各加或减一份速度。
    v1′=v1−jm1n,v2′=v2+jm2n\mathbf{v}_1' = \mathbf{v}_1 - \frac{j}{m_1}\mathbf{n}, \quad \mathbf{v}_2' = \mathbf{v}_2 + \frac{j}{m_2}\mathbf{n}

数值积分方法

台球厅的高速摄像机并不能真正连续计算,它每隔 1/60 秒拍一张照片。物理引擎做的事,就是根据当前状态和加速度,推算出下一张照片里球应该在哪里。

最直觉的方法是显式欧拉:先更新位置,再更新速度。它简单,但误差会累积,甚至会慢慢把能量“吹”进系统,让台球越弹越高。游戏物理更常用半隐式欧拉:先计算新速度,再用新速度更新位置。位置和速度互相追赶,稳定性显著提升,是 PhysX 和 Havok 等引擎最常用的基础积分器之一。

某些更精密的场景会使用更高阶的 RK4 四阶龙格-库塔法,它对轨道模拟更准确,但计算量更大。工程上还要求固定时间步长,并通过子步拆分来避免帧率抖动导致物理表现忽快忽慢。这是“手感”稳定的幕后功臣。

台球厅的每一帧画面,都是由这样一个“预测公式”推出来的。积分方法决定了球滑得顺不顺、弹得稳不稳。最后一个问题是:桌上有几十上百颗球时,如何让它们全都算得过来?

vn+1=vn+aΔt,pn+1=pn+vn+1Δt\displaystyle \mathbf{v}_{n+1} = \mathbf{v}_n + \mathbf{a}\Delta t, \qquad \mathbf{p}_{n+1} = \mathbf{p}_n + \mathbf{v}_{n+1}\Delta t
半隐式欧拉先用新速度更新位置,像跑步时先确认新步伐再迈出去,不容易跑飘。
  1. 用加速度更新速度把当前加速度乘以步长,加到旧速度上。
    vn+1=vn+aΔt\mathbf{v}_{n+1} = \mathbf{v}_n + \mathbf{a}\Delta t
  2. 用新速度更新位置这是半隐式欧拉与显式欧拉的关键差异。
    pn+1=pn+vn+1Δt\mathbf{p}_{n+1} = \mathbf{p}_n + \mathbf{v}_{n+1}\Delta t
  3. 继续下一帧把新状态作为下一帧的起点,循环执行积分。
    pn←pn+1,vn←vn+1\mathbf{p}_n \leftarrow \mathbf{p}_{n+1}, \quad \mathbf{v}_n \leftarrow \mathbf{v}_{n+1}

引擎优化选型

台球厅高峰期有几十组客人同时打球,但并不是每张桌子都值得一直盯着。一颗已经停稳的球,不需要每一帧都重算;一颗在角落里睡着的球,更可以在它醒来前彻底忽略。于是引擎学会了“睡眠”。

如果一颗球的线速度、角速度和动能长期低于阈值,引擎就把它标记为睡眠;一旦有约束把它撞醒,再重新激活。更进一步,球与球之间的接触会连成“孤立岛”,不同孤岛之间没有物理联系,可以并行求解。多核 CPU 与 GPU 把这些岛分配到不同线程或批次,极大提升吞吐量。

选型时,PhysX 凭借 Unity/Unreal 生态和 GPU 加速广受欢迎;Havok 以稳定和高效闻名,常出现在大型动作游戏中;Bullet 开源免费,适合科研与定制。无论哪个引擎,底层都跑着上面讲的同一套刚体动力学规则,只是工程实现各有取舍。

从一颗球到一张球桌,再到几十张球桌,刚体动力学像一套分工明确的台球厅管理手册:登记状态、分析受力、判定碰撞、修正速度、逐帧结算,最后让睡着的球休息。读懂这套逻辑,你就拿到了解读 PhysX 与 Havok 的钥匙。

Ek=12m∥v∥2+12ωTIω\displaystyle E_k = \frac{1}{2}m\|\mathbf{v}\|^2 + \frac{1}{2}\boldsymbol{\omega}^T\mathbf{I}\boldsymbol{\omega}
动能是判断睡眠的体温计:当球的“体温”持续很低且稳定,就可以让它睡一会儿。
  1. 计算平移动能质量乘线速度平方的一半,代表球“平移”的能量。
    Elin=12m∥v∥2E_{lin} = \frac{1}{2} m \|\mathbf{v}\|^2
  2. 计算旋转动能角速度与惯量张量共同贡献,代表球“旋转”的能量。
    Erot=12ωTIωE_{rot} = \frac{1}{2}\boldsymbol{\omega}^T\mathbf{I}\boldsymbol{\omega}
  3. 与阈值比较若总动能持续低于阈值,则把刚体标记为睡眠。
    Ek=Elin+Erot<εE_k = E_{lin} + E_{rot} < \varepsilon

AI 应用场景

自动驾驶仿真环境构建

阶段:物理仿真环境构建

解决的问题:真实路测成本高、危险场景难以复现;刚体动力学引擎能够提供廉价、可重复、带真实碰撞反馈的仿真场景。

具体案例:训练无人车在模拟城市中变道时,车辆由多个刚体组成,轮胎与路沿、车辆与护栏之间用碰撞检测和接触约束求解。强化学习策略在仿真器里试错,每一次急刹或碰撞都来自刚体动力学给出的精确反馈。

机器人抓取强化学习

阶段:强化学习经验生成

解决的问题:机械臂夹取物体时,需要视觉感知与物理动作联动;若缺少刚体动力学,物体可能被“手穿模”式抓取,策略学到不真实的动作。

具体案例:使用 PyBullet 这类基于 Bullet 的物理引擎训练机械臂抓取策略。机械臂关节施加力矩,物体在重力下落,被抓取时接触约束提供摩擦与反弹反馈,RL 模型通过数十万次交互学会稳定抓取。

Python 演示

python60 行
import math  class RigidBall:    def __init__(self, x, y, vx, vy, radius, mass=None):        self.pos = [x, y]        self.vel = [vx, vy]        self.radius = radius        self.mass = mass if mass is not None else radius * radius        self.inv_mass = 1.0 / self.mass     def step(self, dt, gravity=-10.0, floor=0.0):        self.vel[1] += gravity * dt        self.pos[0] += self.vel[0] * dt        self.pos[1] += self.vel[1] * dt        if self.pos[1] - self.radius < floor:            self.pos[1] = floor + self.radius            self.vel[1] = -self.vel[1] * 0.85  def resolve_collision(a, b, restitution=0.9):    dx = b.pos[0] - a.pos[0]    dy = b.pos[1] - a.pos[1]    dist = math.hypot(dx, dy)    min_dist = a.radius + b.radius    if dist >= min_dist or dist == 0:        return    nx = dx / dist    ny = dy / dist    overlap = min_dist - dist    a.pos[0] -= overlap * 0.5 * nx    a.pos[1] -= overlap * 0.5 * ny    b.pos[0] += overlap * 0.5 * nx    b.pos[1] += overlap * 0.5 * ny    rvx = b.vel[0] - a.vel[0]    rvy = b.vel[1] - a.vel[1]    vn = rvx * nx + rvy * ny    if vn > 0:        return    j = -(1 + restitution) * vn / (a.inv_mass + b.inv_mass)    a.vel[0] -= j * nx * a.inv_mass    a.vel[1] -= j * ny * a.inv_mass    b.vel[0] += j * nx * b.inv_mass    b.vel[1] += j * ny * b.inv_mass  def main():    balls = [RigidBall(-5 + i * 2, 1, i * 0.6, -2, 1, 2) for i in range(5)]    for frame in range(10):        for b in balls:            b.step(0.02)        for i in range(len(balls)):            for j in range(i + 1, len(balls)):                resolve_collision(balls[i], balls[j])        if frame % 2 == 0:            print([round(b.pos[0], 2) for b in balls])  if __name__ == "__main__":    main()
目的:用 5 个小球演示刚体动力学两个核心步骤:半隐式欧拉积分更新位置速度,以及基于冲量公式求解球与球之间的弹性碰撞。
  1. self.vel[1] += gravity * dt先更新速度,对应半隐式欧拉的第一步。
  2. self.pos[1] += self.vel[1] * dt用新速度更新位置,是半隐式欧拉的关键。
  3. if self.pos[1] - self.radius < floor碰撞检测:判断球是否越过地面。
  4. vn = rvx * nx + rvy * ny计算两球沿法线方向的相对速度。
  5. j = -(1 + restitution) * vn / (a.inv_mass + b.inv_mass)按冲量公式求出碰撞冲量大小。
  6. b.vel[0] += j * nx * b.inv_mass把冲量按质量倒数分配给被撞球。

常见误区

误区只要算出合力除以质量,就能预测刚体运动,旋转是额外附加的小问题。

正解刚体除了平移,还有旋转。旋转由力矩、惯量张量、角速度共同决定。两颗台球相撞后为什么有的前冲、有的带着旋转溜走,靠的正是牛顿欧拉方程里“力与力矩”两条腿走路。

为何常见:高中物理最常讨论质点的 F=ma,没有接触真实物体的旋转自由度,所以初学者很容易把刚体简化成点。

误区所有物体都应该在每帧对每个三角形做精确碰撞检测,这样才不会有穿模。

正解真实引擎如果全部精确检测,场景中数千个物体会产生天文数字的候选对。正确做法是先做宽相检测,用 AABB 或空间哈希快速筛掉不可能碰撞的物体,再对少数候选对做窄相检测,效率和精度才能兼得。

为何常见:在小场景 demo 中物体很少,宽相优化看起来毫无必要,因此容易被忽略。

误区物理帧率越高、步长越小,物理就一定越准,所以无脑增大计算频率就好。

正解步长缩小确实能降低单步误差,但计算成本线性上升,而且如果帧率不稳定,物体运动时快时慢。工程上更常见的是固定时间步长加子步,并用半隐式欧拉在 60Hz 下获得足够稳定的效果。

为何常见:人们只看到局部截断误差随步长变小,却忽略了工程性能与确定性要求。

误区只要把恢复系数设为 1,球就会永远弹性碰撞,永远不减速。

正解恢复系数只描述单次碰撞法向速度的比值,数值积分本身的离散误差、摩擦阻力以及穿透修正都会引入能量损失。游戏中通常还要加阻尼和角速度衰减,才能让球“停得自然”。

为何常见:公式看起来简洁,但连续时间方程在离散化后不会完美守恒,初学者容易把公式理想化。

误区碰撞是两个物体的事,一次解一组接触点就够了,迭代求解器没有必要。

正解当多颗球挤在一起,一个接触点会通过速度变化影响其他接触点。引擎需要把接触看成全局约束,用迭代法反复修正,让整个接触网络近似收敛。这就像开球瞬间裁判要同时处理十几颗球的连锁碰撞,不可能只处理其中一对。

为何常见:单独看两球碰撞很容易,但多个物体同时接触时,约束会互相耦合,问题复杂度远超直觉。

面试题

Q1. 物理引擎中的“刚体”最核心假设是下列哪一项?

单选题 · easy

  • A.物体的形状永远不会改变← 正确答案
  • B.质量会随速度变化
  • C.只能沿直线运动
  • D.永远不受重力影响

答案:A。刚体忽略形变,用来简化位置、旋转、速度等状态计算。质量保持不变、只沿直线运动、不受重力都不是刚体的定义,而是某些特定模拟的附加条件。

Q2. 下列哪一项通常不属于刚体状态变量?

单选题 · easy

  • A.物体的位置矢量
  • B.物体的线速度
  • C.物体的贴图颜色← 正确答案
  • D.物体的角速度

答案:C。贴图颜色属于渲染信息,不影响物理计算。位置、线速度、角速度才是引擎描述刚体当前运动状态的核心数据。

Q3. 与显式欧拉相比,半隐式欧拉积分的关键改进是什么?

单选题 · easy

  • A.先更新速度再更新位置← 正确答案
  • B.先旋转再平移
  • C.直接使用解析解
  • D.不需要设置时间步长

答案:A。半隐式欧拉用新速度更新位置,使位置与速度互相耦合,稳定性更好;显式欧拉用旧速度更新位置,容易发散。旋转、平移不分先后,解析解通常也不存在。

Q4. 在刚体碰撞冲量公式中,符号 e 表示什么?

单选题 · mid

  • A.摩擦系数
  • B.恢复系数← 正确答案
  • C.惯性张量
  • D.接触点个数

答案:B。恢复系数 e 控制碰撞后法向相对速度与碰撞前之比,e=1 为完全弹性,e=0 为完全非弹性。摩擦系数对应切向力,惯性张量描述旋转惯性。

Q5. 物理引擎中“宽相”检测主要用来做什么?

单选题 · mid

  • A.计算每个接触点的精确法向
  • B.较快筛出可能碰撞的候选对← 正确答案
  • C.求解所有接触约束的冲量
  • D.更新物体的位置和速度

答案:B。宽相用包围盒、空间哈希等廉价方法快速排除明显不会碰撞的物体对。精确法向是窄相的任务,求解冲量属于碰撞响应阶段。

Q6. 当场景中有大量接触点时,游戏引擎通常采用什么策略求解约束?

单选题 · mid

  • A.一次性形成线性方程组并求逆
  • B.迭代法逐步逼近可行解← 正确答案
  • C.随机挑选一个接触点忽略
  • D.只保留质量最大的物体

答案:B。真实引擎常用迭代求解器,每轮修正每个接触约束,反复迭代后近似收敛。一次性求逆在大规模场景中太慢,随机忽略和只保留大物体都会产生错误物理。

Q7. 下列哪些情况通常被用来判断刚体能否进入“睡眠”状态?

多选题 · mid

  • A.线速度大小持续低于阈值← 正确答案
  • B.角速度大小持续低于阈值← 正确答案
  • C.动能持续低于阈值← 正确答案
  • D.物体完全透明不可见

答案:ABC。睡眠机制通过速度、角速度、动能综合判断物体是否长期静止。透明度是视觉属性,与物理状态无关,不用于睡眠判断。

Q8. 下列哪种算法适合两个凸体之间的窄相碰撞检测?

单选题 · hard

  • A.空间网格哈希
  • B.AABB 包围盒求交
  • C.GJK 算法← 正确答案
  • D.光线投射

答案:C。GJK 专门用于两个凸体之间的相交检测,并能返回最近点信息。空间网格哈希和 AABB 包围盒常用于宽相筛选,光线投射则用于射线与物体求交。

Q9. 关于显式欧拉与半隐式欧拉,下列哪些说法正确?

多选题 · hard

  • A.时间步长越小通常越稳定← 正确答案
  • B.显式欧拉在弹簧系统中可能逐渐引入能量← 正确答案
  • C.半隐式欧拉使用新速度更新位置← 正确答案
  • D.时间步长越大求解越准确

答案:ABC。步长越小,数值误差通常越小;显式欧拉在振荡系统中可能“注入”能量,导致越弹越高;半隐式欧拉的核心是先更新速度再更新位置。D 与正确方向相反。

Q10. 关于 PhysX、Havok 等物理引擎的接触约束求解,下列说法哪些符合实际?

多选题 · extreme

  • A.把接触与关节统一成约束← 正确答案
  • B.使用迭代求解器求冲量← 正确答案
  • C.每次迭代尽量修正穿透和相对速度← 正确答案
  • D.单次求解就能完全消除穿透

答案:ABC。现代引擎会把接触、关节等统一为约束,用迭代方法逐轮修正速度和穿透。由于约束互相耦合,单次求解无法完全收敛,只能逐步逼近稳定解。