Continuous collision detection (CCD) ensures that fast-moving bodies collide with objects instead of passing, or tunnelling, through those objects. Unity provides the following CCD methods:
要使用基于扫掠的 CCD,请在 Inspector 窗口中选择一个刚体 (RigidBody),并将 Collision Detection 设置为 Continuous 或 Continuous Dynamic 。要使用推断性 CCD,请将 Collision Detection 设置为 Continuous Speculative 。
基于扫掠的 CCD 采用撞击时间 (TOI) 算法,通过扫掠对象的前向轨迹来计算对象的潜在碰撞(采用对象的当前速度)。如果沿对象移动方向有接触,该算法会计算撞击时间并移动对象直至达到该时间。该算法可从该时间开始执行子步骤,即计算 TOI 之后的速度,然后重新扫掠,代价是需要经历更多的 CPU 周期。
然而,因为此方法依赖于线性扫掠,所以会忽略物体的角运动,这在对象迅速旋转时会引起穿隧效应。例如,弹球机上的弹球杆固定在一端,围绕一个固定点旋转。弹球杆只做角运动,不做线性运动。因此,很容易打不中弹球:
此方法的另一个问题是性能问题。如果附近有大量启用 CCD 的高速对象,CCD 的开销将由于进行额外的扫掠而很快增加,因此物理引擎不得不执行更多的 CCD 子步骤。
推断性 CCD 的工作原理是基于对象的线性运动和角运动增大一个对象的粗筛阶段轴对齐最小包围盒 (AABB)。该算法是一种推测性的算法,因为会选取下一物理步骤中的所有潜在触点。然后将所有触点送入解算器,因此可确保满足所有的触点约束,使对象不会穿过任何碰撞。
下图显示了从 t0 开始移动的球体如何获得预期的 t1 位置(如果其路径中没有墙)。通过使用目标姿势将 AABB 扩大,推测性算法选取与 n1 和 n2 法线之间的两个触点。然后,该算法告诉解算器遵循这些触点,使球体不会穿过墙壁。
基于当前速度并扩大的 AABB 有助于检测沿运动轨迹的所有潜在触点,使解算器能够防止对象穿过去。
推测性 CCD 的成本通常低于基于扫掠的方法,因为只在碰撞检测阶段(而不在求解和积分阶段)计算触点。此外,由于推测性 CCD 根据对象的线性运动和角运动来扩展粗筛阶段 AABB,因此能发现基于扫掠的 CCD 可能遗漏的触点。
但是,推测性 CCD 可能会导致幽灵碰撞;在这种碰撞中,对象的运动受到推测性触点的影响,而这是不应发生的。这是因为推测性 CCD 根据最近点算法收集所有潜在触点,所以触点法线不太准确。这通常会使高速对象沿着细分的碰撞特征滑动并跳起来,但不应该这样。例如,下图中,球体从 t0 开始向右水平移动,积分后的预测位置为 t1 。扩大后的 AABB 与框形 b0 和 b1 重叠,而 CCD 在 c0 和 c1 产生两个推测性触点。由于推测性 CCD 使用最近点算法来生成触点, c0 具有非常倾斜的法线,因此解算器会将其视作斜坡。
这种非常倾斜的法线导致 t1 在积分后向上跳动,而不是笔直向前移动:
推测性 CCD 还可能导致发生穿隧,因为只会在碰撞检测阶段计算推测性触点。在触点求解过程中,如果一个对象从解算器获得太多能量,在积分后,其最终位置可能在初始扩大的 AABB 之外。如果在紧邻 AABB 的外部发生碰撞,对象会从右边穿出。
例如,下图显示了球体从 t0 向左移动,而球杆顺时针旋转。如果球体从撞击中获得太多能量,最终可能离开扩大的 AABB(红点矩形),落在 t1 处。如果在紧邻 AABB 的外部发生碰撞(如下面的蓝色框所示),球体最终可能会从右边穿出。这是因为解算器只计算扩大的 AABB 的内部触点,在求解和积分阶段不会执行碰撞检测。