AABB的球面相交测试

时间:2015-02-05 12:14:39

标签: c++ math aabb

我有一个球体,我想知道我的轴对齐边界框(AABB)是否完全,部分或根本不在球体内部。我发现了很多算法,但它们只给出部分或外部结果。有什么指针吗?

3 个答案:

答案 0 :(得分:2)

您可能已经找到了最流行的算法,以确定AABB是否与实体球体相交,Jim Arvo是否与“图形宝石”相关:

        dmin = 0;
        for( i = 0; i < 3; i++ ) {
            if( C[i] < Bmin[i] ) dmin += SQR( C[i] - Bmin[i] ); else
            if( C[i] > Bmax[i] ) dmin += SQR( C[i] - Bmax[i] );     
            }
        if( dmin <= r2 ) return TRUE;

Bmin存储每个轴的AABB的最小值,Bmax存储每个轴的AABB的最大值,C是球体中心的坐标,r2是半径平方。例如,此解决方案也出现在此stackoverflow问题中:Cube sphere intersection test?

正如您已经发现的,如果AABB完全位于球体内,此算法也会返回TRUE,但您希望将此情况视为特殊情况。这样做的一种方法是颠倒上述算法正在做的事情。该算法基本上找到AABB的点最接近到球心,并总结该点与球心之间的平方坐标增量。如果该和小于球面半径的平方,那么(在毕达哥拉斯定理之后)AABB的点位于球体内部。结果,AABB部分或完全包含在球体内。

现在假设您已经运行了该检查,并且想要确定AABB是否仅是部分或是否完全包含。为此,让我们进行类似的检查,但不是最接近圆心的AABB点,而是距离它最远的点。如果此点距球体中心的距离小于球体半径,则AABB完全包含在球体内。

有趣的是,Jim Arvo引用的算法已经包含了一个算法来完成这个任务。原始代码包含“空心”或“实心”球体和AABB的检查。不幸的是,http://www.ics.uci.edu/~arvo/code/BoxSphereIntersect.c的原始代码不再可用,但互联网存档仍然有:http://web.archive.org/web/20100323053111/http://www.ics.uci.edu/~arvo/code/BoxSphereIntersect.c您基本上对空心球的情况感兴趣。我不知道你是否希望你的AABB盒子是空心的(区别在于当球体里面盒子时你的检查是否返回true)所以我将在这里粘贴两种情况:< / p>

switch( mode )
    {
    case 0: /* Hollow Box and Hollow Sphere */
        dmin = 0;
        dmax = 0;
        face = FALSE;
        for( i = 0; i < n; i++ ) {
            a = SQR( C[i] - Bmin[i] );
            b = SQR( C[i] - Bmax[i] );
            dmax += MAX( a, b );
            if( C[i] < Bmin[i] ) {
                face = TRUE;
                dmin += a;
                }
            else if( C[i] > Bmax[i] ) {
                face = TRUE;
                dmin += b;
                }
            else if( MIN( a, b ) <= r2 ) face = TRUE;
            }
        if( face && ( dmin <= r2 ) && ( r2 <= dmax ) ) return TRUE;
        break;
    case 2: /* Solid Box and Hollow Sphere */
        dmax = 0;
        dmin = 0;
        for( i = 0; i < n; i++ ) {
            a = SQR( C[i] - Bmin[i] );
            b = SQR( C[i] - Bmax[i] );
            dmax += MAX( a, b );
            if( C[i] < Bmin[i] ) dmin += a; else
            if( C[i] > Bmax[i] ) dmin += b;
            }
        if( dmin <= r2 && r2 <= dmax ) return TRUE;
        break;

要解决您的初始问题,您现在可以更改返回条件。如果dmin小于r2dmax大于r2,则您的AABB位于球体表面(部分交叉点)。如果dmin dmax小于r2,则您的AABB完全位于您的范围内。

答案 1 :(得分:1)

交叉点测试导致true至少部分交叉,而false没有交叉,详细here

您现在想要检查AABB是否完全在球体内。您可以通过检查所有点是否都在球体内来轻松完成此操作。该测试可以简化为检查AABB的两个相对顶点是否在球体内。将平方距离与球体的平方半径进行比较,可以非常快速地进行测试。

您可以轻松地将两个测试链接在一起:

  • 检查AABB是否完全包含。如果没有,请检查它是否部分包含或根本不包含。
  • 反之亦然:检查AABB是否至少部分包含。如果是,请检查它是否完全包含。

根据每个案例发生的频率,一个或另一个可能更好 - 如果您觉得需要速度,可以对您的代码进行分析。

答案 2 :(得分:0)

尝试此算法:如果球体位于(或部分位于)AABB所有平面的inside side上,则球体会与AABB发生碰撞。飞机的Inside side意味着指向AABB中心的半空间。

因此,您应检查6个AABB平面(xmin / xmax,ymin / ymax,zmin / zmax)中每一个的球体与轴对齐平面交点。如果您按球半径拉伸平面并检查sphere center pointextruded plane,则此比较非常简单。

P上。 S.我没有尝试过练习。该算法基于类似的方法来确定三角形内的点(https://stackoverflow.com/a/2049593/326017