H
Hi !
Hier ist der Code meiner Rayclass, mit zusätzlichen Comments...
Bei Fragen könnt ihr hier posten / mir mailen
Der Code stammt wie gesagt aus meiner alten Engine,
OHNE meine Matrixklasse, d.h. ich greife auf ein
paar D3DX Funktionen zu, sollte aber kein Problem sein
die durch andere zu ersetzen...
Ich hoffe das Forum kann so lange Posts darstellen
(Hehe, wenn ich euch ärgen will würd ich jetzt Syntaxcoloring
ausscalten *gg*)
---------------------------------------------------------------------------
//smartbbox.h
class CSmartBBox
{
CSmartVector min, max;
};
---------------------------------------------------------------------------
//smartplane.h
class CSmartPlane
{
public :
CSmartVector n;
float d;
};
---------------------------------------------------------------------------
#include "smartplane.h"
#include "smartbbox.h"
#include "smartvector.h"
#include "smartinput.h"
#include "smartd3d.h"
//smartray.h
class CSmartRay
{
public :
//hiermit wird die Rayklasse m.h. der Mauskoordinaten erstellt.
//d.h. man hat dann einen Strahl den man für Intersection tests verwenden
//kann ("auf etwas in der 3D scene klicken")
void FillFromMouse ();
//naja, checkt ob der Ray ein triangle trifft,
//v MUSS ein array der größe 3 sein (CSmartVector* v = new CSmartVector[3];)
//in "t" kommt die Entfernung m_start->Punkt auf dem Triangle wo der Ray "reintraf"
BOOL IntersectTriangle (CSmartVector* v,float& t) const;
//hiermit kann man testen ob der Ray eine Boundingbox schneidet.
//wenn ja wird TRUE returned, in "in" kommt die Distanz m_start->Intersection point,
//in "out" kommt die Distanz von m_start->Punkt wo der Ray AUS der Box kommt
BOOL IntersectBoundingBox (CSmartBBox&b, float& in, float& out) const;
//intersection von dem Ray und ner Ebene, ist nüztlich für Collision detection
BOOL IntersectPlane (const CSmartPlane& p) const;
//das hier ist der Startpunkt des Rays in Weltkoordinaten
//CSmartVector ist ne Vektorklasse (*echt* ??)
CSmartVector m_start;
//das ist die Richtung in die der Ray "zeigt". Dieser Vektor
//ist normalisiert
CSmartVector m_dir;
};
---------------------------------------------------------------------------
//smartray.cpp
BOOL CSmartRay::FillFromMouse ()
{
//in rx und ry kommt die Auflösung bzw die Größe des Fensters
//GetResolution ermittelt die Werte indem es einfach die
//breite und höhe des Backbuffer returned
int rx,ry;
g_smartD3D.GetResolution (rx,ry);
//nun holen wir uns die Projection matrix von D3D
//in meiner neuen Engine gibts hier einen Fehler : D3DERR_INVALIDCALL,
//hier klappt es aber einwandfrei
D3DXMATRIX matProj;
g_smartD3D.GetD3DDevice()->GetTransform (D3DTS_PROJECTION, &matProj);
//nun wandeln wir die Mausposition (von DirectInput in diesem Fall)
//in einen 3D Punkt um
CSmartVector v;
v.x = (((2.0f * g_smartInput.m_x) / rx) - 1.0f) / matProj._11;
v.y = -(((2.0f * g_smartInput.m_y) / ry) - 1.0f) / matProj._22;
v.z = 1.0f;
//hier holen wir uns die Viewmatrix und invertieren sie
D3DXMATRIX matView, m;
g_smartD3D.GetD3DDevice()->GetTransform (D3DTS_VIEW, &matView);
D3DXMatrixInverse (&m, NULL, &matView);
//jetzt wird die Raydirection m.h. der invertierten Viewmatrix
//ermittelt.
m_dir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
m_dir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
m_dir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
//und die Startposition gesetzt
m_start.x = m._41;
m_start.y = m._42;
m_start.z = m._43;
m_dir.Normalize ();
}
---------------------------------------------------------------------------
BOOL CSmartRay::IntersectBBox (CSmartBBox&b, float& enter, float& leave)
{
//der Algorithmus den ich hier verwende heißt "Kay and Kayjia "slab" method"
//komischer Name :-)
//ich hab hier keine Comments zu der Funktion, da ich durch die Mathe
//nicht ganz durchblicke...
float tnear = -99999.0f;
float tfar = 99999.0f;
for (int i=0; i<3; i++)
{
//ich habe bei meinen Vektoren den operator [] überladen
//Bsp :
//CSmartVector v;
//v[0] = 2; // v.x = 3;
//v[1] = 3; // v.y = 2;
//v[2] = 0; // v.z = 0;
float origin = m_start[i];
float direction = m_dir[i];
float mmin = b.min[i];
float mmax = b.max[i];
if (direction)
{
direction = 1.0f / direction;
float t1 = (mmin - origin) * direction;
float t2 = (mmax - origin) * direction;
if (t1 > t2)
{
if (t2 > tnear) tnear = t2;
if (t1 < tfar) tfar = t1;
}
else
{
if (t1 > tnear) tnear = t1;
if (t2 < tfar) tfar = t2;
}
//keine intersection
if (tnear > tfar || tfar < 0.0f)
return FALSE;
}
else
{
//wieder keine Intersection
if (rigin < mmin || origin > mmax)
return FALSE;
}
}
//Werte speichern
enter = tnear;
leave = tfar;
//ray hits box
return TRUE;
}
---------------------------------------------------------------------------
BOOL CSmartRay::IntersectTriangle (CSmartVector* vv,float& t)
{
//diese Methode wurde von Möller entwickelt (k.a. wie der mit
//Vornamen heißt, er ist auf jeden Fall der größte Theoretiker
//was Mathematik usw bei Games angeht, Einfach mal was googlen...
//der Code stammt btw aus dem DX8 SDK, wo er super implementiert wurde !
//keinen NULLPointer annehmen !
assert (vv != NULL);
float u,v;
//die Eckvectoren des Triangles finden
CSmartVector edge1 = vv[1]- vv[0];
CSmartVector edge2 = vv[2]- vv[0];
//determinant berechnen, wird auch für U (texturkoordinate) verwendet
CSmartVector pvec;
pvec=CrossProduct(m_dir, edge2);
//wenn der determinant fast 0 ist, ist der Ray paralell zum Triangle (=> keine Intersection)
float det = DotProduct(edge1, pvec);
if (det < 0.0001f)
return FALSE;
//distanz von vv[0] zu m_start berechnen
CSmartVector tvec = m_start - vv[0];
//berechnen U, und check ob der Ray überhaupt treffen kann
u = DotProduct(tvec,pvec);
if (u < 0.0f || u > det)
return FALSE;
//gleich berechnen wir V (texturkoordinate)
CSmartVector qvec;
qvec=CrossProduct(tvec, edge1);
//so ähnlich wie ein paar Zeilen oben :-)
v = DotProduct(m_dir, qvec);
if (v < 0.0f || u + v > det)
return FALSE;
//distanz berechnen
t = DotProduct(edge2, qvec);
float fInvDet = 1.0f / det;
t *= fInvDet;
//juhu ! intersection
return TRUE;
}
---------------------------------------------------------------------------
BOOL CSmartRay::IntersectPlane (const CSmartPlane& p) const
{
//diesmal ziemlich kurz, he ?
float dista = m_start.Length ();
float distb = (m_start + m_dir).GetLength();
if ((dista > 0.0f)&&(distb < 0.0f)) return TRUE;
if ((dista < 0.0f)&&(distb > 0.0f)) return TRUE;
return FALSE;
}
---------------------------------------------------------------------------