Разделительная ось Теория — ложное срабатывание на вертикальной оси

Я реализовал обнаружение столкновений с помощью СУББОТА и я получаю ложные срабатывания, если другой 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
};

Я добавил скриншот для отображения проблемы:

сидел ложный позитив

Итак, проблема в том, что:

Он возвращает ложное срабатывание для всех объектов ниже или выше ограничительной рамки.

1

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы [email protected]