[OpenGL] Man sieht ein kleines Häufchen Elend :D (anstatt des 3D-Models)



  • Tagchen C++ - Forum.

    Ich hab hier ein etwas seltsames Phänomen bei Vertex Buffer Objects. Zuvor hatte ich jeweils einen eigenen Buffer für Vertexkoordinaten, Vertexfarben, VertexNormalen und Texturkoordinaten. Da dies Performancemäßig nicht grad die ideale Lösung ist, hab ich mir gedacht, dem Tutorial hier zu folgen und Die Daten als Serialized Arrays zu speichern. Nun ist aber folgendes Passiert - aus meinem schönen 3D-Modell ist ein kleines Häufchen irgendwas geworden.

    Ich poste mal ein wenig Code:

    Folgendes geschieht beim Laden des Meshes:

    // Get vertice and triangle count
        unsigned int numVert = meshes[numMeshes].numVert = mesh->vertCount();
        unsigned int numTris = meshes[numMeshes].numTris = mesh->TrisCount();
    
        glGenBuffers(2, meshes[numMeshes].Buffers);
    
        // Copy indices to buffer
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshes[numMeshes].Buffers[1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, numTris*sizeof(AL_Triangle),
                     mesh->getTrianglePointer(), GL_STREAM_DRAW);
        // Reserve video memory
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].Buffers[0]);
        glBufferData(GL_ARRAY_BUFFER,
                     numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)+sizeof(AL_VertCrd)),
                     0, GL_STREAM_DRAW);
    
        // Copy Vertex Data
        glBufferSubData(GL_ARRAY_BUFFER,
                        0,
                        numVert*sizeof(AL_VertCol),
                        mesh->getColorPointer());
        glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*sizeof(AL_VertCol),
                        numVert*sizeof(AL_VertTex),
                        mesh->getUVCoordPointer());
        glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)),
                        numVert*sizeof(AL_VertNor),
                        mesh->getNormalPointer());
        glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)),
                        numVert*sizeof(AL_VertCrd),
                        mesh->getCoordPointer());
    
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        numMeshes++;
    

    Beim rendern gehe ich so vor:

    // Bind buffer of the Mesh to draw
        glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].Buffers[0]);
        // Check if the mesh hasn't changed during calls
        if (lastMesh != Id)
        {
                // Specify Data offsets in the buffer
                glColorPointer(4, GL_UNSIGNED_BYTE, 0,0);
                glTexCoordPointer(2, GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*sizeof(AL_VertCol)));
                glNormalPointer(GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex))));
                glVertexPointer(3, GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor))));
                lastMesh = Id;
        }
        // Bind Index Buffer
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,meshes[Id].Buffers[1]);
        // Draw
        glDrawRangeElements(GL_TRIANGLES, 0,meshes[Id].numTris*3-1,meshes[Id].numTris*3,
                            GL_UNSIGNED_INT,NULL);
    

    Habe ich irgendetwas im Artikel falsch verstanden? So wie ich das Verstanden habe ist der letzte Parameter bei gl*Pointer bei VBOs ein Offset im Buffer, stimmt das? Die Framerate ist eher ziemlich gedroppt anstatt anzusteigen.

    Hier screenshots:
    mehrere Buffer
    ein Buffer


  • Mod



  • rapso schrieb:

    dein stride parameter ist falsch.

    http://opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/colorpointer.html

    So wie ich das verstanden habe gibt stride an, wie viele Bytes sich zwischen zwei gültigen Werten befinden. Da es sich bei mir nicht um Interleaved Arrays sondern um Serialized arrays handelt, dachte ich es kommt hier eine 0 hin.

    Hab ich das irgendwie falsch verstanden? Ich hab nämlich die vorstellung dass mein buffer so gefüllt wird:

    --------------------------------
    |Cols|TexCrds|Nors|Crds|
    --------------------------------

    und ich dann bei gl*pointer den letzten Parameter mit dem Byteoffset bis zu den entsprechenden daten besetze.

    Also Frage: Was kommt denn bei stride hin? Die Bytegröße eines Attributs?


  • Mod

    Azrael, il Meraz schrieb:

    [
    So wie ich das verstanden habe gibt stride an, wie viele Bytes sich zwischen zwei gültigen Werten befinden.

    genau "stride specifies the byte stride"

    Da es sich bei mir nicht um Interleaved Arrays sondern um Serialized arrays handelt, dachte ich es kommt hier eine 0 hin.

    tut mir leid, es gibt nur packed oder interleaved.

    Hab ich das irgendwie falsch verstanden? Ich hab nämlich die vorstellung dass mein buffer so gefüllt wird:

    --------------------------------
    |Cols|TexCrds|Nors|Crds|
    --------------------------------

    und ich dann bei gl*pointer den letzten Parameter mit dem Byteoffset bis zu den entsprechenden daten besetze.

    stride ist der vorletzte parameter.

    Also Frage: Was kommt denn bei stride hin? Die Bytegröße eines Attributs?

    die antwort in der verlinkten doku sagt : "stride specifies the byte stride from one color to the next allowing vertexes"



  • Ich habe die Dokumentation durchgelesen.
    aber zwischen meinen Datensätzen soll garkein Abstand sein. Sie sollen nebeneinander liegen. Ich habe das so verstanden dass ich genau dass erreiche wenn ich mit glBufferSubData() in den Buffer schreibe...

    Also etwa so:

    Buffer:

    ------------------
    |uuuuuuuuuuuuuuuu|
    ------------------
    u für ungültigen speicher
    
    glBufferData(GL_ARRAY_BUFFER,
                     numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)+sizeof(AL_VertCrd)),
                     0, GL_STREAM_DRAW);
    

    Buffer:

    ------------------
    |aaaaaaaaaaaaaaaa|
    ------------------
    a für alloziierten speicher
    
    glBufferSubData(GL_ARRAY_BUFFER,
                        0,
                        numVert*sizeof(AL_VertCol),
                        mesh->getColorPointer());
    

    Buffer:

    ------------------
    |ccccaaaaaaaaaaaa|
    ------------------
    c für color
    
    glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*sizeof(AL_VertCol),
                        numVert*sizeof(AL_VertTex),
                        mesh->getUVCoordPointer());
    

    Buffer:

    ------------------
    |ccccttttaaaaaaaa|
    ------------------
    t für texture coordinates
    
    glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)),
                        numVert*sizeof(AL_VertNor),
                        mesh->getNormalPointer());
    

    Buffer:

    ------------------
    |ccccttttnnnnaaaa|
    ------------------
    n für normals
    
    glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)),
                        numVert*sizeof(AL_VertCrd),
                        mesh->getCoordPointer());
    

    Buffer:

    ------------------
    |ccccttttnnnnvvvv|
    ------------------
    v für vertex coordinates
    

    Hab ich DAS HIER falsch verstanden? Für mich sieht das nämlich so aus als würden die Daten hintereinander im Buffer stehen. was in dem oZone3D-Artikel als Serialized Array (was wohl nichts anderes als ein packed array ist) bezeichnet wird.

    Dementsprechend stell ich mit das mit den gl*Pointern so vor:

    glColorPointer(4, GL_UNSIGNED_BYTE, 0,0);
    

    Buffer:

    ------------------
    |ccccttttnnnnvvvv|
    -^----------------
     |cp
    cp für colorpointer
    
    glTexCoordPointer(2, GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*sizeof(AL_VertCol)));
    

    Buffer:

    ------------------
    |ccccttttnnnnvvvv|
    -^---^------------
     |cp |tp
    tp für texture coordinates pointer
    
    glNormalPointer(GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex))));
    

    Buffer:

    ------------------
    |ccccttttnnnnvvvv|
    -^---^---^--------
     |cp |tp |np
    np für normal pointer
    
    glVertexPointer(3, GL_FLOAT, 0,
                    BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor))));
    

    Buffer:

    ------------------
    |ccccttttnnnnvvvv|
    -^---^---^---^----
     |cp |tp |np |vp
    vp für vertex coordinates pointer
    

    Mir ist schon klar dass ich hier an irgendeiner Stelle einen Fehler mache. Aber der liegt daran dass ich nicht wirklich verstehe, WAS ich falsch mache. Wenn ein Array doch packed ist, dann ist der Stride doch 0 oder sizeof(ArrayElement) ? das zweite führt zum selben Ergebnis...
    Ich verstehs echt nicht


  • Mod

    du kannst entweder packed haben

    |ccccc|
    |vvvvv|
    

    dabei ist es der graka bzw egal wieviel platz zwischen den buffern ist. da ogl aber weiss wie gross ein element ist, kannst du als stride 0 angeben, weil der stride sizeof(element) ist

    zweite moeglichkeit ist interleaved

    |tcvtcvtcvtcv|
    

    da ogl nun nicht wissen kann wieviel platz zwischen den elementen ist, musst du bei stride sizeof(c)+sizeof(t)+sizeof(v), also die vertexgroesse angeben.



  • Was macht denn dieses "BUFFER_OFFSET" bei dir? Weil auf den ersten Blick sieht es sonst soweit ok aus. Bist mal mit dem Debuigger durch, ob deine Zeiger die du übergibts auch alle richtig sind?



  • rapso schrieb:

    du kannst entweder packed haben

    |ccccc|
    |vvvvv|
    

    dabei ist es der graka bzw egal wieviel platz zwischen den buffern ist. da ogl aber weiss wie gross ein element ist, kannst du als stride 0 angeben, weil der stride sizeof(element) ist

    zweite moeglichkeit ist interleaved

    |tcvtcvtcvtcv|
    

    da ogl nun nicht wissen kann wieviel platz zwischen den elementen ist, musst du bei stride sizeof(c)+sizeof(t)+sizeof(v), also die vertexgroesse angeben.

    joa. Ich habe bei mir die obere Version.

    Pellaeon schrieb:

    Was macht denn dieses "BUFFER_OFFSET" bei dir? Weil auf den ersten Blick sieht es sonst soweit ok aus. Bist mal mit dem Debuigger durch, ob deine Zeiger die du übergibts auch alle richtig sind?

    #define BUFFER_OFFSET(i) (reinterpret_cast<char*>(NULL)+i)
    

    Das Makro hab ich aus dem Artikel und in der Doku stehts auch als

    #define BUFFER_OFFSET(i) ((char*)NULL+(i))

    Davor hatte ich das auch so drin, Ergebnis war nicht anders. Die pointer sind alle richtig. hab sie mir auch als arrays anzeigen lassen - die Daten stimmen.

    Ich hab grad aber etwas viel seltsameres entdeckt:
    glGenBuffers(2, meshes[numMeshes].Buffers);
    scheint einen Buffer overflow zu verursachen und zwar einen ziemlich heftigen.

    typedef struct
    {
        GLuint Buffers[2];
        GLuint numVert;
        GLuint numTris;
    }AL_MeshData;
    

    meshes ist ein statisches Array von diesem Typ... was kann hier falsch sein? Oo

    [Edit] Muss eine Spinnerei von gdb sein - der Springt nämlich inklusive der Watches in einen ziemlich seltsamen zustand und kommt danach wieder zurück. Oder die Grakatreiber verwirren ihn Oo... auf jeden Fall sind die Zeiger gültig und die Daten auch



  • Also ich würde in der Rendermethode mal die VBO-Sachen auskommentieren und es mit den normalen Vertexarrays probieren. Wenn das geht, dann sukzessive VBO für VBO dazunehmen und schauen ab wann es zur Fehldarstellung kommt, um die Fehlerquelle zu lokalisieren.

    MfG Pellaeon

    PS: dir reicht auch 1 VBO-ID pro Modell, die du jeweils für ARRAY und ELEMENT verwenden kannst



  • glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].Buffer);
        /*if (lastMesh != Id)
        {
                glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(AL_VertCol),0);
                glTexCoordPointer(2, GL_FLOAT, sizeof(AL_VertTex),
                    BUFFER_OFFSET(meshes[numMeshes].numVert*sizeof(AL_VertCol)));
                glNormalPointer(GL_FLOAT, sizeof(AL_VertNor),
                    BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex))));*/
                glVertexPointer(3, GL_FLOAT, 0,
                    0/*BUFFER_OFFSET(meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)))*/);
        //        lastMesh = Id;
        //}
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,meshes[Id].Buffer);
        glEnableClientState(GL_VERTEX_ARRAY);
        glDrawRangeElements(GL_TRIANGLES, 0,meshes[Id].numTris*3-1,meshes[Id].numTris*3,
                            GL_UNSIGNED_INT,NULL);
        glDisableClientState(GL_VERTEX_ARRAY);
    
    glGenBuffers(1, &meshes[numMeshes].Buffer);
    
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].Buffer);
        glBufferData(GL_ARRAY_BUFFER,
                     numVert*(/*sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor)+*/sizeof(AL_VertCrd)),
                     0, GL_STREAM_DRAW);
    
        /*glBufferSubData(GL_ARRAY_BUFFER,
                        0,
                        numVert*sizeof(AL_VertCol),
                        mesh->getColorPointer());
        glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*sizeof(AL_VertCol),
                        numVert*sizeof(AL_VertTex),
                        mesh->getUVCoordPointer());
        glBufferSubData(GL_ARRAY_BUFFER,
                        numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)),
                        numVert*sizeof(AL_VertNor),
                        mesh->getNormalPointer());*/
        glBufferSubData(GL_ARRAY_BUFFER,
                        /*numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)+sizeof(AL_VertNor))*/0,
                        numVert*sizeof(AL_VertCrd),
                        mesh->getCoordPointer());
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshes[numMeshes].Buffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, numTris*sizeof(AL_Triangle),
                     mesh->getTrianglePointer(), GL_STREAM_DRAW);
    

    Verursacht Segfault bei glDrawRangeElements.

    VertexArrays funktionieren bestens aber ziemlich kriechend...

    [Edit] Mit unterschiedlichen Buffern für indices und vertices funktioniert das. muss man sich da, wenn man einen Buffer verwendet, extra speicher reservieren? Ich mach das mal...



  • OK, alles kaputt, Segfaultet nur so 🙂

    hab jetzt ein Backup genommen - der Code sieht so aus:

    Rendern

    void ALSAGE_OGL::drawMesh(int Id,AL_Vector pos,AL_Vector scale, int TexId)
    {
        glScalef(scale.x,scale.y,scale.z);
        glDisable(GL_LIGHTING);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnableClientState(GL_VERTEX_ARRAY);
        if(TexId != -1) glBindTexture(GL_TEXTURE_2D, textures[TexId].Name);
    
        if(lastMesh != Id)
        {
    
            glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[2]);
            glColorPointer(4, GL_UNSIGNED_BYTE, 0,0);
    
            glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[3]);
            glTexCoordPointer(2, GL_FLOAT, 0,0);
    
            glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[4]);
            glNormalPointer(GL_FLOAT, 0,0);
    
            glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[0]);
            glVertexPointer(3, GL_FLOAT, 0,0);
    
            lastMesh = Id;
        }
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,meshes[Id].VBO[1]);
        glDrawRangeElements(GL_TRIANGLES, 0,meshes[Id].numTris*3-1,meshes[Id].numTris*3,
                            GL_UNSIGNED_INT,NULL);
        glBindTexture(GL_TEXTURE_2D, 0);
        glBindBuffer(GL_ARRAY_BUFFER,0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);
    }
    

    laden:

    int ALSAGE_OGL::loadMesh(AL_Char* filename)
    {
        AL_Mesh* mesh = new AL_Mesh;
        AL_byte nBufs = 5;
        mesh->loadFromFile(filename);
        meshes[numMeshes].numVert = mesh->vertCount();
        meshes[numMeshes].numTris = mesh->TrisCount();
    
        glGenBuffers(nBufs, meshes[numMeshes].VBO);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshes[numMeshes].VBO[1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshes[numMeshes].numTris*sizeof(AL_Triangle),
                     mesh->getTrianglePointer(), GL_STREAM_DRAW);
    
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].VBO[2]);
        glBufferData(GL_ARRAY_BUFFER, meshes[numMeshes].numVert*sizeof(AL_VertCol),
                     mesh->getColorPointer(), GL_STREAM_DRAW);
    
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].VBO[3]);
        glBufferData(GL_ARRAY_BUFFER, meshes[numMeshes].numVert*sizeof(AL_VertTex),
                     mesh->getUVCoordPointer(), GL_STREAM_DRAW);
    
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].VBO[4]);
        glBufferData(GL_ARRAY_BUFFER, meshes[numMeshes].numVert*sizeof(AL_VertNor),
                     mesh->getNormalPointer(), GL_STREAM_DRAW);
    
        glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].VBO[0]);
        glBufferData(GL_ARRAY_BUFFER, meshes[numMeshes].numVert*sizeof(AL_VertCrd),
                     mesh->getCoordPointer(), GL_STREAM_DRAW);
        numMeshes++;
        delete mesh;
    
        return numMeshes-1;
    }
    

    Und funktioniert bestens. Ich mache jetzt folgendes (Zeile 21-22 beim Laden):

    glBufferData(GL_ARRAY_BUFFER, 
                     meshes[numMeshes].numVert*sizeof(AL_VertTex),
                     0, 
                     GL_STREAM_DRAW);
        glBufferSubData(GL_ARRAY_BUFFER,
                        0,
                        meshes[numMeshes].numVert*sizeof(AL_VertTex),
                        mesh->getUVCoordPointer());
    

    Es funktioniert. Dann probiert ich das hier (Zeile 17-22 beim laden):

    glBufferData(GL_ARRAY_BUFFER, 
                     meshes[numMeshes].numVert*(sizeof(AL_VertCol)+sizeof(AL_VertTex)),
                     0, 
                     GL_STREAM_DRAW);
        glBufferSubData(GL_ARRAY_BUFFER,
                        0,
                        meshes[numMeshes].numVert*sizeof(AL_VertCol),
                        mesh->getColorPointer());
    
        /*glBindBuffer(GL_ARRAY_BUFFER, meshes[numMeshes].VBO[3]);
        glBufferData(GL_ARRAY_BUFFER, 
                     meshes[numMeshes].numVert*sizeof(AL_VertTex),
                     0, 
                     GL_STREAM_DRAW);*/
        glBufferSubData(GL_ARRAY_BUFFER,
                        meshes[numMeshes].numVert*sizeof(AL_VertCol),
                        meshes[numMeshes].numVert*sizeof(AL_VertTex),
                        mesh->getUVCoordPointer());
    

    und dann beim Rendern (Zeile 13-17):

    glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[2]);
            glColorPointer(4, GL_UNSIGNED_BYTE, 0,0);
    
            //glBindBuffer(GL_ARRAY_BUFFER,meshes[Id].VBO[3]);
            glTexCoordPointer(2, GL_FLOAT, 0,
                BUFFER_OFFSET(meshes[numMeshes].numVert*sizeof(AL_VertCol)));
    

    Das Ergebnis:
    http://b.imagehost.org/view/0899/bug.png

    Die TexturCoordinaten sind absolut falsch. Was hab ich falsch gemacht?

    [EDIT] Möchte noch hinzufügen, dass ich nach alldem anscheinend meine Grafikkarte leicht zerschossen habe denn ich hab soeben ein Game angemacht und plötlich sprang mein Pc in einen 800x600x16farben modus. Also der Treiber ist eindeutig abgestürzt. Ist OpenGL irgendwie schädlich? 😃

    [Edit2] lag daran dass ich beim Rendern numMeshes als index genommen hab, hätte Id nehmen sollen... Immer diese Konzentrationsfehler... Sind mir in der schule doch schon zu genüge ein problem 😃


Anmelden zum Antworten