0
Komisch, dass ihr immer von einem unendlich großen Kegel ausgeht. In meiner Gedankenwelt gibts nur Kegel mit Deckel drauf
Nachdem mir die Mathe für WebFritzi's Verfahren gefehlt hat, habe ich nun meines umgesetzt. Und es funktioniert erstaunlicherweise sogar.
Und für den Fall, dass das mal jemand wieder braucht, hier der Code: (die Vektorfunktionen sollten selbsterklärend sein)
#define VEC3 D3DXVECTOR3
bool Util::KollisionKonusGerade( D3DXVECTOR3* vPos, // Ein Punkt auf der Geraden
D3DXVECTOR3* vDir, // dir Richtung der Geraden
D3DXVECTOR3* vKonusSpitze, // Position der Kegelspitze
D3DXVECTOR3* vKonusDir, // Ausrichtung des Kegels, die Länge dieses Vektors entspricht der Kegelhöhe
float fKonusWinkel ) // Kegelwinkel
{
// Radius des Bodens:
float fBodenRadius = D3DXVec3Length( vKonusDir ) * sinf( fKonusWinkel * 0.5f );
if( !VektorenSenkrecht( vDir, vKonusDir ) )
{
// Als erstes mal testen, ob der Strahl den Boden vom Kegel trifft:
// Schnittpunkt Gerade-Ebene:
float r = D3DXVec3Dot( vKonusDir, &(((*vKonusSpitze)+(*vKonusDir))-(*vPos)) ) /
D3DXVec3Dot( vKonusDir, vDir );
VEC3 vSchnitt = *vPos + r * (*vDir);
// Schnittpunkt innerhalb des Kreises?
VEC3 vAbstand = (*vKonusSpitze + *vKonusDir) - vSchnitt;
if( D3DXVec3Dot( &vAbstand, &vAbstand ) < (fBodenRadius * fBodenRadius) )
return true;
}
if( !VektorenParallel( vDir, vKonusDir ) )
{
// Den Punkt auf der Kegelachse berechnen der der Geraden am nächsten ist:
VEC3 vPunkt;
VEC3 n;
D3DXVec3Cross( &n, vDir, vKonusDir );
float zaehler = -(
vDir->x * ( n.y * (vPos->z-vKonusSpitze->z) - n.z * (vPos->y-vKonusSpitze->y) ) -
vDir->y * ( n.x * (vPos->z-vKonusSpitze->z) - n.z * (vPos->x-vKonusSpitze->x) ) +
vDir->z * ( n.x * (vPos->y-vKonusSpitze->y) - n.y * (vPos->x-vKonusSpitze->x) ) );
float nenner = vDir->x * (vKonusDir->y * n.z - vKonusDir->z * n.y) -
vDir->y * (vKonusDir->x * n.z - vKonusDir->z * n.x) +
vDir->z * (vKonusDir->x * n.y - vKonusDir->y * n.x);
if( nenner == 0.0f )
return false;
float r = zaehler / nenner;
vPunkt = *vKonusSpitze + r * (*vKonusDir);
// Liegt der Punkt hinter der Kegelspitze?
if( D3DXVec3Dot( vKonusDir, &(vPunkt-*vKonusSpitze) ) < 0 )
return false;
// Abstand Punkt - Gerade:
VEC3 vTemp;
float dg = D3DXVec3Length( D3DXVec3Cross( &vTemp, vDir, &(vPunkt-(*vPos)) ) ) /
D3DXVec3Length( vDir );
// Wenn der Abstand größer als der Bodenradius ist, trifft die Gerade schonmal nicht:
if( dg > fBodenRadius )
return false;
// Senkrechter Abstand des Punktes ( der ja auf der Kegelachse liegt ) zur Kegelspitze:
float dp = D3DXVec3Length( &(vPunkt - *vKonusSpitze) );
// Liegt der Punkt vor dem Boden?
if( dp > D3DXVec3Length( vKonusDir ) )
return false;
// Liegt der Punkt denn jetzt im Kegel?
return( dg < dp * sinf( fKonusWinkel * 0.5f ) );
}
return false;
}
Es ist bestimmt nicht sonderlich schnell, aber bei mir ist der Code nicht zeitkritisch also scheiß ich drauf.