【问题标题】:Resolving a Circle-Circle Collision解决圆-圆碰撞
【发布时间】:2016-11-15 09:34:27
【问题描述】:

我正在编写扩展Circle-Rectangle collision detection (intersection) 的软件,以包括对碰撞的响应。圆边和圆矩形相当直接。但是一圈圈让我难住了。

例如,在离散事件模拟中让两个圆相撞,一个红色和一个绿色。我们可能会遇到以下情况:

它们碰撞后我们可以立即:

这里的 RIP 和 GIP 是上一个时钟滴答时圆圈的位置。在当前时钟滴答处,在 RDP 和 GDP 上检测到冲突。然而,当两个圆圈位于 RCP 和 GCP 时,时钟滴答之间发生了冲突。在时钟滴答声中,红色圆圈使 RVy 向下移动,RVx 向右移动;绿色圆圈向下移动 GVy,向左移动 GVx。 RVy 不等于 GVy; RVx 也不等于 GVx。

当圆心之间的距离小于或等于圆的半径之和时发生碰撞,即上图中d

这就是问题所在:我如何重新回到 CP。一些作者建议应用下图中 p 给出的一半穿透。

对我来说这是完全错误的。它假设两个圆的速度矢量相等,但在本例中并非如此。我认为渗透与计算有关,但我如何逃避。我确实知道这个问题可以重新定义为直角相似三角形问题,我们要在其中解决 Gcdy 和 GCdx。

碰撞本身将被建模为弹性,并且惯性交换的数学已经到位。唯一的问题是碰撞时圆圈的位置。

【问题讨论】:

  • 你在寻找什么样的碰撞?有弹性(没有能量损失)?无弹性(能量损失)?两个圆圈粘在一起并继续成对移动?
  • 这个问题似乎是题外话,因为它是关于物理而不是编程。
  • @john 碰撞将被建模为弹性。惯性交换的数学已经到位。问题在于圆圈的位置。
  • @tom10 问题与编写简单的离散事件动画有关。碰撞后定位圆将被合并到动画中。
  • @Gus:仅仅因为它最终会在程序中使用并没有提出关于编程的问题。题目是关于物理的,结果会在程序中使用。

标签: math geometry collision-detection


【解决方案1】:

“这就是问题所在:我该如何行动。”

您可能想知道如何“在调整圆的速度分量之前将 DP 定位回 CP。”

所以有两个问题,如何确定 CP(发生碰撞的位置)以及如何从该点调整圆圈的运动。第一部分有一个相当简单的解决方案(允许不同的半径和速度分量),但第二部分取决于是否对弹性或非弹性响应进行建模。在您写的评论中:

碰撞将被建模为弹性。惯性交换的数学 已经到位。问题在于圆圈的位置。

鉴于我将只解决第一个问题,解决发生碰撞的确切位置。假设两个圆匀速运动,知道碰撞发生的确切时间就足够了,即圆心之间的距离何时等于它们的半径之和。

对于匀速运动,通过从另一个圆(绿色)的速度中减去它的速度,可以将一个圆(红色)视为静止。实际上,我们将第一个圆的中心视为固定的,而仅考虑第二个圆处于(匀速)运动中。

现在通过求解一个二次方程可以找到确切的碰撞时间。令 V = (GVx-RVx, GVy-RVy) 为圆的相对运动,令 P = (GIPx-RIPx,GIPy-RIPy) 它们在碰撞前的“瞬间”中的相对位置。我们通过定义为相对位置 P“动画”了一条线性路径:

P(t) = P + t*V

并询问这条直线何时与以半径 Rr+Gr 为原点的圆相交,或者何时相交:

(Px + t*Vx)^2 + (Py + t*Vy)^2 = (Rr + Gr)^2

这是一个未知时间 t 的二次方程,所有其他涉及的量都是已知的。情况是这样的(碰撞发生在 CP 位置或之前)将存在正实解(通常有两种解,一种在 CP 之前,一种在之后,但可能是掠过接触,产生“双根”)。您想要的解(根)t 是较早的解,即 t(在“即时”RIP、GIP 位置为零)较小的解。

【讨论】:

    【解决方案2】:

    如果您正在寻找有关圆形物体非弹性碰撞的基本参考资料,Joe van den Heuvel 和 Miles Jackson 的 Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres 非常容易理解。

    从最不正式到最正式,这里有一些关于实现支持您的问题(冲突响应)解决方案的编程工艺的后续参考。

    您将不得不接受一些近似值 - 贝克曼在视频中演示了即使对于非常简单的情况,也无法通过分析预测会发生什么,这更糟,因为您正在模拟一个连续系统离散步骤。

    【讨论】:

      【解决方案3】:

      要以恒定速度重新定位两个重叠的圆,您需要做的就是找到发生碰撞的时间,并将它们的速度因子添加到它们的位置。

      首先,我们将考虑一个具有组合半径和相对位置和速度的圆,而不是两个圆移动。让输入圆的位置为P1P2,速度为V1V2,半径为r1r2。让组合圆有位置P = P2 - P1,速度V = V2 - V1,半径r = r1 + r2

      我们必须找到圆穿过原点的时间,换句话说,找到t 的值r = |P + tV|。应该有 0、1 或 2 个值,具体取决于圆是不通过原点、与原点相切还是穿过原点。

      r^2 = ||P + tV|| 两边取平方。

      r^2 = (P + tV)*(P + tV) = t^2 V*V + 2tP*V + P*P利用L2范数等价于一个向量与自身的点积,然后分布点积。

      t^2 V*V + 2tP*V + P*P - r^2 = 0把它变成一个二次方程。

      如果没有解,则判别式b^2 - 4ac 将为负数。如果它是零或正数,那么我们对第一个解决方案感兴趣,因此我们将减去判别式。

      a = V*V
      b = 2 P*V
      c = P*P - r^2
      t = (-b - sqrt(b^2 - 4ac)) / (2a)
      

      所以t是碰撞的时间。

      【讨论】:

      • 还有一件事。根据您的代码,如果两个重叠的对象被重新定位并且它们的速度像往常一样改变 - 但它们没有重新定位足够远 - 然后它们会立即再次碰撞并由于它们已经改变的速度而在地图上翘曲。为防止这种情况,最好使用浮点数,使其在正确的方向上四舍五入,但我不知道该怎么做,所以我只是将t 乘以一些1+epsilon
      • 我似乎无法使这个解决方案发挥作用。我正在计算 t 然后将速度乘以它,并将结果向量添加到它们的位置。是这个主意吗?
      【解决方案4】:

      在给定初始位置和速度矢量的情况下,您实际上可以推导出到达碰撞所需时间的表达式。

      调用您的对象 A 和 B,并说它们具有位置向量 ab 以及速度向量 uv,分别。假设 A 在每个时间步以 u 个单位的速率移动(因此,在时间 = t,A 在 a;在时间 = t + 1,A 在a + u)。

      我不确定您是否想查看推导;它看起来不太好...我对 LaTeX 的了解非常有限。 (如果您确实希望我这样做,我可以稍后对其进行编辑)。不过,就目前而言,这是我所拥有的,使用通用 C#-ish 语法,具有声明为 Vector2(X, Y) 的 Vector2 类型,并具有向量加法、标量乘法、点积和长度的函数。

      double timeToCollision(Vector2 a, Vector2 b, Vector2 u, Vector2 v)
      {
          // w is the vector connecting their centers;
          // z is normal to w and equal in length.
          Vector2 w = b - a;
          Vector2 z = new Vector2(-1 * w.Y, w.X);
          Vector2 s = u - v;
          // Dot() represents the dot product.
          double m = Dot(z, s) / Dot(w, s);
      
          double t = w.Length() / Dot(w, s) * 
                    (w.Length() - sqrt( ((2 * r) ^ 2) * (1 + m ^ 2) - (m * w.Length()) ^ 2) ) / 
                    (1 + m * m)
      
          return t;
      }
      

      至于对碰撞的反应:如果你可以快进到碰撞点,你就不必担心处理相交的圆圈。

      如果您有兴趣,这个表达式会在不会发生碰撞时给出一些很酷的结果。如果两个物体彼此远离,但如果它们的速度颠倒会发生碰撞,你会得到一个负的 t 值。如果对象位于不平行但永远不会相遇(彼此通过)的路径上,您将在平方根内得到一个负值。丢弃平方根项,您将得到它们彼此最接近的时间。如果它们以相同的速度平行移动,则分母将为零,t 的值未定义。

      嗯,希望这会有所帮助!我碰巧遇到了和你一样的问题,决定看看能不能在纸上解决。

      编辑:我应该在发布之前更仔细地阅读之前的回复......上面的公式的混乱确实是hardmath描述的二次方程的解决方案。为多余的帖子道歉。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-20
        • 1970-01-01
        • 2022-09-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多