Hi all,
I've been struggling to get my OBB - OBB intersection test working, using the Separating Axis theorem.
After doing 2 different implementations, the 1st one always returns false, and the other implementation always returns true.
Debugging shows valid OBB input passed to the functions (verified by debug drawing the OBB's by the renderer).
Any input on what I might be doing wrong, is really appreciated.
bool CBaseCollision::OBBOBBIntersect(const CR_OBB &pOBB1, const CR_OBB &pOBB2)
{
static CR_VECTOR3 rPos = pOBB2.Center - pOBB1.Center;
CR_VECTOR3 xAxis1 = pOBB1.XHalfExtent; xAxis1.Normalize();
CR_VECTOR3 yAxis1 = pOBB1.YHalfExtent; yAxis1.Normalize();
CR_VECTOR3 zAxis1 = pOBB1.ZHalfExtent; zAxis1.Normalize();
CR_VECTOR3 xAxis2 = pOBB2.XHalfExtent; xAxis2.Normalize();
CR_VECTOR3 yAxis2 = pOBB2.YHalfExtent; yAxis2.Normalize();
CR_VECTOR3 zAxis2 = pOBB2.ZHalfExtent; zAxis2.Normalize();
if( SeparatingPlaneExists(rPos, xAxis1, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, yAxis1, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, zAxis1, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, xAxis2, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, yAxis2, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, zAxis2, pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(xAxis1, xAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(xAxis1, yAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(xAxis1, zAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(yAxis1, xAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(yAxis1, yAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(yAxis1, zAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(zAxis1, xAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(zAxis1, yAxis2), pOBB1, pOBB2) ||
SeparatingPlaneExists(rPos, CMathHelper::CrossVec3(zAxis1, zAxis2), pOBB1, pOBB2)) return false;
return true;
}
bool CBaseCollision::SeparatingPlaneExists(const CR_VECTOR3 &pPos, const CR_VECTOR3 &pAxis, const CR_OBB &pObb1, const CR_OBB &pObb2)
{
float baseDist = fabs(CMathHelper::DotProductVec3(pPos, pAxis));
float compDist = fabs(CMathHelper::DotProductVec3(pObb1.XHalfExtent, pAxis)) +
fabs(CMathHelper::DotProductVec3(pObb1.YHalfExtent, pAxis)) +
fabs(CMathHelper::DotProductVec3(pObb1.ZHalfExtent, pAxis)) +
fabs(CMathHelper::DotProductVec3(pObb2.XHalfExtent, pAxis)) +
fabs(CMathHelper::DotProductVec3(pObb2.YHalfExtent, pAxis)) +
fabs(CMathHelper::DotProductVec3(pObb2.ZHalfExtent, pAxis));
return(baseDist > compDist);
}
Implementation 2, based on the Realtime collision book implementation:
bool CBaseCollision::OBBOBBIntersect(const CR_OBB &pOBB1, const CR_OBB &pOBB2)
{
float ra, rb;
CR_VECTOR3 u_obb1[3];
CR_VECTOR3 u_obb2[3];
u_obb1[0] = pOBB1.XHalfExtent; u_obb1[0].Normalize();
u_obb1[1] = pOBB1.YHalfExtent; u_obb1[1].Normalize();
u_obb1[2] = pOBB1.ZHalfExtent; u_obb1[2].Normalize();
u_obb2[0] = pOBB2.XHalfExtent; u_obb2[0].Normalize();
u_obb2[1] = pOBB2.YHalfExtent; u_obb2[1].Normalize();
u_obb2[2] = pOBB2.ZHalfExtent; u_obb2[2].Normalize();
float e_obb1[3] = { pOBB1.Extents.x, pOBB1.Extents.y, pOBB1.Extents.z };
float e_obb2[3] = { pOBB2.Extents.x, pOBB2.Extents.y, pOBB2.Extents.z };
// compute rotation matrix expressing OBB2 in OBB1's coordinate frame
float tR[3][3];
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
tR[i][j] = CMathHelper::DotProductVec3(u_obb1[i], u_obb2[j]);
}
}
// compute translation vector t
CR_VECTOR3 orgt = pOBB2.Center - pOBB1.Center;
float t[3];
// bring translation into 1's coordinate space
t[0] = CMathHelper::DotProductVec3(orgt, u_obb1[0]);
t[1] = CMathHelper::DotProductVec3(orgt, u_obb1[2]);
t[2] = CMathHelper::DotProductVec3(orgt, u_obb1[2]);
// compute common subexpressions. Add epsilon, to prevent cross product being 0 for parallel vectors
float tAbsR[3][3];
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
tAbsR[i][j] = abs(tR[i][j]) + 0.0002f;
}
}
// test axes L = A0 / A1 / A2
for(int i=0;i<3;++i)
{
ra = e_obb1[i];
rb = e_obb2[0] * tAbsR[i][0] + e_obb2[1] * tAbsR[i][1] + e_obb2[2] * tAbsR[i][2];
if(fabs(t[i]) > ra + rb) return false;
}
// test axes L = B0 / B1 / B2
for(int i=0;i<3;++i)
{
ra = e_obb1[0] * tAbsR[0][i] + e_obb1[1] * tAbsR[1][i] + e_obb1[2] * tAbsR[2][i];
rb = e_obb2[i];
if(fabs(t[0] * tR[0][1] + t[1] * tR[1][i] + t[2] * tR[2][i]) > ra + rb) return false;
}
// Test axis L = A0 x B0
ra = e_obb1[1] * tAbsR[2][0] + e_obb1[2] * tAbsR[1][0];
rb = e_obb2[1] * tAbsR[0][2] + e_obb2[2] * tAbsR[0][1];
if(fabs(t[2] * tR[1][0] - t[1] * tR[2][0]) > ra + rb) return false;
// Test axis L = A0 x B1
ra = e_obb1[1] * tAbsR[2][1] + e_obb1[2] * tAbsR[1][1];
rb = e_obb2[0] * tAbsR[0][2] + e_obb2[2] * tAbsR[0][0];
if(fabs(t[2] * tR[1][1] - t[1] * tR[2][1]) > ra + rb) return false;
// Test axis L = A0 x B2
ra = e_obb1[1] * tAbsR[2][2] + e_obb1[2] * tAbsR[1][2];
rb = e_obb2[0] * tAbsR[0][1] + e_obb2[1] * tAbsR[0][0];
if(fabs(t[2] * tR[1][2] - t[1] * tR[2][2]) > ra + rb) return false;
// Test axis L = A1 x B0
ra = e_obb1[0] * tAbsR[2][0] + e_obb1[2] * tAbsR[0][0];
rb = e_obb2[1] * tAbsR[1][2] + e_obb2[2] * tAbsR[1][1];
if(fabs(t[0] * tR[2][0] - t[2] * tR[0][0]) > ra + rb) return false;
// Test axis L = A1 x B1
ra = e_obb1[0] * tAbsR[2][1] + e_obb1[2] * tAbsR[0][1];
rb = e_obb2[0] * tAbsR[1][2] + e_obb2[2] * tAbsR[1][0];
if(fabs(t[0] * tR[2][1] - t[2] * tR[0][1]) > ra + rb) return false;
// Test axis L = A1 x B2
ra = e_obb1[0] * tAbsR[2][2] + e_obb1[2] * tAbsR[0][2];
rb = e_obb2[0] * tAbsR[1][1] + e_obb2[1] * tAbsR[1][0];
if(fabs(t[0] * tR[2][2] - t[2] * tR[0][2]) > ra + rb) return false;
// Test axis L = A2 x B0
ra = e_obb1[0] * tAbsR[1][0] + e_obb1[1] * tAbsR[0][0];
rb = e_obb2[1] * tAbsR[2][2] + e_obb2[2] * tAbsR[2][1];
if(fabs(t[1] * tR[0][0] - t[0] * tR[1][0]) > ra + rb) return false;
// Test axis L = A2 x B1
ra = e_obb1[0] * tAbsR[1][1] + e_obb1[1] * tAbsR[0][1];
rb = e_obb2[0] * tAbsR[2][2] + e_obb2[2] * tAbsR[2][0];
if(fabs(t[1] * tR[0][1] - t[0] * tR[1][1]) > ra + rb) return false;
// Test axis L = A2 x B2
ra = e_obb1[0] * tAbsR[1][2] + e_obb1[1] * tAbsR[0][2];
rb = e_obb2[0] * tAbsR[2][1] + e_obb2[1] * tAbsR[2][0];
if(fabs(t[1] * tR[0][2] - t[0] * tR[1][2]) > ra + rb) return false;
return true;
}