Math 实时计算碰撞-处理时间延迟

Math 实时计算碰撞-处理时间延迟,math,real-time,physics,Math,Real Time,Physics,假设: 您正在编写一个程序,其中3个(或更多)圆(或其他几何体)以不同的速度在屏幕上实时移动,由于物理计算,在某些时间可能会发生变化 计算只能在每一帧上进行 在每一帧中,您必须确保在这一帧和最后一帧之间发生“碰撞”/“碰撞”的圆将通过物理计算“反弹” 假设在帧x和帧x+1之间的时间内,三个圆将相互碰撞。但是,在第x帧期间,没有一个圆与另一个圆接触。在帧x+1中,应用相同的内容(无碰撞) 我将尝试用一幅图像更好地说明这一点: 问题: 有什么好方法可以像这样跟踪碰撞,这样碰撞就不会因为

假设:

  • 您正在编写一个程序,其中3个(或更多)圆(或其他几何体)以不同的速度在屏幕上实时移动,由于物理计算,在某些时间可能会发生变化

  • 计算只能在每一帧上进行

  • 在每一帧中,您必须确保在这一帧和最后一帧之间发生“碰撞”/“碰撞”的圆将通过物理计算“反弹”

  • 假设在帧x和帧x+1之间的时间内,三个圆将相互碰撞。但是,在第x帧期间,没有一个圆与另一个圆接触。在帧x+1中,应用相同的内容(无碰撞) 我将尝试用一幅图像更好地说明这一点:

问题:

有什么好方法可以像这样跟踪碰撞,这样碰撞就不会因为两帧之间的某些(意外)大延迟而被跳过

这个问题在我脑海里萦绕太久了

编辑:
对所有认为这篇文章是OT的人来说:在投票结束之前先看一看。

只在“框架”中评估事物的想法可能是不正确的

最古老的OO模式之一是“”——它鼓励将查看的内容(模型)与查看方式(视图)分离


物理引擎在模型对象上运行,因此将始终跟踪它们之间的交互作用。因此,当视图出现并询问“x+1帧”场景中每个圆的位置和方向时,它可以轻松回答,基于上次查看请求后经过的实时时间。

我知道您的问题指出,物理只能在每一帧进行评估,但我不知道什么时候会出现这种情况。在足够小的步骤中以增量方式更新物理,以避免对象完全绕过彼此,每一步一次,这将是非常简单的

但是,坚持显式更新方案(速度乘以时间步长)只适用于低速。正如在许多基于物理的游戏中所看到的,提高速度通常会导致穿透物体。 大多数简单的物理引擎选择只考虑这些bug,因为健壮性是众所周知的困难和昂贵的

如果将适用范围限制在圆形,那么可以做一些事情。书写对象的距离,作为时间的函数(在时间步长上)

如果距离函数
d_ab
等于时间步长内任何
t
的半径
r_a+r_b
之和,则发生碰撞。因此,首先检查哪些对象发生碰撞(如果有),然后从该点继续并重新进行分析,直到到达时间步长的末尾。非常复杂,仍然只适用于圆/球体。

要正确执行此操作:

  • 计算圆的精确碰撞时间,而不是舍入到下一帧:
    • 如果对象的移动距离超过1D,则需要查找根
  • 按如下顺序解决冲突:
    • 在上述精确碰撞时间停止模拟
    • 在第一次碰撞中解析圆的物理特性
    • 重新计算以确定由新轨迹引起的任何碰撞
    • 重新启动模拟
    • 重复此操作,直到到达帧的末尾而不发生碰撞为止
  • 物理上任何其他计划外的变化也需要更新即将发生的碰撞
您可能会注意到,这可能需要大量计算。如果你的球失去了动能,最终落在对方身上,情况可能会特别糟糕——如果你的物理特性让这成为可能,你需要为“静止接触”增加某种阈值(不幸的是,这会使你的物理特性变得非常复杂)


更新,回应评论:我想明确我的回答忽略了你的一个假设——如果你假装帧边界之间没有时间,你就无法准确地处理碰撞。碰撞不会发生在帧边界处;通常,碰撞将发生在帧边界之间,因此您的计算需要反映这一点

如果假设帧之间的所有运动都是线性的(即,模拟在帧边界上进行所有加速),那么确定是否发生碰撞、发生碰撞的位置和时间实际上非常简单。它将帧间“模拟”减少到几乎为零——即使模拟是二维或三维的,也可以以闭合形式求解方程:

posAB = posA - posB                [relative vector between circles A and B]
velAB = velA - velB                [relative velocity between circles A and B]
posAB(t) = posAB(0) + t * velAB    [relative vector as a function of time]
rAB = rA + rB                      [sum of radii of the two circles]
collision happens when distance(t) = abs(posAB(t)) == rAB
-> rAB^2 = | posAB(t) |^2 = | posAB(0) + t * velAB |^2
-> t^2 * |velAB|^2 + t * 2*posAB(0).velAB + |posAB(0)|^2 - rAB^2 == 0
solve quadratic equation for t:
   - if discriminant is negative, there is no collision.
   - if collision times are outside current timestep, there is no current collision.
   - otherwise, smallest t should be the correct collision time.
   - watch out for cases like 2 circles coming *out* of collision...

最后,听起来你好像在尝试进行过早的优化。最好是让事情正常运转,然后让它们快速运转;在运行代码之前,您不会知道实际的瓶颈。我还认为你实际上低估了现代计算机的能力。当然,你总是可以添加足够多的对象来让你的计算机陷入困境,但我想你会惊讶地发现需要这么多的对象……

这里碰撞检测的关键词是“连续”或“不连续”

正如其他一些答案所述,大多数现代碰撞库都使用非连续版本,因为分析许多碰撞形状的精确碰撞时间成本很高。这意味着让对象相互穿透,检测到这一点,然后调整它们的速度以对抗相互穿透。正如已经指出的,这允许快速移动的物体相互通过。这可以通过增加运行物理的频率来解决,本质上需要将物理与渲染分离(使用更快的计时器运行)。解决穿透分辨率的实际方法
posAB = posA - posB                [relative vector between circles A and B]
velAB = velA - velB                [relative velocity between circles A and B]
posAB(t) = posAB(0) + t * velAB    [relative vector as a function of time]
rAB = rA + rB                      [sum of radii of the two circles]
collision happens when distance(t) = abs(posAB(t)) == rAB
-> rAB^2 = | posAB(t) |^2 = | posAB(0) + t * velAB |^2
-> t^2 * |velAB|^2 + t * 2*posAB(0).velAB + |posAB(0)|^2 - rAB^2 == 0
solve quadratic equation for t:
   - if discriminant is negative, there is no collision.
   - if collision times are outside current timestep, there is no current collision.
   - otherwise, smallest t should be the correct collision time.
   - watch out for cases like 2 circles coming *out* of collision...