如何将轴对齐的边界框适配/裁剪到三角形的一部分

huangapple go评论51阅读模式
英文:

How to fit/clip an axis aligned bounding box around a portion of a triangle

问题

以下是您提供的内容的翻译:

I have looked and looked and cannot find any resources on. I want to clip an axis aligned bounding box against a triangle in a way that creates a new tight fitting axis aligned bounding box around or in the triangle (I have seen the reverse a lot, a triangle clipped against an axis aligned bounding box, but never seen the reverse case). I tried computing the clipped triangle then building a bounding box from it. But it is grossly inefficient and I don't think my code is correct. Does anyone know how to clip a bounding box against a triangle efficiently?

我已经反复查找,但找不到任何相关资源。我想要剪裁一个轴对齐的边界框,以一种方式创建一个新的轴对齐的边界框,紧密围绕或在三角形内部(我经常看到相反的情况,即将三角形剪裁到轴对齐的边界框中,但从未看到相反的情况)。我尝试计算剪裁后的三角形,然后从中构建边界框。但这非常低效,我认为我的代码不正确。有谁知道如何高效地将边界框剪裁到三角形中吗?

这是描述我目前的做法的图片:

如何将轴对齐的边界框适配/裁剪到三角形的一部分
如何将轴对齐的边界框适配/裁剪到三角形的一部分
如何将轴对齐的边界框适配/裁剪到三角形的一部分

typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t   s8;
typedef int16_t  s16;
typedef int32_t  s32;
typedef int64_t  s64;
typedef float    f32;
typedef double   f64;

struct Point
{
    union
    {
        f32 a[3];
        struct
        {
            f32 x;
            f32 y;
            f32 z;
        };
    };
};

struct BoundingBox3
{
    Point m_vMin = {FLT_MAX,FLT_MAX,FLT_MAX};
    Point m_vMax = {-FLT_MAX,-FLT_MAX,-FLT_MAX};
};

inline
s8 Classify( s8 sign, u8 axis, const Point *c_v, const Point *p_v )
{
    const f64 d = sign * ( p_v->a[axis] - c_v->a[axis] );
    if ( d > EPSILON )
    {
        return  1;
    }
    else if ( d < -EPSILON )
    {
        return -1;
    }
    return  0;
}

#define POINT_BUFFER_SIZE 9

inline
void Clip3D_plane( Point *pVerts, s8 sign, u8 axis, u8 *pdwNumVerts, const Point *pPointOnPlane )
{
    u8 dwNumVerts = ( *pdwNumVerts );
    if ( dwNumVerts == 0 )
    {
        return;
    }
    else if ( dwNumVerts == 1 )
    {
        *pdwNumVerts = 0;
        return;
    }

    Point vNewVerts[POINT_BUFFER_SIZE];
    u8 k = 0;
    bool b = true; // polygon is fully located on clipping plane

    Point v1 = pVerts[dwNumVerts - 1];
    s8 d1 = Classify( sign, axis, pPointOnPlane, &v1 );
    for ( u8 j = 0; j < dwNumVerts; ++j )
    {
        const Point &v2 = pVerts[j];
        s8 d2 = Classify( sign, axis, pPointOnPlane, &v2 );

        if ( d2 != 0 )
        {
            b = false;
            if ( ( 0x80 & ( d2 ^ d1 ) ) != 0 ) //if signs differ
            {
                const f32 fAlpha = ( v2.a[axis] - pPointOnPlane->a[axis] ) / ( v2.a[axis] - v1.a[axis] );
                Point_Lerp( &v2, &v1, fAlpha, &vNewVerts[k++] );
            }
            else if ( d1 == 0 && ( k == 0 || !Point_Equals( &vNewVerts[k - 1], &v1 ) ) )
            {
                vNewVerts[k++] = v1;
            }

            if ( d2 > 0 )
            {
                vNewVerts[k++] = v2;
            }
        }
        else
        {
            if ( d1 != 0 )
            {
                vNewVerts[k++] = v2;
            }
        }

        v1 = v2;
        d1 = d2;
    }

    if ( b )
    {
        return;
    }

    *pdwNumVerts = k;
    for ( u8 j = 0; j < k; ++j )
    {
        pVerts[j] = vNewVerts[j];
    }
}

inline void BoundingBox_Append( BoundingBox3 *pBB, const Point *pvPoint )
{
    pBB->m_vMin.x = min( pBB->m_vMin.x, pvPoint->x );
    pBB->m_vMin.y = min( pBB->m_vMin.y, pvPoint->y );
    pBB->m_vMin.z = min( pBB->m_vMin.z, pvPoint->z );
    pBB->m_vMax.x = max( pBB->m_vMax.x, pvPoint->x );
    pBB->m_vMax.y = max( pBB->m_vMax.y, pvPoint->y );
    pBB->m_vMax.z = max( pBB->m_vMax.z, pvPoint->z );
}

void BoundingBox_ClipAndAppendTri( BoundingBox3 *pBB3, Point *pVerts, u8 *phwNumVerts, const BoundingBox3 *pClipBox )
{
    for ( u8 axis = 0; axis < 3; ++axis )
    {
        Clip3D_plane( pVerts, 1, axis, phwNumVerts, &pClipBox->m_vMin );
        Clip3D_plane( pVerts, -1, axis, phwNumVerts, &pClipBox->m_vMax );
    }
    for ( u8 vert = 0; vert < *phwNumVerts; ++vert )
    {
        BoundingBox_Append( pBB3, &pVerts[vert] );
    }
}

希望这些翻译对您有所帮助。如果您有任何其他问题或需要进一步的翻译,请随时提问。

英文:

I have looked and looked and cannot find any resources on. I want to clip an axis aligned bounding box against a triangle in a way that creates a new tight fitting axis aligned bounding box around or in the triangle (I have seen the reverse a lot, a triangle clipped against an axis alinged bounding, but never seen the reverse case). I tried computing the clipped tiangle then building a bounding box from it. But it is grossly inefficent and I don't think my code is correct. Does anyone know how to clip a bounding box against a triangle efficently?

Here is pictures describing what I currently do

如何将轴对齐的边界框适配/裁剪到三角形的一部分
如何将轴对齐的边界框适配/裁剪到三角形的一部分
如何将轴对齐的边界框适配/裁剪到三角形的一部分

typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t   s8;
typedef int16_t  s16;
typedef int32_t  s32;
typedef int64_t  s64;
typedef float    f32;
typedef double   f64;

struct Point
{
    union
    {
        f32 a[3];
        struct
        {
            f32 x;
            f32 y;
            f32 z;
        };
    };
};

struct BoundingBox3
{
    Point m_vMin = {FLT_MAX,FLT_MAX,FLT_MAX};
    Point m_vMax = {-FLT_MAX,-FLT_MAX,-FLT_MAX};
};

inline
s8 Classify( s8 sign, u8 axis, const Point *c_v, const Point *p_v )
{
    const f64 d = sign * ( p_v-&gt;a[axis] - c_v-&gt;a[axis] );
    if ( d &gt; EPSILON )
    {
        return  1;
    }
    else if ( d &lt; -EPSILON )
    {
        return -1;
    }
    return  0;
}

#define POINT_BUFFER_SIZE 9

inline
void Clip3D_plane( Point *pVerts, s8 sign, u8 axis, u8 *pdwNumVerts, const Point *pPointOnPlane )
{
    u8 dwNumVerts = ( *pdwNumVerts );
    if ( dwNumVerts == 0 )
    {
        return;
    }
    else if ( dwNumVerts == 1 )
    {
        *pdwNumVerts = 0;
        return;
    }

    Point vNewVerts[POINT_BUFFER_SIZE];
    u8 k = 0;
    bool b = true; // polygon is fully located on clipping plane

    Point v1 = pVerts[dwNumVerts - 1];
    s8 d1 = Classify( sign, axis, pPointOnPlane, &amp;v1 );
    for ( u8 j = 0; j &lt; dwNumVerts; ++j )
    {
        const Point &amp;v2 = pVerts[j];
        s8 d2 = Classify( sign, axis, pPointOnPlane, &amp;v2 );

        if ( d2 != 0 )
        {
            b = false;
            if ( ( 0x80 &amp; ( d2 ^ d1 ) ) != 0 ) //if signs differ
            {
                const f32 fAlpha = ( v2.a[axis] - pPointOnPlane-&gt;a[axis] ) / ( v2.a[axis] - v1.a[axis] );
                Point_Lerp( &amp;v2, &amp;v1, fAlpha, &amp;vNewVerts[k++] );
            }
            else if ( d1 == 0 &amp;&amp; ( k == 0 || !Point_Equals( &amp;vNewVerts[k - 1], &amp;v1 ) ) )
            {
                vNewVerts[k++] = v1;
            }

            if ( d2 &gt; 0 )
            {
                vNewVerts[k++] = v2;
            }
        }
        else
        {
            if ( d1 != 0 )
            {
                vNewVerts[k++] = v2;
            }
        }

        v1 = v2;
        d1 = d2;
    }

    if ( b )
    {
        return;
    }

    *pdwNumVerts = k;
    for ( u8 j = 0; j &lt; k; ++j )
    {
        pVerts[j] = vNewVerts[j];
    }
}

inline void BoundingBox_Append( BoundingBox3 *pBB, const Point *pvPoint )
{
    pBB-&gt;m_vMin.x = min( pBB-&gt;m_vMin.x, pvPoint-&gt;x );
    pBB-&gt;m_vMin.y = min( pBB-&gt;m_vMin.y, pvPoint-&gt;y );
    pBB-&gt;m_vMin.z = min( pBB-&gt;m_vMin.z, pvPoint-&gt;z );
    pBB-&gt;m_vMax.x = max( pBB-&gt;m_vMax.x, pvPoint-&gt;x );
    pBB-&gt;m_vMax.y = max( pBB-&gt;m_vMax.y, pvPoint-&gt;y );
    pBB-&gt;m_vMax.z = max( pBB-&gt;m_vMax.z, pvPoint-&gt;z );
}

void BoundingBox_ClipAndAppendTri( BoundingBox3 *pBB3, Point *pVerts, u8 *phwNumVerts, const BoundingBox3 *pClipBox )
{
    for ( u8 axis = 0; axis &lt; 3; ++axis )
    {
        Clip3D_plane( pVerts, 1, axis, phwNumVerts, &amp;pClipBox-&gt;m_vMin );
        Clip3D_plane( pVerts, -1, axis, phwNumVerts, &amp;pClipBox-&gt;m_vMax );
    }
    for ( u8 vert = 0; vert &lt; *phwNumVerts; ++vert )
    {
        BoundingBox_Append( pBB3, &amp;pVerts[vert] );
    }
}

答案1

得分: 2

你通常不能避免计算三角形的边与矩形的边之间的交点。要获得正确的结果,您需要计算这两种形状的交点,例如使用Sutherland-Hodgman算法,您可以专门针对三角形和矩形的情况进行优化。如果我没记错,在最坏的情况下,您会得到一个七边形。

然后获得AABB并不困难。

或者,您可以实现一种线段剪切算法,针对多边形(三角形或矩形)窗口。对于AA窗口的专用算法是Cohen-Sutherland算法。然后将所有三角形边剪切为矩形,将所有矩形边剪切为三角形。

英文:

In general you can't escape computing intersection points between the sides of the triangle and those of the box. To get a correct result, you need to compute the intersection of the two shapes, for instance using the Sutherland-Hodgman algorithm, that you can specialize for the case of a triangle and a rectangle. If I am right, in the worst case you get an heptagon.

Then getting the AABB is no big deal.


Alternatively, you can implement a line-segment clipping algorithm against a poygonal (triangular or rectangular) window. A specialization to an AA window is the Cohen-Sutherland algorithm. Then clip all triangle sides against the rectangle and all rectangle sides against the triangle.

huangapple
  • 本文由 发表于 2023年2月8日 14:23:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75382034.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定