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