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.


Log in to reply