1

SATを使用して衝突検出を実装しましたがbbox、バウンディング ボックスの上または下に別の衝突がある場合、誤検知が発生します。

私は、バウンディングボックスの(今のところ)軸に沿った各面を、それ自体と他のbboxコーナーに対して投影しています。

返された衝突データは正しい(depth, stepheight)ですが、バウンディング ボックスの上または下にあるオブジェクトごとに衝突が返されるという事実はofc誤りです。

機能する単純なaabb衝突チェックに対して結果をチェックします。

コードは次のとおりです。

//------------------------------
BoundingBoxIntersectionResult BoundingBox::IntersectionSAT(BoundingBox & other)
{

    // check shortest edge
    f32 distances[6] = {
        (other.mMaxVec.x - this->mMinVec.x),
        (this->mMaxVec.x - other.mMinVec.x),
        (other.mMaxVec.y - this->mMinVec.y),
        (this->mMaxVec.y - other.mMinVec.y),
        (other.mMaxVec.z - this->mMinVec.z),
        (this->mMaxVec.z - other.mMinVec.z)
    };

    i32 faceIndex = 0;
    Vec3 faceNormal;
    f32 collisionDepth = 0.0f;

    // for each face normal, get the minimum and maximum extens of the projection 
    // of all corner points of both shapes
    // if they dont overlap, there is no intersection

    // check each normal
    for (ui32 i = 0; i < 6; i++)
    {
        // CornerPointsWorld represents the world space corner positions
        SATReturn ret = this->SATTest(this->mNormals[i], this->mCornerPointsWorld);
        SATReturn ret2 = this->SATTest(this->mNormals[i], other.mCornerPointsWorld);

        float d1 = ret.minAlong - ret2.maxAlong;
        float d2 = ret2.minAlong - ret.maxAlong;
        if ((d1 > 0.0f) || (d2> 0.0f))
        {
            // return a false collision event, because we got a seperating axis
            return { false, 0.0f, 0.0f, Vec3(), BBOX_SIDE_LEFT };
        }
    }


    // check each normal of the other bbox
    for (ui32 i = 0; i < 6; i++)
    {
        SATReturn ret = this->SATTest(other.mNormals[i], this->mCornerPointsWorld);
        SATReturn ret2 = this->SATTest(other.mNormals[i], other.mCornerPointsWorld);

        float d1 = ret.minAlong - ret2.maxAlong;
        float d2 = ret2.minAlong - ret.maxAlong;
        if ((d1 > 0.0f) || (d2> 0.0f))
        {
            // return a false collision event, because we got a seperating axis
            return { false, 0.0f, 0.0f, Vec3(), BBOX_SIDE_LEFT };
        }

        // get collision data
        if (i == 0 || distances[i] < collisionDepth)
        {
            faceIndex = i;
            faceNormal = this->mNormals[i];
            collisionDepth = distances[i];
        }
    }

    // get step height needed to climb this object
    f32 stepHeight = other.mMaxVec.y - this->mMinVec.y;

    return { true, collisionDepth, stepHeight, faceNormal, BoundingBoxSide(faceIndex) };
}


//------------------------------
SATReturn BoundingBox::SATTest(Vec3& normal, Vector<Vec3>& corners)
{
    SATReturn ret;
    ret.maxAlong = MIN_FLOAT;
    ret.minAlong = MAX_FLOAT;

    // for each point
    for (ui32 i = 0; i < corners.GetSize(); i++)
    {
        f32 dot = Vec3::Dot(corners[i], normal);
        if (dot < ret.minAlong) ret.minAlong = dot;
        if (dot > ret.maxAlong) ret.maxAlong = dot;
    }

    return ret;
}

ここで、面の法線は次のように定義されます。

Vec3 mNormals[6] =
    {
        Vec3(1,  0,  0), // left
        Vec3(-1,  0,  0), // right
        Vec3(0,  1,  0), // up
        Vec3(0,  -1,  0), // down
        Vec3(0,  0,  1), //back
        Vec3(0,  0,  -1), // front
    };

問題を表示するスクリーンショットを追加しました。

偽陽性

問題は次のとおりです。

境界ボックスの下または上のすべてのオブジェクトに対して偽陽性を返します。

4

0 に答える 0