[OpenGL]evtl Problem beim sortieren der Normalen?



  • Hallo,

    ich habe ein Problem bei den Rendern eines Objektes bei Licht.

    Ich lade die Normalen aus einer .obj Datei. vn=die normale, v=Vektoren ,f=Flächen mit Indices die auf die Vektoren und Normalen verweisen.

    So sieht z.B. eine .obj Datei aus

    v 1.000000 -1.000000 -1.000000
    v 1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 -1.000000
    v 1.000000 1.000000 -0.999999
    v 0.999999 1.000000 1.000001
    v -1.000000 1.000000 1.000000
    v -1.000000 1.000000 -1.000000
    vn 0.000000 -1.000000 0.000000
    vn 0.000000 1.000000 0.000000
    vn 1.000000 0.000000 0.000000
    vn -0.000000 -0.000000 1.000000
    vn -1.000000 -0.000000 -0.000000
    vn 0.000000 0.000000 -1.000000
    usemtl Material
    s off
    f 1//1 2//1 3//1
    f 1//1 3//1 4//1
    f 5//2 8//2 7//2
    f 5//2 7//2 6//2
    f 1//3 5//3 6//3
    f 1//3 6//3 2//3
    f 2//4 6//4 7//4
    f 2//4 7//4 3//4
    f 3//5 7//5 8//5
    f 3//5 8//5 4//5
    f 5//6 1//6 4//6
    f 5//6 4//6 8//6
    

    Nach dem einlesen (und umsortieren) übergebe ich die Normalen über glNormalPointer(GL_FLOAT,0,&vectorNormals[0]);

    Bei Kugelen sah das schon ganz gut aus:
    http://imageshack.us/photo/my-images/11/kugeln.png/
    Hier gibt es scheinbar Probleme bei entgegen gerichteten (glaube ich).

    Bei einem Würfel scheint es gar nicht zu funktionieren:
    http://imageshack.us/photo/my-images/210/wuerfel.png/
    Auch bei anderen Modeln gibt es Probleme und ich tappe im Dunkeln woran es genau liegt.

    hier mein Code zum Laden des Models:

    vector<GLfloat> vertices;		//Liste aller Punkte eines Models
    vector<GLuint> indices;			//Gibt an wie die Punkte miteinander verknüpft sind über ihre Indices. 3 Indices von 3 Punkten ergeben ein Polygone.
    vector<GLfloat> normals;		//Sämtliche existierenden Vectornormalen
    vector<GLint> normalsIndices;	//Gibt an welche Vectornormalen an welchen Punkt anliegen.
    vector<GLfloat> vectorNormals;   //Die sortierten Normalen
    
    void loadObject()
    {
    
        float x,y,z;			//Speichert die x,y,z Koordinate eines Vertexes
        int v1,v2,v3;			//Die indexe 3er Punkte eines Polygones
        float vn1,vn2,vn3;		//Die 3 Parameter einer Vertexnormalen
    	int vni1,vni2,vni3;		//Die Indexe der 3 Vertexnormalen der 3 Punkte des Polygones
    
        ifstream file;
        char buffer[100];
        string line;
    
        file.open("Cube.obj");
        cout << "Obj File Loader" << endl;
    
        while(!file.eof())
        {
            file.getline(buffer,100);
            line=buffer;
    
            if(!line.find("v "))
            {
                sscanf(line.c_str(),"v %f %f %f",&x,&y,&z);
                vertices.push_back(x);
                vertices.push_back(y);
                vertices.push_back(z);
            }
            else if(!line.find("f "))
            {
                sscanf(line.c_str(),"f %d//%d %d//%d %d//%d",&v1,&vni1,&v2,&vni2,&v3,&vni3);
                indices.push_back(v1-1);
                indices.push_back(v2-1);
                indices.push_back(v3-1);
    			normalsIndices.push_back(vni1-1);
                normalsIndices.push_back(vni2-1);
                normalsIndices.push_back(vni3-1);
            }
    		else if(!line.find("vn "))
            {
                sscanf(line.c_str(),"vn %f %f %f",&vn1,&vn2,&vn3);
                normals.push_back(vn1);
                normals.push_back(vn2);
                normals.push_back(vn3);
            }
        }
    
    	vectorNormals.resize(normalsIndices.size()*3);
    	//erstelle die sortieren Normalenliste:
        for(int i=0; i<indices.size();i++)
    	{
    
    		vectorNormals[indices[i]*3]=normals[normalsIndices[i]*3];
    		vectorNormals[indices[i]*3+1]=normals[normalsIndices[i]*3+1];
    		vectorNormals[indices[i]*3+2]=normals[normalsIndices[i]*3+2];
    
        }
        file.close();
    }
    

    Für Hilfe danke ich schonmal im voraus!

    MfG

    Cyphron


  • Mod

    Cyphron schrieb:

    //erstelle die sortieren Normalenliste:
        for(int i=0; i<indices.size();i++)
    	{
    
    		vectorNormals[indices[i]*3]=normals[normalsIndices[i]*3];
    		vectorNormals[indices[i]*3+1]=normals[normalsIndices[i]*3+1];
    		vectorNormals[indices[i]*3+2]=normals[normalsIndices[i]*3+2];
    
        }
    }
    

    zeile 17 und zeile 21 aus deinem geposteten obj haben den selben 'indices' wert aber unterschiedliche 'normalindices', wie soll das funktionieren?



  • rapso schrieb:

    Cyphron schrieb:

    //erstelle die sortieren Normalenliste:
        for(int i=0; i<indices.size();i++)
    	{
    
    		vectorNormals[indices[i]*3]=normals[normalsIndices[i]*3];
    		vectorNormals[indices[i]*3+1]=normals[normalsIndices[i]*3+1];
    		vectorNormals[indices[i]*3+2]=normals[normalsIndices[i]*3+2];
    
        }
    }
    

    zeile 17 und zeile 21 aus deinem geposteten obj haben den selben 'indices' wert aber unterschiedliche 'normalindices', wie soll das funktionieren?

    Die .obj Datei hab ich nicht selber erstellt sondern Blender.

    Die von dir zitierte Schleife soll die Normalen so sortiert in den neuen Vektor speichern, dass sie in der Reihenfolge stehen, wie sie von OpenGL benötigt werden.

    Die Indices verweisen auf einen Vektor. Die Normalen Indices auf die dazugehörige Normale.

    Also:
    f index//normalenindex ...

    Die Normalen müssen demnach umsortiert werden da z.B. die Normale mit dem index 1 (vn 0.000000 -1.000000 0.000000) 6mal gebraucht wird.

    Jedenfalls so wie ich das verstanden habe mit glNormalPointer()

    hier nochmal mein Code wie ich OpenGL meine Daten übermittle:

    liste = glGenLists(1);
    
        glNewList(liste, GL_COMPILE);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
    
        glNormalPointer(GL_FLOAT,0,&vectorNormals[0]);
        glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
    	glDrawElements(GL_TRIANGLES, indices.size(),GL_UNSIGNED_INT,&indices[0]);
    
    	glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);
        glEndList();
    

  • Mod

    dann nochmal

    Cyphron schrieb:

    [b]v 1.000000 -1.000000 -1.000000[/b]
    v 1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 -1.000000
    v 1.000000 1.000000 -0.999999
    v 0.999999 1.000000 1.000001
    v -1.000000 1.000000 1.000000
    v -1.000000 1.000000 -1.000000
    [b]vn 0.000000 -1.000000 0.000000[/b]
    vn 0.000000 1.000000 0.000000
    [b]vn 1.000000 0.000000 0.000000[/b]
    vn -0.000000 -0.000000 1.000000
    vn -1.000000 -0.000000 -0.000000
    vn 0.000000 0.000000 -1.000000
    usemtl Material
    s off
    f 1//1 2//1 3//1
    f 1//3 5//3 6//3
    

    ich habe dir fuer zwei faces aus deinem blender obj file die normalen und die position vom ersten vertex beider faces markeirt.

    ich hoffe jetzt ist dir dein fehler offensichtlicher.



  • @rapso

    also ich dachte eigentlich das wäre so korrekt.
    Denn der Vertex 1 gehört ja zu beiden Flächen bzw insg. 5 Flächen.

    Die beiden Flächen "blicken" auch in die jeweilige Richtung.

    Tut mir leid das ich grade nicht verstehe was du meinst 😞


  • Mod

    Cyphron schrieb:

    @rapso

    also ich dachte eigentlich das wäre so korrekt.
    Denn der Vertex 1 gehört ja zu beiden Flächen bzw insg. 5 Flächen.

    Die beiden Flächen "blicken" auch in die jeweilige Richtung.

    Tut mir leid das ich grade nicht verstehe was du meinst 😞

    vielleicht versteh ich ja etwas an deinem code nicht, kannst du mir nochmal sagen, wie du die zwei faces die
    1. eine position haben

    v 1.000000 -1.000000 -1.000000
    

    2. die in zwei verschiedene richtungen zeigen

    vn 0.000000 -1.000000 0.000000
    vn 1.000000 0.000000 0.000000
    

    mit nur einem vertex representieren kannst, ohne dass es falsch ausschaut?



  • Na es ist doch so das ein Würfel 8 Ecken Hat. Deswegen 8mal v.
    Über glVertexPointer(3, GL_FLOAT, 0, &vertices[0]); gebe ich OpenGL diese Ecken
    (8x3 für x,y,z).

    Dann muss man noch festlegen wie der Körper Zusammengesetzt wird.
    dies sage ich über:

    f 1//1 2//1 3//1
    

    Jedes f ist hierbei eine Fläche. Statt jedes mal die x,y,z Werte hinzuschreiben wird nur der Index aus der v liste hingeschrieben. Also Fläche 1,2,3 nutzt (die erste)

    v 1.000000 -1.000000 -1.000000
    v 1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 1.000000
    

    Dadurch wird viel Redundanz eingespart und da ich die Daten der Ecken in den Grafikkartenspeicher lege spare ich somit wertvollen Speicher auf der Grafikkarte.

    Die Indices ist die Liste die OpenGl sagt wie es zusammengebaut wird.
    (Indices nach einlesen: (1,2,3,1,5,6....). Übergeben tu ich dieses Indices über:

    glDrawElements(GL_TRIANGLES, indices.size(),GL_UNSIGNED_INT,&indices[0]);
    

    Da ich als "Modus" GL_TRIANGLES angegeben habe, nutzt OpenGL jeweils 3 Indices (die auf eine Ecke des Würfels verweisen) um Damit 1 Dreieck zu Zeichnen. Dies ergibt bei 6 Flächen des Würfels 12 Polygone da der Würfel Trianguliert wurde.

    Durch die Triangulierung ist es theoretisch möglich das 6 Flächen (aber Mind 2) einen Eckpunkt nutzen. Bei diesen sind es 5.

    Bei den Normalen ist es so wie bei den Ecken das sie über Ihren Index referenziert werden. Zwar hat jede Fläche in diesem Fall nur eine Normale (deswegen 3 mal 1 bei f 1//1 2//1 3//1), das muss aber nicht immer so sein. Z.B bei Kugeln (oder anderen Rundungen):

    Flat Shading(1 Normale je Fläche)vs Smooth Shading(1 Normale je Eckpunkt):
    http://imageshack.us/photo/my-images/233/31872976.png/

    mein Problem ist aber nun die Normalen in OpenGL geeignet zu übermitteln (deswegen die Umsortierung). Bei den Eckpunkten ist es kein Problem weil man deren indices übergeben kann. Die Normalenindices leider aber nicht 😞

    Das Problem liegt also hier:

    //erstelle die sortieren Normalenliste:
        for(int i=0; i<indices.size();i++)
        {
    
            vectorNormals[indices[i]*3]=normals[normalsIndices[i]*3];
            vectorNormals[indices[i]*3+1]=normals[normalsIndices[i]*3+1];
            vectorNormals[indices[i]*3+2]=normals[normalsIndices[i]*3+2];
        }
    

  • Mod

    ich wiederhole es gerne noch ein drittes mal:

    wie soll dein sortiercode funktionieren bei dem fall, dass du zwei faces hast, die dieselbe position beim ersten vertex haben, aber ZWEI UNTERSCHIEDLICHE normalen?



  • rapso schrieb:

    ich wiederhole es gerne noch ein drittes mal:

    wie soll dein sortiercode funktionieren bei dem fall, dass du zwei faces hast, die dieselbe position beim ersten vertex haben, aber ZWEI UNTERSCHIEDLICHE normalen?

    Ich kann dein Problem an diesen Punkt überhaupt nicht verstehen. 2 Faces mit 2 Blickrichtungen. Jeder Punkt hat eine Normale für JEDES Face. Aus dem Punkt muss ich dir wiedersprechen das dort ein Wiederspruch beseht.

    hier meine Sortierte normalenliste für die Beiden Faces:

    Face:1
    0:-1:0
    0:-1:0
    0:-1:0
    Face:2
    1:0:0
    1:0:0
    1:0:0
    

    <<genauso hatte ich es auch erwartet...

    Das ganze klappt bei Komplexen Körpern wunderbar. Vll ist es auch gar kein Fehler sondern das Ergebniss entsprach nur nicht meinen erwarungen was das "Beleuchtungslevel" der einzelnen Flächen angeht.

    hier nochmal ne Genmanipulierte Banane:
    http://imageshack.us/photo/my-images/213/dingw.png/

    Ist das was ich erwartet habe.

    Edit sez:
    Ich mach jetzt einfach mit Texturierung und Material weiter.


  • Mod

    Cyphron schrieb:

    rapso schrieb:

    ich wiederhole es gerne noch ein drittes mal:

    wie soll dein sortiercode funktionieren bei dem fall, dass du zwei faces hast, die dieselbe position beim ersten vertex haben, aber ZWEI UNTERSCHIEDLICHE normalen?

    Ich kann dein Problem an diesen Punkt überhaupt nicht verstehen. 2 Faces mit 2 Blickrichtungen. Jeder Punkt hat eine Normale für JEDES Face. Aus dem Punkt muss ich dir wiedersprechen das dort ein Wiederspruch beseht.

    du uebergibst deine positionen, normalen, texturcoordinaten aber nicht nicht pro face sondern pro vertex. dafuer hast du ja deine wundersame "transformation" entwickelt.

    initialisiere dein vectorNormals mit (0|0|0) normalen, und steppe ein paar mal durch den loop, du wirst erkennen, dass du auf eine schon zugewiesene stelle nochmals eine _andere_ normale zuweist.

    du wirst dasselbe problem mit texturcoordinates haben, wenn du dort auch soeine wundersame "transformation" machst.



  • ok da hast du recht. Ich hatte dich völlig anders verstanden. Ich dachte du meintest die Datenstruktur...

    ich habe jetzt meinen schleifenrumpf abgewandelt:

    vectorNormals[i*3]=normals[normalsIndices[i]*3];
    	vectorNormals[i*3+1]=normals[normalsIndices[i]*3+1];
    	vectorNormals[i*3+2]=normals[normalsIndices[i]*3+2];
    

    Ergebniss nachher:

    Index:1- Normale:1=0:-1:0
    Index:2- Normale:1=0:-1:0
    Index:3- Normale:1=0:-1:0
    Index:1- Normale:1=0:-1:0
    Index:3- Normale:1=0:-1:0
    Index:4- Normale:1=0:-1:0
    Index:5- Normale:2=0:1:0
    Index:8- Normale:2=0:1:0
    Index:7- Normale:2=0:1:0
    Index:5- Normale:2=0:1:0
    Index:7- Normale:2=0:1:0
    Index:6- Normale:2=0:1:0
    Index:1- Normale:3=1:0:0
    Index:5- Normale:3=1:0:0
    Index:6- Normale:3=1:0:0
    Index:1- Normale:3=1:0:0
    Index:6- Normale:3=1:0:0
    Index:2- Normale:3=1:0:0
    Index:2- Normale:4=-0:-0:1
    Index:6- Normale:4=-0:-0:1
    Index:7- Normale:4=-0:-0:1
    Index:2- Normale:4=-0:-0:1
    Index:7- Normale:4=-0:-0:1
    Index:3- Normale:4=-0:-0:1
    Index:3- Normale:5=-1:-0:-0
    Index:7- Normale:5=-1:-0:-0
    Index:8- Normale:5=-1:-0:-0
    Index:3- Normale:5=-1:-0:-0
    Index:8- Normale:5=-1:-0:-0
    Index:4- Normale:5=-1:-0:-0
    Index:5- Normale:6=0:0:-1
    Index:1- Normale:6=0:0:-1
    Index:4- Normale:6=0:0:-1
    Index:5- Normale:6=0:0:-1
    Index:4- Normale:6=0:0:-1
    Index:8- Normale:6=0:0:-1
    

    Damit sehen zwar die Werte Richtig aus aber beim Rendern der Kugeln sieht das dann z.b. so aus (natürlich mit anderen daten als die für den Würfel):
    http://imageshack.us/photo/my-images/687/kugeln.png/

    😞

    Kann es sein das ich das selbe wie mit den Normalen auch mit den Vertices machen muss?


  • Mod

    du musst neue vertices erstellen, ja! (aus position|normal|texcoord)



  • rapso schrieb:

    du musst neue vertices erstellen, ja! (aus position|normal|texcoord)

    verdammt 😞

    Danke für die Hilfe 👍


  • Mod

    ach ja, schau dir bei glVertexPointer(3, GL_FLOAT, 0, &vertices[0]) den 3ten parameter an, er ist speziell dafuer gedacht solche vertices zu haben/unterstuetzen.



  • rapso schrieb:

    ach ja, schau dir bei glVertexPointer(3, GL_FLOAT, 0, &vertices[0]) den 3ten parameter an, er ist speziell dafuer gedacht solche vertices zu haben/unterstuetzen.

    Ich hatte das als eine art "Offset" zwischen vertices verstanden. so das z.b. daten dazwischen stehen könnten. Z.B. Für solch einen Fall:

    struct vertex
    {
        float xyz[3];
        float uvw[3];
        float n[3];
    };
    

    Wobei der 3. Parameter dann sizof(vertex) ist. bringt dies Performancetechnische vor- bzw nachteile? Oder ist es nur als Hilfe für solche structs gedacht?


Anmelden zum Antworten