Probleme beim Frustum Culling (behoben)
-
Hi,
ich habe versucht eine Klasse fürs Frustum Culling zu schreiben.
void Frustum::berechne_frustum() { //Die Projektionsmatrix hat nun diese Form// // | 0 1 2 3| // | 4 5 6 7| // | 8 9 10 11| // | 12 13 14 15| ///////////////////////////////// glGetFloatv(GL_PROJECTION_MATRIX, projM); //Die Modelbetrachtungsmatrix hat nun diese Form// // | 0 1 2 3| // | 4 5 6 7| // | 8 9 10 11| // | 12 13 14 15| ///////////////////////////////// glGetFloatv(GL_MODELVIEW_MATRIX, modM); clip[ 0] = modM[ 0]*projM[ 0] + modM[ 1]*projM[ 4] + modM[ 2]*projM[ 8] + modM[ 3]*projM[12]; // Normale Matrixmultiplikation Modelbetrachtungsmatrix * Projektionsmatrix clip[ 1] = modM[ 0]*projM[ 1] + modM[ 1]*projM[ 5] + modM[ 2]*projM[ 9] + modM[ 3]*projM[13]; clip[ 2] = modM[ 0]*projM[ 2] + modM[ 1]*projM[ 6] + modM[ 2]*projM[10] + modM[ 3]*projM[14]; clip[ 3] = modM[ 0]*projM[ 3] + modM[ 1]*projM[ 7] + modM[ 2]*projM[11] + modM[ 3]*projM[15]; clip[ 4] = modM[ 4]*projM[ 0] + modM[ 5]*projM[ 4] + modM[ 6]*projM[ 8] + modM[ 7]*projM[12]; clip[ 5] = modM[ 4]*projM[ 1] + modM[ 5]*projM[ 5] + modM[ 6]*projM[ 9] + modM[ 7]*projM[13]; clip[ 6] = modM[ 4]*projM[ 2] + modM[ 5]*projM[ 6] + modM[ 6]*projM[10] + modM[ 7]*projM[14]; clip[ 7] = modM[ 4]*projM[ 3] + modM[ 5]*projM[ 7] + modM[ 6]*projM[11] + modM[ 7]*projM[15]; clip[ 8] = modM[ 8]*projM[ 0] + modM[ 9]*projM[ 4] + modM[10]*projM[ 8] + modM[11]*projM[12]; clip[ 9] = modM[ 8]*projM[ 1] + modM[ 9]*projM[ 5] + modM[10]*projM[ 9] + modM[11]*projM[13]; clip[10] = modM[ 8]*projM[ 2] + modM[ 9]*projM[ 6] + modM[10]*projM[10] + modM[11]*projM[14]; clip[11] = modM[ 8]*projM[ 3] + modM[ 9]*projM[ 7] + modM[10]*projM[11] + modM[11]*projM[15]; clip[12] = modM[12]*projM[ 0] + modM[13]*projM[ 4] + modM[14]*projM[ 8] + modM[15]*projM[12]; clip[13] = modM[12]*projM[ 1] + modM[13]*projM[ 5] + modM[14]*projM[ 9] + modM[15]*projM[13]; clip[14] = modM[12]*projM[ 2] + modM[13]*projM[ 6] + modM[14]*projM[10] + modM[15]*projM[14]; clip[15] = modM[12]*projM[ 3] + modM[13]*projM[ 7] + modM[14]*projM[11] + modM[15]*projM[15]; //Das Ergebnis ist wieder eine 4*4 Matrix, die clip Matrix // | 0 1 2 3| // | 4 5 6 7| // | 8 9 10 11| // | 12 13 14 15| ///////////////////////////////// //Ebenen in "Hessesche Normalform": normale und Abstand zum Ursprung //rechts frustum[0][0] = clip[ 3] - clip[ 0]; //x der normalen frustum[0][1] = clip[ 7] - clip[ 4]; //y der normalen frustum[0][2] = clip[11] - clip[ 8]; //z der normalen frustum[0][3] = clip[15] - clip[12]; //Abstand der Ebene zum Ursprung NormalizePlane( 0); //links frustum[1][0] = clip[ 3] + clip[ 0]; frustum[1][1] = clip[ 7] + clip[ 4]; frustum[1][2] = clip[11] + clip[ 8]; frustum[1][3] = clip[15] + clip[12]; NormalizePlane( 1); //unten frustum[2][0] = clip[ 3] + clip[ 1]; frustum[2][1] = clip[ 7] + clip[ 5]; frustum[2][2] = clip[11] + clip[ 9]; frustum[2][3] = clip[15] + clip[13]; NormalizePlane( 2); //oben frustum[3][0] = clip[ 3] - clip[ 1]; frustum[3][1] = clip[ 7] - clip[ 5]; frustum[3][2] = clip[11] - clip[ 9]; frustum[3][3] = clip[15] - clip[13]; NormalizePlane( 3); //hinten frustum[4][0] = clip[ 3] - clip[ 2]; frustum[4][1] = clip[ 7] - clip[ 6]; frustum[4][2] = clip[11] - clip[10]; frustum[4][3] = clip[15] - clip[14]; NormalizePlane( 4); //vorne frustum[5][0] = clip[ 3] + clip[ 2]; frustum[5][1] = clip[ 7] + clip[ 6]; frustum[5][2] = clip[11] + clip[10]; frustum[5][3] = clip[15] + clip[14]; NormalizePlane( 5); } //Liegt ein Punkt im Frustum (3 Einzelkoordinaten) bool Frustum::Punkt_im_Frustum(float pX,float pY,float pZ) { return Punkt_im_Frustum(Vektor3D(pX,pY,pZ)); //Zurückführen auf die Version mit Vektor3D } bool Frustum::Punkt_im_Frustum(const Vektor3D& v) //Liegt ein Punkt im Frustum (Vektor3D) { for (int i = 0; i < 6;i++) //Für jede Ebene des Frustums testen, ob der Punkt innerhalb der Ebene ist { if (frustum[i][0]*v.x + frustum[i][1]*v.y + frustum[i][2]*v.z + frustum[i][3] <= 0.0f) { return false; //gibt es auch nur eine Ebene bei der der Punkt außerhalb liegt, so kann er nicht im Frustum sein } } return true; //liegt der Punkt vor allen 6 Ebenen, so liegt er im Frustum } bool Frustum::Linie_im_Frustum(float p1X,float p1Y,float p1Z,float p2X,float p2Y,float p2Z) //Testen, ob Teile einer Linie gegeben duch die Koordinaten der beiden Endpunkte im Frustum liegen { return Linie_im_Frustum(Vektor3D(p1X,p1Y,p1Z),Vektor3D(p2X,p2Y,p2Z)); //Zurückführen auf die Version mit Start- und Zielpunkt gegeben als Vektor3D } bool Frustum::Linie_im_Frustum(Vektor3D v1, Vektor3D v2) //Testen, ob Teile einer Linie gegeben duch die Koordinaten der beiden Endpunkte (als Vektor3D) im Frustum liegen { if (Punkt_im_Frustum(v1) || Punkt_im_Frustum(v2)) {return true;} //Liegt ein Eckpunkt der Linie um Frustum, so muß die Linie gemalt werden //Wenn kein Ende der Linie im Frustum liegt, teste ob der Schnittpunkt der Linie //Mit einer der 6 Ebene des Frustums im Frustum liegt. for (int i=0;i<6;i++) { if ( linie_schneidet_Ebene(v1,v2,Vektor3D(frustum[i][0],frustum[i][1],frustum[i][2]),frustum[i][3])) { if (Punkt_im_Frustum(kollision1) || Punkt_im_Frustum(kollision2)) {return true;} //Um Rundungsfehler zu vermeiden zwei Schnittpunkte testen, die jeweils etwas vor und hinter dem Schnittpunkt liegen } } return false; //Linie liegt vollkommen außerhalb des Frustums } //berechnet, ob eine Kugel gegeben als Mittelpunkt (Vektor3D) und Radius im Frustum ist bool Frustum::Kugel_im_Frustum(Vektor3D v,float radius) { //Für jede Ebene des Frustums testen, ob der Punkt innerhalb der Ebene ist for (int i = 0; i < 6;i++) { if (frustum[i][0]*v.x + frustum[i][1]*v.y + frustum[i][2]*v.z + frustum[i][3] <= -radius) { return false; } } return true; }
Das Problem ist, dass die Methode Kugel_im_Frustum nicht funktioniert, da die Kugel nur als "im Frustum" erkannt wird (also "true" zurückliefert), wenn der Mittelpunkt im Frustum liegt.
(Die Methoden Punkt_im_Frustum und Linie_im_Frustum funktionieren wie gewünscht, daraus schließe ich , das die Methode "berechne_frustum" funktioniert)
Was habe ich bei der Methode "Kugel_im_Frustum" falsch gemacht?
-
zeig mal die funktion "NormalizePlane()".
-
DANKE!!!!!!!!!!!!!
Genau in dieser Methode ist der Fehler. Beim Invertieren der Länge.
void Frustum::NormalizePlane(int pPlane) { float laenge; laenge = sqrt(frustum[pPlane][0]*frustum[pPlane][0]+frustum[pPlane][1]*frustum[pPlane][1]+frustum[pPlane][2]*frustum[pPlane][2]); //Brerechne Entfernung zwischen gegebenem Punkt(der am nächsten am 0 Punkt ist) der ebene und dem 0 Punkt laenge=laenge/1.0f; //Invertieren der Entfernung frustum[pPlane][0] = frustum[pPlane][0]*laenge; //teilen durch die Entfernung frustum[pPlane][1] = frustum[pPlane][1]*laenge; frustum[pPlane][2] = frustum[pPlane][2]*laenge; frustum[pPlane][3] = frustum[pPlane][3]*laenge; }
Ich habs sooooooo oft gelsesen und den Fehler einfach übersehen.
Erst mit deinem Hinweis diese Methode genauer zu betrachten ist mir der
Fehler aufgefallen. (Da ich den Fehler immer in "Kugel_im_Frustum" vermutet habe)laenge=laenge/1.0f;
muß natürlich wie folgt aussehen:
laenge=1.0f/laenge;
Jetzt klappt alles wie es soll.