碰撞响应与约束求解
Collision Response & Constraint Solving
刚体碰撞后,模拟必须让它们做出逼真的反应,并保证一步结束时不再互相穿透,这就是碰撞响应。主流方法有三种:基于牛顿恢复定律的冲量法、像硬阻尼弹簧一样的惩罚力、以及把碰撞当作约束交给通用约束求解器。此外还要处理摩擦、多边形汤上的伪接触(焊接),以及让物体安静下来(休眠与模拟岛)。约束(点对点、铰链、棱柱、布娃娃、动力约束等)限制刚体的自由度;每帧的物理步骤是"积分 → 碰撞检测 → 碰撞解决 → 约束求解"的迭代误差最小化(GEA4 卷 II 14.4.7–14.4.10)。
能量
力使物体移动一段距离即做功,功就是能量的变化:爆炸往系统加能量,摩擦从系统取走能量。势能 V 来自物体在力场(重力场、磁场)中的位置;动能 T 来自物体的运动。孤立系统的总能量 守恒(卷 II 14.4.7.1)。
冲量式碰撞响应
多数实时模拟用无摩擦瞬时碰撞的牛顿恢复定律近似真实碰撞中的压缩、回弹、声与热损失(卷 II 14.4.7.2)。三个假设:
- 碰撞力作用时间无穷短,是理想冲量,速度瞬间改变。
- 接触点无摩擦,冲量沿两表面的公共法线,没有切向分量。
- 复杂的微观作用用一个恢复系数 ε 概括: 是完全弹性碰撞(空中相撞的两个台球), 是完全非弹性(完全塑性)碰撞,两物体粘在一起沿原质心方向运动(两块油灰撞在一起)。
线动量守恒:;动能扣除损失项 后守恒。冲量 ( 指向物体 1),物体 1 受 ,物体 2 受 :
恢复系数联系碰撞前后的相对速度(式 14.10)。暂时假设物体不能旋转,联立解得
检验: 且物体 2 质量无穷大(如水泥车道,,)时,,,正是速度关于接触法线的反射。考虑旋转时要用两物体接触点的速度而非质心速度,GEA 不展开,推荐 Chris Hecker 的文章。
惩罚力
在刚刚穿透的接触点之间加一根虚拟的硬阻尼弹簧,在一段短而有限的时间内产生碰撞响应。劲度系数 控制穿透持续多久,阻尼系数 的作用类似恢复系数: 时无能量损失(完全弹性), 越大越接近塑性(卷 II 14.4.7.3)。
- 优点:好实现、好理解;三个以上物体同时互相穿透时依然稳定,而逐对解决很难处理这种情况(例:PS3 上把大量橡皮鸭倒进浴缸的演示)。
- 缺点:力响应的是穿透(相对位置)而非相对速度,高速时方向可能违反直觉。经典例子:矮轿车迎头撞上高卡车,惩罚力可能是竖直的,卡车车头被顶起,轿车钻到底下。
- 结论:适合低速撞击,高速时很差;可与其他方法组合,兼顾大量穿透时的稳定性和高速时的直观表现。
用约束解决碰撞
把碰撞当作"不允许穿透"的约束,直接交给模拟的通用约束求解器。只要求解器够快、效果够好,这就是一种有效方法(卷 II 14.4.7.4)。
摩擦
两个持续接触的物体之间阻碍相对运动的力(卷 II 14.4.7.5):
- 静摩擦:让静止物体开始滑动时感受到的阻力。
- 动摩擦:物体相对运动时的阻力;滑动摩擦是其中一种。
- 滚动摩擦:轮子等圆形物体与地面接触点处的摩擦。表面很粗糙时恰好使轮子纯滚不打滑,相当于静摩擦;较光滑时可能打滑,变成动摩擦。
- 碰撞摩擦:两物体运动中碰撞时,在接触点瞬间作用的摩擦,也就是牛顿恢复定律忽略的那部分。
- 约束也可以有摩擦,比如生锈的铰链产生阻碍转动的摩擦力矩。
斜面例子:重力 ,法向分量 ,摩擦力 ( 为摩擦系数),方向沿表面、与(试图的)运动方向相反。切向分量 ,合力 :括号内为零时匀速滑动或静止,大于零时加速下滑,小于零时减速直到停下。
焊接 (Welding)
物体在多边形汤上从一个三角形滑到相邻三角形时,碰撞检测会误以为它要撞上下一个三角形的边,产生伪接触(图 14.29)(卷 II 14.4.7.6)。两种解法:
- 用启发式规则(加上上一帧的接触信息)分析接触集合,丢弃看起来是伪接触的那些。Havok 4.5 之前用这种方法。
- 从 Havok 4.5 起给网格标注三角形邻接信息,系统"知道"哪些是内部边,可以可靠、快速地丢弃伪碰撞。Havok 称之为焊接:相当于把汤中三角形的边焊在一起。
静止、休眠与模拟岛
浮点误差、恢复力计算不准、数值不稳定都可能让物体永远抖动而停不下来。所以多数引擎用启发式方法检测"在振荡而不是在静止",然后额外移除能量,或在平均速度低于阈值时直接停住(卷 II 14.4.7.7)。
真正静止的物体不必每帧积分,可以休眠:暂时退出动力学模拟,但仍参与碰撞。有力或冲量作用于它,或它失去维持平衡的某个接触时,就会被唤醒。
常用的休眠判据:
- 有支撑:三个及以上接触点(或一个以上平面接触),能与重力等外力平衡。
- 线动量和角动量低于阈值。
- 线动量和角动量的滑动平均低于阈值。
- 总动能 低于阈值,通常按质量归一化,使所有物体共用一个阈值。
判据并不总可靠:长摆角动量很小,但屏幕上仍明显在动。即将休眠的物体可以逐步加大阻尼,平滑停下,避免突然定住。
模拟岛:Havok 和 PhysX 会自动把正在相互作用或即将相互作用的物体分组。各岛可独立模拟,利于缓存一致性优化和并行。两者都按岛整体休眠:收益更大,但岛内只要有一个物体醒着,整个岛就醒着。GEA 认为利大于弊。
约束
无约束刚体有 6 个自由度(三轴平移 + 三轴旋转)。约束部分或完全地减少自由度(卷 II 14.4.8)。例:摇摆的吊灯(点对点)、能被踹开、甩上、炸飞的门(铰链)、车轮总成(轴约束 + 阻尼弹簧悬挂)、火车或拖车(硬弹簧/杆)、绳索与链条(硬弹簧或杆链)、布娃娃(模仿人体关节的专用约束)。
| 约束 | 行为 |
|---|---|
| 点对点 (Point-to-Point) | 最简单,像球窝关节:一个物体上的指定点必须与另一个物体上的指定点重合 |
| 硬弹簧 (Stiff Spring) | 两点保持指定距离,像一根看不见的杆 |
| 铰链 (Hinge) | 旋转只剩绕铰链轴的 1 个自由度。无限铰链像车轴;有限铰链限制角度范围(原书:单向门 180°,双向门 ±180°,后者有误,见文末);可带摩擦力矩 |
| 棱柱 (Prismatic) | 像活塞,只剩 1 个平移自由度;可选是否允许绕轴旋转、是否有限、是否带摩擦 |
| 平面 (Planar) | 物体只能在一个二维平面内运动 |
| 车轮 (Wheel) | 通常是无限旋转的铰链,加弹簧-阻尼器模拟竖直悬挂 |
| 滑轮 (Pulley) | 虚拟绳索穿过滑轮连接两个物体,按杠杆比沿绳运动 |
- 可断约束:受力够大会自动断开,游戏也可以按自己的规则开关约束。
- 约束链:迭代求解器难以稳定模拟长链。约束链是一组附带连接信息的特化约束,让求解器更稳定地处理链条(卷 II 14.4.8.5–14.4.8.6)。
布娃娃与动力约束
- 布娃娃 (Rag Doll):模拟死亡或昏迷时完全瘫软的人体。每个半刚性部位一个刚体(脚、小腿、大腿、手、上臂、前臂、头用胶囊,躯干可能用几个以模拟脊柱弯曲),用模仿人体关节的专用约束相连,通常配合约束链提高稳定性(卷 II 14.4.8.7)。
- 布娃娃总是与动画系统紧密集成:从物理世界取出刚体的位置和旋转,驱动动画骨骼中对应关节的位置和朝向。所以布娃娃本质上是由物理驱动的程序化动画。难点:骨骼关节一般比布娃娃刚体多,需要一个"刚体 → 关节"的映射系统,并为中间关节求出正确的姿势变换。这不是精确科学,要靠艺术判断和人体生物力学知识。
- 动力约束 (Powered Constraint):让动画系统等外部系统间接控制布娃娃刚体(卷 II 14.4.8.8)。以肘关节为例,把它建模成有限铰链加旋转弹簧,力矩 ;让静止角 始终等于动画骨骼的肘角。没有其他力时刚体完全跟随动画;前臂碰到不可移动的物体时,它会以较逼真的方式偏离动画(图 14.34)。效果像一个人尽力按某种方式动作,却被物理世界限制(手臂挂住了东西)。补充:只有比例项 的纯弹簧会绕目标角来回振荡,书中"无其他力时刚体会精确跟随动画"需要加阻尼项(,即 PD 控制)并有足够刚度才近似成立(Wikipedia "Harmonic oscillator"、"PID controller")。与动画端的衔接见 动画约束与后处理。
控制刚体运动
游戏设计常要求在自然运动之外施加控制:通风口向上吹、汽车拖拖车、牵引光束、反重力装置、河流把漂浮物冲向下游(卷 II 14.4.9)。
- 重力:GEA 说重力"严格说不是力,而是(近似)恒定的加速度",对所有物体作用相同、与质量无关。这句与 14.4.7.5 把重量写成"重力产生的力 "并不一致:在牛顿力学中重力就是力(重量 ),只是它产生的加速度 与质量无关;说"重力不是力"是广义相对论的观点(Wikipedia "Weight"、"Gravity")。对引擎而言要点不变:SDK 存的是全局加速度 ,而不是对每个物体单独施加的力。多数 SDK 用一个全局设置指定它;太空游戏可以设为零。
- 施力:力总是作用一段有限时间。游戏中的力常每帧改变大小或方向,所以 SDK 的施力函数(如
applyForce(const Vector& forceInNewtons))设计为在力的作用期间每帧调用一次,持续时间假定为 。 - 施加力矩:作用线穿过质心的力只产生线加速度;偏离质心则同时产生线、角加速度。在与质心等距的两点施加等大反向的力(力偶),线性效果抵消,只剩转动(其实不必"等距":任意一对等大、反向、不共线的力都构成力偶,合力为零,力矩为 ,与参考点无关;见 Wikipedia "Couple (mechanics)")。SDK 可能提供
applyTorque(const Vector& torque),没有的话可以自己写一个,生成合适的力偶。 - 施加冲量:冲量是动量的瞬时变化,而时间步进模拟中最短的施力时长就是 ,不够短,模拟不了冲量。所以 SDK 提供
applyImpulse(const Vector& impulse)。好的 SDK 应同时提供线冲量和角冲量。
碰撞/物理步骤
GEA 见过最常见的每帧顺序(卷 II 14.4.10):
- 把作用在物体上的力和力矩向前积分 ,得到下一帧的暂定位置和朝向(见 数值积分)。
- 调用碰撞检测库,找出暂定运动产生的新接触。物体通常记录自己的接触以利用时间一致性,所以每步只需判断哪些旧接触消失了、哪些新接触出现了(见 碰撞检测系统)。
- 解决碰撞:施加冲量或惩罚力,或并入下面的约束求解。视 SDK 而定,这一步可能包含连续碰撞检测(CCD,也叫碰撞时间 TOI 检测)。
- 约束求解器满足各约束。
第 4 步可能把物体移离暂定位置,引起新的穿透或破坏已满足的约束,所以重复第 1–4 步(或只重复第 2–4 步),直到(a)碰撞全部解决、约束全部满足,或(b)超过最大迭代次数。后者相当于求解器"放弃",指望后续帧自然解决。这样把开销摊到多帧,避免性能尖峰;但误差太大、时间步太长或不一致时会显得不对。可以混入惩罚力,逐步消除这些问题。
约束求解器本质上是迭代的误差最小化算法:同时满足大量约束,使物体的实际位置和旋转与约束定义的理想值之间误差最小(卷 II 14.4.10.1)。
- 单个铰链:积分器给出两个物体的暂定变换,求解器计算公共转轴的误差并移动物体消除它;第二轮迭代没有新接触,约束已满足,循环退出。
- 多个约束:积分器会把物体推离约束,求解器再拉回来。设计得当的话,这个反馈环最终会收敛到有效解,但不一定精确。所以游戏里偶尔能看到链条被拉长、节间出现缝隙、物体短暂穿透、铰链短暂超出限位。目标是最小化误差,不一定能完全消除。
引擎差异:以上是简化描述(卷 II 14.4.10.2)。有些约束被建模为力和力矩,由积分步骤处理而不进求解器;碰撞可能在积分之前运行;碰撞解决方式也多种多样。要深入了解某个 SDK,应读它的文档,可能的话再看源码。GEA 建议从免费的 ODE 和 PhysX 入手,ODE 的 wiki 也很有用。
与 UE5 的对照
- UE5 文档列出的刚体动力学功能包括碰撞响应、约束、阻尼与摩擦(Physics in Unreal Engine),覆盖本节各主题。
- UE5 的物理资产用一组刚体加约束组成布娃娃,且不限于人形(Physics Asset Editor / Physics Bodies),与 GEA 14.4.8.7 的布娃娃结构一致。
- Chaos 破碎也有休眠机制:Sleep 场让刚体休眠,碰撞和场都能唤醒,对应 GEA 的休眠概念(Chaos Destruction Overview,UE 4.27 文档)。详见 Chaos 物理与碰撞。
GEA 原书中的问题
14.4.7.2 的推导有几处符号错误(2026-10-12 已逐一核对渲染页,印刷页 392–393):
- 式 14.9 第二式:写成 ,但上一行是 ,应为减号。本页已改正。
- 式 14.10:写成 。牛顿恢复定律应带负号,且只作用于法向分量:。按书中的写法, 时速度完全不变,与下文"反射"的结论矛盾。本页没有照抄书中原式。
- 反射推导:写成 ,应为 ;最后一步 多了一个 ,应为 。
- (2026-10-12 复核撤回:此前称 14.4.7.2 动能守恒式右侧 漏了平方;重读原文,两侧各项都带平方,是 PDF 文本提取把上标拆开造成的误读。再次核对渲染页 392 确认撤回正确。)
- 完全塑性碰撞的动能:14.4.7.2 两处说 时"两物体的动能全部损失""碰撞后动能之和为零",但同段又说两物体粘在一起"沿原质心运动方向继续运动",两者矛盾。由动量守恒,碰后共同速度 ,剩余动能 ,只有总动量为零时才为零;损失的是相对质心的那部分动能 (Wikipedia "Inelastic collision" 中 Perfectly inelastic collision 一节)。本页正文按"沿质心方向运动"表述。
- 图 14.27 与正文法线方向不一致:正文约定 指向物体 1、物体 1 受 ;而图中 的箭头指向左侧的 Body 2, 也画在 Body 2 一侧(看渲染页 392 所得)。本页按正文约定。
- 滚动摩擦:14.4.7.5 说表面很粗糙时"滚动摩擦恰好使轮子纯滚不打滑,相当于静摩擦"。这把两件事混在一起了:让轮子纯滚不打滑的是接触点的静摩擦;通常所说的**滚动摩擦(滚动阻力)**是轮子与地面形变、迟滞造成的阻碍滚动的力矩,即使纯滚也存在(Wikipedia "Rolling resistance")。
- 双向门 ±180°:14.4.8.3 说单向门只能转 180° 以免穿过相邻墙壁,"同样"双向门限制在 ±180°。按同一逻辑 ±180° 共 360°,门同样会穿墙;装在墙洞里的双向弹簧门通常是约 ±90°。本页约束表照录原书数字并附此说明。
- 其他:14.4.7.5 说碰撞摩擦是"在 14.4.7.1 讨论牛顿恢复定律时忽略的",但牛顿恢复定律在 14.4.7.2;14.4.7.3 的"Sony PS3 演示"是 PS3 时代的例子;PhysX/Havok 相关描述的时效见 游戏中的物理与中间件。
出处
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 14 章 14.4.7–14.4.10 节
- Physics in Unreal Engine
- Physics Asset Editor / Physics Bodies
- Chaos Destruction Overview