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