检查两个移动的AABB是否相交的最快方法是什么?


12

我有两个正在移动的AABB,检查它们是否在框架下相交的最快方法是什么?

通过移动,我的意思是不仅要检查常用的矩形交集方法,还意味着某种简单易行的测试,该测试仅返回布尔值,没有命中时间或其他任何东西。

我认为就是这样简单地做到这一点:

这个

但是那个Hexagon非常复杂,我不知道如何计算AABB-多边形相交,也许有更简单的方法吗?

您最喜欢的任何编程语言,我都可以轻松移植。

谢谢。


3
我很困惑。您特别提到“扫描测试”,您是否尝试过典型的AABB扫描测试?它正是您想要的。
SomeWritesReserved 2015年

1
我同意上面的评论-“经典”测试有什么问题?而且,这里提出的大多数解决方案显然比这要慢...此外,其中一些解决方案可能会给出错误的结果(不可靠)。
温德拉

你可以尝试分离轴测试gamedevelopment.tutsplus.com/tutorials/...
Pharap

Answers:


8

使用Minkowski总和

解决此问题的一个好方法是考虑转换为原点(v')的运动线(v)与原点(A')旋转180度的AMinkowski和与障碍物之间的交点(仅B在这种情况下):A”

在下图中,我在任意坐标系的原点中放置了一个 smack-dab。这简化了理解,因为将A旋转180度会导致A',并且将v转换为原点等于v'

Minkowski和是绿色矩形,通过进行线-AABB交点可以找到运动的A和静止的B的交点。这些点用蓝色圆圈标记。

Minkowski sum-退化案例

在下图中,使用了不同的原点,并且找到了相同的交点。

Minkowski sum-更一般的情况

多个移动AABB

为了使这项工作了两个的AABB期间的特定时间段,你会减去以线性方式移动 “从s的速度矢量 S波速度矢量和使用”,作为线段的线AABB相交。

伪代码

def normalize(aabb):
    return {x1: min(aabb.x1, aabb.x2), x2: max(aabb.x1, aabb.x2),
            y1: min(aabb.y1, aabb.y2), y2: max(aabb.y1, aabb.y2),

def rotate_about_origin(aabb):
    return normalize({x1: -aabb.x1, x2: -aabb.x2
                      y1: -aabb.y1, y2: -aabb.y2})

# given normalized aabb's
def minkowski_sum(aabb1, aabb2):
    return {x1: aabb1.x1+aabb2.x1, x2: aabb1.x2+aabb2.x2,
            y1: aabb1.y1+aabb2.y1, y2: aabb1.y2+aabb2.y2}

def get_line_segment_from_origin(v):
    return {x1: 0, y1: 0, x2: v.x, y2: v.y}

def moving_objects_with_aabb_intersection(object1, object2):
    A = object1.get_aabb()
    B = object2.get_aabb()

    # get A'⊕B
    rotated_A = rotate_about_origin(A)
    sum_aabb = minkowski_sum(rotated_A, B)

    # get v'
    total_relative_velocity = vector_subtract(object1.get_relative_velocity(), object2.get_relative_velocity())
    line_segment = get_line_segment_from_origin(total_relative_velocity)

    # call your favorite line clipping algorithm
    return line_aabb_intersection(line_segment, sum_aabb)

碰撞反应

根据游戏玩法,您将执行更细粒度的碰撞检测(可能是AABB的网格物体),或者前进到下一阶段:碰撞响应。

发生碰撞时,线A-ABB交点算法将分别返回1或2个交点,这取决于A是在B内结束运动还是通过B。(这是对A沿其边或沿其各个角之一吃草B的退化案例的打折。)

无论哪种方式,沿线段的第一个交点都是碰撞点,您都可以将其转换回世界坐标系中的正确位置(第二幅图片中第一个浅蓝色圆圈沿原始v,称为p),然后确定(例如,对于弹性碰撞,通过沿p处的碰撞法线反射v),在帧末尾A的实际位置将是(At + 1)。

碰撞反应

如果有两个以上的对撞机,这将变得稍微复杂一些,因为您也想对v的第二个反射部分进行碰撞检测。


谢谢,最有趣。您能解释一下在移动过程中A和B相交而在没有相交的情况下结束移动时的情况吗?
GameAlchemist

@GameAlchemist那将是碰撞响应,而不是太多的碰撞检测(问题的原始主题)。但是我喜欢Paint,所以请检查编辑。:-)
Eric

感谢您的更新(和HURRA的方案:-)),这不是我的问题,但让我了解到,你的算法已经处理的情况下,当A到B.完全通过
GameAlchemist

5

OBB-定向边界框。这是一个教程

有效地,将对象A的速度矢量作为y轴(向上)对齐的边界框。可以通过对象A的起点和终点来计算宽度和高度。然后将其与对象B的AABB(作为OOBB进行处理)和黄金进行比较。

如果您只是在寻找快速相交测试以查看它们是否可能相交,则可以创建一个AABB,该AABB在开始位置和结束位置都围绕对象A的AABB。如果AABB不与所有AABB相交,则不存在相交;但是,这可能会导致误报,因此您仅应将其用作初步测试。


4

您不需要OOB,也不需要使用时间步冲突检测。只需使用普通的AABB扫频测试,请参阅此链接。从本质上讲,它确实可以实现图中的功能:从起点到终点“扫过”移动的ABB,然后将其用于与其他静态ABB的碰撞检测。

如果您担心此扫描测试会因为返回“影响时间”而更加昂贵,那么我认为您过早进行了优化。

在出色的书:克里斯特·埃里克森(Christer Ericson)的《实时碰撞检测》中,可以找到有关扫频测试的更多深入信息。


3

AABB近似边缘情况弱点

您首先需要将运动分解为较小的步骤,然后使用该信息来计算高级AABB。如果较大的AABB相交,则可以检查较小的步长以使其更准确。

如果任一对象快速旋转并且在一个维度上比另一个维度更长,则仅通过使用起始和结束位置来检查ABB(或OOBB)来估计是否存在碰撞可能会错过碰撞。

要计算更准确的估算AABB,将运动分解为较小的步长,然后仅使用初始AABB(而不是对象网格),旋转AABB(现在只是一个框,没有轴对齐),因为对象将在每个位置旋转和移动步。每个轴的最大和最小点将为您提供包围对象整个运动的AABB。

如果与较大的ABB交叉,则可以使用已经计算出的较小的ABB,以确定可能发生碰撞的位置。对于与另一个对象相交的每个较小的AABB,您可以执行更昂贵的网格相交检测。


2
或预先计算出BB可以进行任何旋转的最大宽度,并使用它
棘轮怪胎

2

您将不得不将运动分解为较小的运动步骤。例如:

您想使用更大的分量(在本例中为X轴)分解运动,然后在每个步骤中检查碰撞。

这看起来可能太昂贵了,但是要考虑到一个对象在每个循环中移动得快于其自身宽度的速度将非常快,因此这种情况并不像您首先想到的那样普遍。


2
这种方法很糟糕,因为它无法捕获某些情况(例如,靠近您绘制的第一个和第二个盒子的盒子),并且增加采样量可能会过大。使用SAT进行简单的多边形测试应该足够快速且可靠。
Sopel

1
是的,这是一个不错的解决方案,但不是太好。当碰撞接近对象的拐角时,准确性会迅速下降,随着速度的增加(或准确性,取决于实现方式),性能会下降,并且这仅仅是不必要的漏洞。
BWG 2015年

2

您还应该使用相对速度进行碰撞检查,以使一个AABB为“静态”,而另一个以其自身速度减去“静态”一个的速度运动。

最快的方式,看看他们是否可以相交是刚刚拓展移动AABB的速度。

例如,AABB以0.1 x /帧向右移动,然后将其扩展,以使左边缘保持不变,而右边缘则进一步保持0.1。然后,您可以检查新的AABB。如果为假,则不存在冲突。(提早返回并在小速度时准确)。

然后,您可以检查运动对象的末端和起点AABB是否相交。如果为true,则返回true。

否则,您需要检查对角线是否与静态ABB相交。

这涉及获取对角线的坐标,其中x =静态元素的左边缘,右边缘查看y是否在底部和顶部之内。(反过来重复)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.