I've implemented a collision detecting using SAT and I get false positives if another bbox
is above or below the bounding box.
I'm projecting each (for now) axis aligned face of the bounding box against its own and the other bbox
corners.
The collision data returned is correct (depth, stepheight)
, but the fact that it returns a collision for each object that is above or below the bounding box is ofc
false.
I check my results against a simple aabb
collision check which works.
Here is the code:
//------------------------------
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;
}
where face normals are defined as:
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
};
I've added a screenshot to display the problem:
So the problem is:
It returns false positive for all objects below or above the bounding box.