www.pudn.com > zfxcengine-0.1.0.zip > ceRay.cpp


// $Id: ceRay.cpp,v 1.6 2005/07/10 18:53:23 kimmi Exp $ 
///////////////////////////////////////////////////////////////////////// 
//  Module:    Math 
//! \file      ceRay.cpp 
//! \brief     Implementations of ceRay 
//! \author    Kim Kulling aka kimmi 
// 
// Licence : LGPL 
///////////////////////////////////////////////////////////////////////// 
#include "Math/ceMath.h" 
 
namespace ZFXCE { 
	//////////////////////////////////////////////////////////////////////////////// 
	ceRay::ceRay(ceVec3f &Origin, ceVec3f &Dir) 
	{ 
		m_vOrigin = Origin; 
		m_vDir = Dir; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	ceRay::ceRay(ceRay &Ref) 
	{ 
		m_vOrigin = Ref.m_vDir; 
		m_vDir = Ref.m_vDir; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	void ceRay::Set(const ceVec3f& vOrigin, const ceVec3f& vDir) 
	{ 
		m_vOrigin = vOrigin; 
		m_vDir = vDir; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	void ceRay::Set(const ceVec4f& vOrigin, const ceVec4f& vDir) 
	{ 
		m_vOrigin.x = vOrigin.x; 
		m_vOrigin.y = vOrigin.y; 
		m_vOrigin.z = vOrigin.z; 
 
		m_vDir.x = vDir.x; 
		m_vDir.y = vDir.y; 
		m_vDir.z = vDir.z; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	void ceRay::Detransform(const ceMatrix& m) 
	{ 
		ceMatrix mInverse; 
		ceMatrix mCopy = m; 
 
		// Translation umkehren 
		m_vOrigin.x -= m._ms._41; 
		m_vOrigin.y -= m._ms._42; 
		m_vOrigin.z -= m._ms._43; 
 
		// Und nun die Translation entfernen 
		mCopy._ms._41 = mCopy._ms._42 = mCopy._ms._43 = 0.0f; 
 
		// Matrix invertieren und auf diesen Strahl anwenden 
		mInverse.CreateInverseOf(mCopy); 
 
		m_vOrigin = m_vOrigin * mInverse; 
		m_vDir = m_vDir * mInverse; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceVec3f& v0, const ceVec3f& v1, const ceVec3f& v2,  
					BOOL bCull, FLOAT* pF) const 
	{ 
		ceVec3f vA, vB, vC; 
 
		const ceVec3f vEdge1 = v1 - v0; 
		const ceVec3f vEdge2 = v2 - v0; 
 
		vA.Cross(m_vDir, vEdge2); 
 
		// Wenn nahe bei 0, dann parallel 
		const FLOAT fDet = vEdge1 * vA; 
		if (bCull && (fDet < 0.0001f) ) 
			return FALSE; 
		else if( (fDet < 0.001f) && (fDet > -0.0001f) ) 
			return FALSE; 
 
		vB = m_vOrigin - v0; 
		const FLOAT u = vB * vA; 
		if (u < 0.0f || u > fDet) 
			return FALSE; 
 
		vC.Cross(vB, vEdge1); 
		const FLOAT v = m_vDir * vC; 
		if(v < 0.0f || u+v > fDet) 
			return FALSE; 
 
		if (pF) 
		{ 
			*pF = vEdge2 * vC; 
			const FLOAT fInvDet = 1.0f / fDet; 
			*pF *= fInvDet; 
		} 
    
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceVec3f& v0, const ceVec3f& v1, const ceVec3f& v2,  
					BOOL bCull, FLOAT fL, FLOAT *pF) const 
	{ 
		ceVec3f vA, vB, vC; 
 
		const ceVec3f vEdge1 = v1 - v0; 
		const ceVec3f vEdge2 = v2 - v0; 
 
		vA.Cross(m_vDir, vEdge2); 
 
		// Wenn nahe bei 0, dann parallel 
		const FLOAT fDet = vEdge1 * vA; 
		if (bCull && (fDet < 0.0001f) ) 
			return FALSE; 
		else if ( (fDet < 0.001f) && (fDet > -0.0001f) ) 
			return FALSE; 
 
		vB = m_vOrigin - v0; 
		const FLOAT u = vB * vA; 
		if(u < 0.0f || u > fDet) 
			return FALSE; 
 
		vC.Cross(vB, vEdge1); 
		const FLOAT v = m_vDir * vC; 
		if(v < 0.0f || u+v > fDet) 
			return FALSE; 
 
		if(pF) 
		{ 
			*pF = vEdge2 * vC; 
			const FLOAT fInvDet = 1.0f / fDet; 
			*pF *= fInvDet; 
			// Kollision mit dem Strahl, aber nicht mit dem Segment? 
			if(*pF > fL) 
				return FALSE; 
		} 
		else 
		{ 
			// Kollision mit dem Strahl, aber nicht mit dem Segment? 
			const FLOAT f = (vEdge2 * vC) * (1.0f / fDet); 
			if(f > fL) 
				return FALSE; 
		} 
    
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const cePlane& plane, BOOL bCull, FLOAT* pF,  
					ceVec3f* pvHit) const 
	{ 
		const FLOAT fD = plane.m_vNormal * m_vDir; 
 
		// Strahl parallel zur Ebene? 
		if(_fabs(fD) < 0.00001f) 
			return FALSE; 
    
		// Zeigt die Normale weg von der Strahlenrichtung? 
		if(bCull && (fD > 0.0f) ) 
			return FALSE; 
 
 
		const FLOAT fT = -( (plane.m_vNormal * m_vOrigin) + plane.m_fDistance); 
		const FLOAT fT2 = fT / fD; 
 
		// Schnittpunkt hinter dem Strahlenursprung? 
		if(fT2 < 0.0f) 
			return FALSE; 
 
		if(pvHit) 
		{ 
			ceVec3f vT = m_vDir * fT2; 
			vT += m_vOrigin; 
			(*pvHit) = vT; 
		} 
 
		if(pF) 
			(*pF) = fT2; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const cePlane& plane, BOOL bCull, FLOAT fL, FLOAT* pF,  
				ceVec3f* pvHit) const 
	{ 
		const FLOAT fD = plane.m_vNormal * m_vDir; 
 
		// Strahl parallel zur Ebene? 
		if (_fabs(fD) < 0.00001f) 
			return FALSE; 
    
		// Zeigt die Normale weg von der Strahlenrichtung? 
		if (bCull && (fD > 0.0f) ) 
			return FALSE; 
 
		const FLOAT fT  = -( (plane.m_vNormal * m_vOrigin) + plane.m_fDistance); 
		const FLOAT fT2 = fT / fD; 
 
		// Schnittpunkt hinter dem Strahlenursprung oder nicht an einem gültigen Punkt? 
		if(fT2 < 0.0f || fT2 > fL) 
			return FALSE; 
 
		if (pvHit) 
		{ 
			ceVec3f vT = m_vDir * fT2; 
			vT += m_vOrigin; 
			(*pvHit) = vT; 
		} 
 
		if (pF) 
			(*pF) = fT2; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceAABB& AABB, FLOAT* pF) const 
	{ 
		FLOAT fT0, fT1, fTmp; 
		FLOAT fNear = -999999.9f; 
		FLOAT fFar = 999999.9f; 
		FLOAT fEpsilon = 0.00001f; 
 
		// Die ersten beiden Ebenen der Box 
		if( _fabs(m_vDir.x) < fEpsilon) 
			if( (m_vOrigin.x < AABB.m_vMin.x) || (m_vOrigin.x > AABB.m_vMax.x) ) 
				return FALSE; 
 
		fT0 = (AABB.m_vMin.x - m_vOrigin.x) / m_vDir.x; 
		fT1 = (AABB.m_vMax.x - m_vOrigin.x) / m_vDir.x; 
 
		if(fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return FALSE; 
		 
		if(fFar < 0) 
			return FALSE; 
 
		// Das zweite Paar 
		if( _fabs(m_vDir.y) < fEpsilon) 
			if( (m_vOrigin.y < AABB.m_vMin.y) || (m_vOrigin.y > AABB.m_vMax.y) ) 
				return FALSE; 
 
		fT0 = (AABB.m_vMin.y - m_vOrigin.y) / m_vDir.y; 
		fT1 = (AABB.m_vMax.y - m_vOrigin.y) / m_vDir.y; 
 
		if(fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
    
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
		if(fNear > fFar) 
			return FALSE; 
		if(fFar < 0) 
			return FALSE; 
 
		// Und das letzte Paar 
		if( _fabs(m_vDir.z) < fEpsilon) 
			if( (m_vOrigin.z < AABB.m_vMin.z) || (m_vOrigin.z > AABB.m_vMax.z) ) 
				return FALSE; 
    
		const FLOAT fDirZ = 1 / m_vDir.z; 
		fT0 = (AABB.m_vMin.z - m_vOrigin.z) * fDirZ; 
		fT1 = (AABB.m_vMax.z - m_vOrigin.z) * fDirZ; 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
		if(fNear > fFar) 
			return FALSE; 
		if(fFar < 0) 
			return FALSE; 
 
		if(fNear > 0) 
		{ 
			if(pF) 
				(*pF) = fNear; 
		} 
		else 
		{ 
			if(pF) 
				(*pF) = fFar; 
		} 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceAABB& AABB, FLOAT fL, FLOAT* pF) const 
	{ 
		FLOAT fT0, fT1, fTmp; 
		FLOAT fNear = -999999.9f; 
		FLOAT fFar = 999999.9f; 
		FLOAT fEpsilon = 0.00001f; 
 
		// Die ersten beiden Ebenen der Box 
		if( _fabs(m_vDir.x) < fEpsilon) 
			if( (m_vOrigin.x < AABB.m_vMin.x) || (m_vOrigin.x > AABB.m_vMax.x) ) 
				return FALSE; 
 
		fT0 = (AABB.m_vMin.x - m_vOrigin.x) / m_vDir.x; 
		fT1 = (AABB.m_vMax.x - m_vOrigin.x) / m_vDir.x; 
 
		if(fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return FALSE; 
		if(fFar < 0) 
			return FALSE; 
 
		// Das zweite Paar 
		if( _fabs(m_vDir.y) < fEpsilon) 
			if( (m_vOrigin.y < AABB.m_vMin.y) || (m_vOrigin.y > AABB.m_vMax.y) ) 
				return FALSE; 
 
		fT0 = (AABB.m_vMin.y - m_vOrigin.y) / m_vDir.y; 
		fT1 = (AABB.m_vMax.y - m_vOrigin.y) / m_vDir.y; 
 
		if(fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
    
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
		if(fNear > fFar) 
			return FALSE; 
		if(fFar < 0) 
			return FALSE; 
 
		// Und das letzte Paar 
		if( _fabs(m_vDir.z) < fEpsilon) 
			if( (m_vOrigin.z < AABB.m_vMin.z) || (m_vOrigin.z > AABB.m_vMax.z) ) 
				return FALSE; 
    
		fT0 = (AABB.m_vMin.z - m_vOrigin.z) / m_vDir.z; 
		fT1 = (AABB.m_vMax.z - m_vOrigin.z) / m_vDir.z; 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
		if(fNear > fFar) 
			return FALSE; 
		if(fFar < 0) 
			return FALSE; 
 
		FLOAT fFinal; 
		if(fNear > 0) 
			fFinal = fNear; 
		else 
			fFinal = fFar; 
 
		if(fFinal > fL) 
			return FALSE; 
 
		if(pF) 
			(*pF) = fFinal; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceOBB& OBB, FLOAT* pF) const 
	{ 
		FLOAT e,f, fT0, fT1, fTmp; 
		FLOAT fMin = -99999.9f; 
		FLOAT fMax = 99999.9f; 
 
		const ceVec3f vP = OBB.m_vCenter - m_vOrigin; 
 
		e = OBB.m_vAxis0 * vP; 
		f = OBB.m_vAxis0 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis0) / f; 
			fT1 = (e - OBB.m_fAxis0) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis0) > 0.0f) || ((-e + OBB.m_fAxis0) < 0.0f) ) 
			return FALSE; 
 
		e = OBB.m_vAxis1 * vP; 
		f = OBB.m_vAxis1 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis1) / f; 
			fT1 = (e - OBB.m_fAxis1) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis1) > 0.0f) || ((-e + OBB.m_fAxis1) < 0.0f) ) 
			return FALSE; 
 
		e = OBB.m_vAxis2 * vP; 
		f = OBB.m_vAxis2 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis2) / f; 
			fT1 = (e - OBB.m_fAxis2) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis2) > 0.0f) || ((-e + OBB.m_fAxis2) < 0.0f) ) 
			return FALSE; 
 
		if(fMin > 0.0f) 
		{ 
			if(pF) 
				(*pF) = fMin; 
			return TRUE; 
		} 
 
		if(pF) 
			(*pF) = fMax; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	BOOL ceRay::Intersects(const ceOBB& OBB, FLOAT fL, FLOAT* pF) const 
	{ 
		FLOAT e,f, fT0, fT1, fTmp; 
		FLOAT fMin = -99999.9f; 
		FLOAT fMax = 99999.9f; 
 
		const ceVec3f vP = OBB.m_vCenter - m_vOrigin; 
 
		e = OBB.m_vAxis0 * vP; 
		f = OBB.m_vAxis0 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis0) / f; 
			fT1 = (e - OBB.m_fAxis0) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis0) > 0.0f) || ((-e + OBB.m_fAxis0) < 0.0f) ) 
			return FALSE; 
 
		e = OBB.m_vAxis1 * vP; 
		f = OBB.m_vAxis1 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis1) / f; 
			fT1 = (e - OBB.m_fAxis1) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis1) > 0.0f) || ((-e + OBB.m_fAxis1) < 0.0f) ) 
			return FALSE; 
 
		e = OBB.m_vAxis2 * vP; 
		f = OBB.m_vAxis2 * m_vDir; 
 
		if( _fabs(f) > 0.00001f) 
		{ 
			fT0 = (e + OBB.m_fAxis2) / f; 
			fT1 = (e - OBB.m_fAxis2) / f; 
	 
			if(fT0 > fT1) 
			{ 
				fTmp = fT0; 
				fT1 = fT0; 
				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 - OBB.m_fAxis2) > 0.0f) || ((-e + OBB.m_fAxis2) < 0.0f) ) 
			return FALSE; 
 
		if( (fMin > 0.0f) && (fMin <= fL) ) 
		{ 
			if(pF) 
				(*pF) = fMin; 
			return TRUE; 
		} 
 
		// Kollision auf dem Strahl, aber nicht mit dem Segment 
		if(fMax > fL) 
			return FALSE; 
 
		if(pF) 
			(*pF) = fMax; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	bool ceRay::operator == (const ceRay &Ref) 
	{ 
		if (Ref.m_vDir == this->m_vDir) { 
			if (Ref.m_vOrigin == this->m_vOrigin) { 
				return true; 
			} 
		} 
	 
		return false; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
} // Namespace ZFXCE