www.pudn.com > zfxcengine-0.1.0.zip > ceOBB.cpp
// $Id: ceOBB.cpp,v 1.6 2005/08/10 20:13:08 kimmi Exp $
#include "Math/ceMath.h"
namespace ZFXCE {
////////////////////////////////////////////////////////////////////////////////
void ceOBB::OBBProjection(const ceOBB& OBB, const ceVec4f& v, FLOAT* pfMin,
FLOAT* pfMax) const
{
const FLOAT fDP = v * OBB.m_vCenter;
const FLOAT fR = OBB.m_fAxis0 * _fabs(v * OBB.m_vAxis0)
+ OBB.m_fAxis1 * _fabs(v * OBB.m_vAxis1)
+ OBB.m_fAxis2 * _fabs(v * OBB.m_vAxis2);
if(pfMin)
(*pfMin) = fDP - fR;
if(pfMax)
(*pfMax) = fDP + fR;
}
////////////////////////////////////////////////////////////////////////////////
void ceOBB::TriangleProjection(const ceVec4f& v0, const ceVec4f& v1,
const ceVec4f& v2, const ceVec4f& v,
FLOAT* pfMin, FLOAT* pfMax) const
{
if (pfMin)
(*pfMin) = v * v0;
if (pfMax)
(*pfMax) = (*pfMin);
FLOAT fDP = v * v1;
if(fDP < *pfMin)
(*pfMin) = fDP;
else if(fDP > *pfMax)
(*pfMax) = fDP;
fDP = v * v2;
if(fDP < *pfMin)
(*pfMin) = fDP;
else if(fDP > *pfMax)
(*pfMax) = fDP;
}
////////////////////////////////////////////////////////////////////////////////
void ceOBB::Detransform(const ceOBB& OBB, const ceMatrix& m)
{
ceMatrix Mat = m;
ceVec3f vTranslation;
// Translation entfernen
vTranslation.Set(Mat._ms._41, Mat._ms._42, Mat._ms._43);
Mat._ms._41 = Mat._ms._42 = Mat._ms._43 = 0.0f;
// Das Zentrum und die Achsen in das Koordinatensystem transformieren
ceVec4f v = Mat * OBB.m_vCenter;
m_vCenter.Set(v.x, v.y, v.z);
v = Mat * OBB.m_vAxis0;
m_vAxis0.Set(v.x, v.y, v.z);
v = Mat * OBB.m_vAxis1;
m_vAxis1.Set(v.x, v.y, v.z);
v = Mat * OBB.m_vAxis2;
m_vAxis2.Set(v.x, v.y, v.z);
// Translation wieder hinzufügen
m_vCenter += vTranslation;
// Achsenlängen kopieren
m_fAxis0 = OBB.m_fAxis0;
m_fAxis1 = OBB.m_fAxis1;
m_fAxis2 = OBB.m_fAxis2;
}
////////////////////////////////////////////////////////////////////////////////
BOOL ceOBB::Intersects(const ceRay& Ray, FLOAT* pF) const
{
FLOAT e,f, fT0, fT1, fTmp;
FLOAT fMin = -99999.9f;
FLOAT fMax = 99999.9f;
const ceVec3f vP = m_vCenter - Ray.m_vOrigin;
e = m_vAxis0 * vP;
f = m_vAxis0 * Ray.m_vDir;
if(_fabs(f) > EPS) {
fT0 = (e+m_fAxis0) / f;
fT1 = (e-m_fAxis0) / f;
if(fT0 > fT1) {
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if(fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return FALSE;
if(fMax < 0.0f)
return FALSE;
}
else if( ((-e - m_fAxis0) > 0.0f) || ((-e + m_fAxis0) < 0.0f) )
return FALSE;
e = m_vAxis1 * vP;
f = m_vAxis1 * Ray.m_vDir;
if(_fabs(f) > 0.00001f)
{
const FLOAT fVal = 1 / f;
fT0 = (e+m_fAxis1) * fVal;
fT1 = (e-m_fAxis1) * fVal;
if(fT0 > fT1)
{
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if(fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return FALSE;
if(fMax < 0.0f)
return FALSE;
}
else if( ((-e - m_fAxis1) > 0.0f) || ((-e + m_fAxis1) < 0.0f) )
return FALSE;
e = m_vAxis2 * vP;
f = m_vAxis2 * Ray.m_vDir;
if(_fabs(f) > 0.00001f)
{
const FLOAT fVal = 1 / f;
fT0 = (e+m_fAxis2) / fVal;
fT1 = (e-m_fAxis2) / fVal;
if(fT0 > fT1)
{
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if(fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return FALSE;
if(fMax < 0.0f)
return FALSE;
}
else if( ((-e - m_fAxis2) > 0.0f) || ((-e + m_fAxis2) < 0.0f) )
return FALSE;
if(fMin > 0.0f)
{
if(pF)
(*pF) = fMin;
return TRUE;
}
if(pF)
(*pF) = fMax;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
BOOL ceOBB::Intersects(const ceRay& Ray, FLOAT fL, FLOAT* pF) const
{
FLOAT e,f, fT0, fT1, fTmp;
FLOAT fMin = -99999.9f;
FLOAT fMax = 99999.9f;
const ceVec3f vP = m_vCenter - Ray.m_vOrigin;
e = m_vAxis0 * vP;
f = m_vAxis0 * Ray.m_vDir;
if(_fabs(f) > EPS) {
const FLOAT fVal = 1 / f;
fT0 = (e+m_fAxis0) * fVal;
fT1 = (e-m_fAxis0) * fVal;
if (fT0 > fT1) {
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if(fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return false;
if(fMax < 0.0f)
return false;
}
else if( ((-e - m_fAxis0) > 0.0f) || ((-e + m_fAxis0) < 0.0f) )
return false;
e = m_vAxis1 * vP;
f = m_vAxis1 * Ray.m_vDir;
if (_fabs(f) > EPS) {
const FLOAT fVal = 1 / f;
fT0 = (e+m_fAxis1) * fVal;
fT1 = (e-m_fAxis1) * fVal;
if(fT0 > fT1) {
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if (fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return false;
if(fMax < 0.0f)
return false;
}
else if( ((-e - m_fAxis1) > 0.0f) || ((-e + m_fAxis1) < 0.0f) )
return false;
e = m_vAxis2 * vP;
f = m_vAxis2 * Ray.m_vDir;
if(_fabs(f) > EPS) {
const FLOAT fVal = 1/f;
fT0 = (e+m_fAxis2) * fVal;
fT1 = (e-m_fAxis2) * fVal;
if(fT0 > fT1) {
fTmp = fT0;
fT0 = fT1;
fT1 = fTmp;
}
if(fT0 > fMin)
fMin = fT0;
if(fT1 < fMax)
fMax = fT1;
if(fMin > fMax)
return false;
if(fMax < 0.0f)
return false;
}
else if( ((-e - m_fAxis2) > 0.0f) || ((-e + m_fAxis2) < 0.0f) )
return false;
if( (fMin > 0.0f) && (fMin <= fL) ) {
if(pF)
(*pF) = fMin;
return true;
}
if(fMax > fL)
return false;
if(pF)
(*pF) = fMax;
return true;
}
////////////////////////////////////////////////////////////////////////////////
BOOL ceOBB::Intersects(const ceOBB& OBB) const
{
FLOAT faT[3];
const ceVec3f vDifference = OBB.m_vCenter - m_vCenter;
FLOAT faaM[3][3], fRadiusA, fRadiusB, fT;
// Erste Achse
faaM[0][0] = m_vAxis0 * OBB.m_vAxis0;
faaM[0][1] = m_vAxis0 * OBB.m_vAxis1;
faaM[0][2] = m_vAxis0 * OBB.m_vAxis2;
fRadiusA = m_fAxis0;
fRadiusB = OBB.m_fAxis0 * _fabs( faaM[0][0])
+ OBB.m_fAxis1 * _fabs( faaM[0][1])
+ OBB.m_fAxis2 * _fabs( faaM[0][2]);
faT[0] = vDifference * m_vAxis0;
fT = _fabs( faT[0] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Zweite Achse
faaM[1][0] = m_vAxis1 * OBB.m_vAxis0;
faaM[1][1] = m_vAxis1 * OBB.m_vAxis1;
faaM[1][2] = m_vAxis1 * OBB.m_vAxis2;
fRadiusA = m_fAxis1;
fRadiusB = OBB.m_fAxis0 * _fabs( faaM[1][0])
+ OBB.m_fAxis1 * _fabs( faaM[1][1])
+ OBB.m_fAxis2 * _fabs( faaM[1][2]);
faT[1] = vDifference * m_vAxis1;
fT = _fabs( faT[1] );
if(fT > (fRadiusA + fRadiusB) )
return false;
// Dritte Achse
faaM[2][0] = m_vAxis2 * OBB.m_vAxis0;
faaM[2][1] = m_vAxis2 * OBB.m_vAxis1;
faaM[2][2] = m_vAxis2 * OBB.m_vAxis2;
fRadiusA = m_fAxis2;
fRadiusB = OBB.m_fAxis0 * _fabs( faaM[2][0])
+ OBB.m_fAxis1 * _fabs( faaM[2][1])
+ OBB.m_fAxis2 * _fabs( faaM[2][2]);
faT[2] = vDifference * m_vAxis1;
fT = _fabs( faT[2] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Erste Achse
fRadiusA = m_fAxis0 * _fabs( faaM[0][0])
+ m_fAxis1 * _fabs( faaM[1][0])
+ m_fAxis2 * _fabs( faaM[2][0]);
fRadiusB = OBB.m_fAxis0;
fT = _fabs( faT[0] * faaM[0][0] + faT[1] * faaM[1][0] + faT[2] * faaM[2][0] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Zweite Achse
fRadiusA = m_fAxis0 * _fabs( faaM[0][1])
+ m_fAxis1 * _fabs( faaM[1][1])
+ m_fAxis2 * _fabs( faaM[2][1]);
fRadiusB = OBB.m_fAxis1;
fT = _fabs( faT[0] * faaM[0][1] + faT[1] * faaM[1][1] + faT[2] * faaM[2][1] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Third axis
fRadiusA = m_fAxis0 * _fabs( faaM[0][2])
+ m_fAxis1 * _fabs( faaM[1][2])
+ m_fAxis2 * _fabs( faaM[2][2]);
fRadiusB = OBB.m_fAxis2;
fT = _fabs( faT[0] * faaM[0][2] + faT[1] * faaM[1][2] + faT[2] * faaM[2][2] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Axis A0xB0
fRadiusA = m_fAxis1 * _fabs( faaM[2][0]) + m_fAxis2 * _fabs( faaM[1][0]);
fRadiusB = OBB.m_fAxis1 * _fabs( faaM[0][2]) + OBB.m_fAxis2 * _fabs( faaM[0][1]);
fT = _fabs( faT[2] * faaM[1][0] - faT[1] * faaM[2][0]);
if( fT > (fRadiusA + fRadiusB) )
return false;
// Axis A0xB1
fRadiusA = m_fAxis1 * _fabs( faaM[2][1]) + m_fAxis2 * _fabs( faaM[1][1]);
fRadiusB = OBB.m_fAxis0 * _fabs( faaM[0][2]) + OBB.m_fAxis2 * _fabs( faaM[0][0]);
fT = _fabs( faT[2] * faaM[1][1] - faT[1] * faaM[2][1]);
if(fT > (fRadiusA + fRadiusB) )
return false;
// Axis A0xB2
fRadiusA = m_fAxis1 * _fabs( faaM[2][2]) + m_fAxis2 * _fabs( faaM[1][2]);
fRadiusB = OBB.m_fAxis0 * _fabs( faaM[0][1]) + OBB.m_fAxis0 * _fabs( faaM[0][0]);
fT = _fabs( faT[2] * faaM[1][2] - faT[1] * faaM[2][2]);
if(fT > (fRadiusA + fRadiusB) )
return false;
// Axis A1xB0
fRadiusA = m_fAxis0 * _fabs( faaM[2][0]) + m_fAxis2 * _fabs( faaM[0][0]);
fRadiusB = OBB.m_fAxis1 * _fabs( faaM[1][2]) + OBB.m_fAxis2 * _fabs( faaM[1][1]);
fT = _fabs( faT[0] * faaM[2][0]- faT[2] * faaM[0][0]);
if (fT > (fRadiusA + fRadiusB) )
return false;
// Axis A1xB1
fRadiusA = m_fAxis0*_fabs( faaM[2][1]) + m_fAxis2*_fabs( faaM[0][1]);
fRadiusB = OBB.m_fAxis0*_fabs( faaM[1][2]) + OBB.m_fAxis2*_fabs( faaM[1][0]);
fT = _fabs( faT[0]* faaM[2][1] - faT[2]* faaM[0][1] );
if(fT > (fRadiusA + fRadiusB) )
return false;
// Axis A1xB2
fRadiusA = m_fAxis0*_fabs( faaM[2][2]) + m_fAxis2*_fabs( faaM[0][2]);
fRadiusB = OBB.m_fAxis0*_fabs( faaM[1][1]) + OBB.m_fAxis1*_fabs( faaM[1][0]);
fT = _fabs( faT[0]* faaM[2][2] - faT[2]* faaM[0][2] );
if(fT > (fRadiusA + fRadiusB) )
return false;
// Axis A2xB0
fRadiusA = m_fAxis0*_fabs( faaM[1][0]) + m_fAxis1*_fabs( faaM[0][0]);
fRadiusB = OBB.m_fAxis1*_fabs( faaM[2][2]) + OBB.m_fAxis2*_fabs( faaM[2][1]);
fT = _fabs( faT[1]* faaM[0][0] - faT[0]* faaM[1][0] );
if (fT > (fRadiusA + fRadiusB) )
return false;
// Axis A2xB1
fRadiusA = m_fAxis0*_fabs( faaM[1][1]) + m_fAxis1*_fabs( faaM[0][1]);
fRadiusB = OBB.m_fAxis0 *_fabs( faaM[2][2]) + OBB.m_fAxis2*_fabs( faaM[2][0]);
fT = _fabs( faT[1]* faaM[0][1] - faT[0]* faaM[1][1] );
if(fT > (fRadiusA + fRadiusB) )
return false;
// Axis A2xB2
fRadiusA = m_fAxis0*_fabs( faaM[1][2]) + m_fAxis1*_fabs( faaM[0][2]);
fRadiusB = OBB.m_fAxis0*_fabs( faaM[2][1]) + OBB.m_fAxis1*_fabs( faaM[2][0]);
fT = _fabs( faT[1]* faaM[0][2] - faT[0]* faaM[1][2] );
if (fT > (fRadiusA + fRadiusB) )
return false;
return false;
}
////////////////////////////////////////////////////////////////////////////////
BOOL ceOBB::Intersects(const ceVec3f& v0, const ceVec3f& v1, const ceVec3f& v2) const
{
FLOAT fMin0, fMax0, fMin1, fMax1;
FLOAT fD;
ceVec3f v, vTriangleEdges[3], vA[3];
vA[0] = m_vAxis0;
vA[1] = m_vAxis1;
vA[2] = m_vAxis2;
vTriangleEdges[0] = v1 - v0;
vTriangleEdges[1] = v2 - v0;
v.Cross(vTriangleEdges[0], vTriangleEdges[1]);
fMin0 = v * v0;
fMax0 = fMin0;
OBBProjection( *this, v, &fMin1, &fMax1);
if( fMax1 < fMin0 || fMax0 < fMin1)
return TRUE;
// Erste Achse
v = m_vAxis0;
TriangleProjection(v0, v1, v2, v, &fMin0, &fMax0);
fD = v * m_vCenter;
fMin1 = fD - m_fAxis0;
fMax1 = fD + m_fAxis0;
if( fMax1 < fMin0 || fMax0 < fMin1)
return TRUE;
// Zweite Achse
v = m_vAxis1;
TriangleProjection(v0, v1, v2, v, &fMin0, &fMax0);
fD = v * m_vCenter;
fMin1 = fD - m_fAxis1;
fMax1 = fD + m_fAxis1;
if( fMax1 < fMin0 || fMax0 < fMin1)
return TRUE;
// Dritte Achse
v = m_vAxis2;
TriangleProjection(v0, v1, v2, v, &fMin0, &fMax0);
fD = v * m_vCenter;
fMin1 = fD - m_fAxis2;
fMax1 = fD + m_fAxis2;
if( fMax1 < fMin0 || fMax0 < fMin1)
return TRUE;
vTriangleEdges[2] = vTriangleEdges[1] - vTriangleEdges[0];
for(INT j=0; j < 3; j++)
{
for(INT k=0; k < 3; k++)
{
v.Cross(vTriangleEdges[1], vA[k]);
TriangleProjection(v0, v1, v2, v, &fMin0, &fMax0);
OBBProjection( *this, v, &fMin1, &fMax1);
if( fMax1 < fMin0 || fMax0 < fMin1)
return TRUE;
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
INT ceOBB::Cull(const cePlane* pPlanes, UINT uiNumOfPlanes)
{
ceVec3f vNormal;
INT iResult = ceVisible;
FLOAT fRadius, fTest;
// für alle Ebenen
for(UINT i=0; i < uiNumOfPlanes; i++)
{
// Die Normalen des Frustums zeigen nach außen, wir brauchen sie nach innen zeigend
vNormal = pPlanes[i].m_vNormal * -1.0f;
fRadius = _fabs(m_fAxis0 * ( vNormal * m_vAxis0) )
+ _fabs(m_fAxis1 * (vNormal * m_vAxis1) )
+ _fabs(m_fAxis2 * (vNormal * m_vAxis2) );
// Testwert berechnen
fTest = vNormal * m_vCenter - pPlanes[i].m_fDistance;
if(fTest < -fRadius)
return ceCulled;
else if( ! (fTest > fRadius))
iResult = ceClipped;
}
return iResult;
}
} // Namespace ZFXCE