Frage

Ich habe etwas Zeit und habe über VBO gelesen und das habe ich bekommen:

http://img64.imageshack.us/img64/5733/fps8.jpg

Ok, es ist viel besser als zuvor. Es ist bei Release kompiliert. Ich benutze VBO (wahrscheinlich, wenn alles in Ordnung ist) und glDrawArrays zum Zeichnen.

Hier ist Zeichnungscode. Bitte geben Sie mir Ratschläge zur Optimierung. Ich wollte mit Gelände ... ähm ein paar tausend FPS, ist es echt?

void DrawVBO (void)
{
    int i;

    CVert*      m_pVertices; 
    CTexCoord*  m_pTexCoords;

    unsigned int    m_nTextureId;

    m_pVertices = NULL;
    m_pTexCoords = NULL;
    m_nVertexCount = 0;
    m_nVBOVertices = m_nVBOTexCoords = m_nTextureId = 0;


    if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
    {
        // Pobierz wskaźniki na funkcje OpenGL 
        glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
        glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
        glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
        glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) 
        wglGetProcAddress("glDeleteBuffersARB"); 
    }

    todrawquads=0;
    nIndex=0;


// my function counting how many quads I will draw


    for (i=0;i<MAX_CHUNKS_LOADED;i++)
    {
        if (chunks_loaded[i].created==1)
        {
            countquads(i);
        }
    }

    m_nVertexCount=4*todrawquads;

    m_pVertices = new CVec[m_nVertexCount];
    m_pTexCoords = new CTexCoord[m_nVertexCount];

// another my function adding every quad which i'm going to draw (its verticles) to array

    for (i=0;i<MAX_CHUNKS_LOADED;i++)
    {
        if (chunks_loaded[i].created==1)
        {
            addchunktodraw(i,m_pVertices,m_pTexCoords);
        }
    }


    glClearColor (1,1,1, 0.0);
    glColor3f(1,1,1);

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
    glLoadIdentity ();                                          // Reset The Modelview Matrix

    fps++;

    // Camera settings.

    //gluLookAt (zom, zom, zom, 0.0, 0.0, 0.0, 0, 0, 1);

    gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
    glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
    glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
    glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

    //m_nTextureId = t_terrain;

    // Generate And Bind The Vertex Buffer
    glGenBuffersARB( 1, &m_nVBOVertices );                          // Get A Valid Name
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );         // Bind The Buffer
    // Load The Data
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB );

    // Generate And Bind The Texture Coordinate Buffer
    glGenBuffersARB( 1, &m_nVBOTexCoords );                         // Get A Valid Name
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );        // Bind The Buffer
    // Load The Data
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB );

    // Enable Pointers
    glEnableClientState( GL_VERTEX_ARRAY );                     // Enable Vertex Arrays
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );              // Enable Texture Coord Arrays

    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
    glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );       // Set The Vertex Pointer To The Vertex Buffer
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
    glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );     // Set The TexCoord Pointer To The TexCoord Buffe

    glDrawArrays( GL_QUADS, 0, m_nVertexCount); // Draw All Of The Triangles At Once

    glDisableClientState( GL_VERTEX_ARRAY );                    // Disable Vertex Arrays
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );             // Disable Texture Coord Arrays

    liniergb();

    glutSwapBuffers();

    delete [] m_pVertices; m_pVertices = NULL;
    delete [] m_pTexCoords; m_pTexCoords = NULL;
}

Also, was kann ich damit machen? (Der obige Code ist die Hauptzeichnungsfunktion)

bearbeiten

Ich habe Folgendes verschoben:

if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
{
    // Pobierz wskaźniki na funkcje OpenGL 
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
    glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
    glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) 
    wglGetProcAddress("glDeleteBuffersARB"); 
}

zu meiner Hauptfunktion. Wahrscheinlich keine Verbesserung.

edit2

Jetzt kann ich auch sehen, dass es Erinnerung frisst. Alle paar Sekunden steigt die Programmspeicherauslastung immer mehr an ... Was ist los? Was lösche ich nicht?

edit3

Ok, vielen Dank. Ich habe Code außerhalb der Zeichenfunktion verschoben und ... viel mehr fps! Vielen Dank!

http://img197.imageshack.us/img197/5193/fpsfinal.jpg

Es ist eine Karte mit 640 x 640 Blöcken (also 40-mal größer) mit 650'000 Quads (ungefähr 70-mal mehr) und immer noch ~ 170 fps. Großartig ! Und keine Speicherlecks. Nochmals vielen Dank!

War es hilfreich?

Lösung

Ihre DrawVBO-Funktion sollte nur Folgendes enthalten:

glClearColor (1,1,1, 0.0);
glColor3f(1,1,1);

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
glLoadIdentity ();                                          // Reset The Modelview Matrix

fps++;

// Camera settings.

//gluLookAt (zom, zom, zom, 0.0, 0.0, 0.0, 0, 0, 1);

gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

// Enable Pointers
glEnableClientState( GL_VERTEX_ARRAY );                     // Enable Vertex Arrays
glEnableClientState( GL_TEXTURE_COORD_ARRAY );              // Enable Texture Coord Arrays

glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );       // Set The Vertex Pointer To The Vertex Buffer
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );     // Set The TexCoord Pointer To The TexCoord Buffe

glDrawArrays( GL_QUADS, 0, m_nVertexCount); // Draw All Of The Triangles At Once

glDisableClientState( GL_VERTEX_ARRAY );                    // Disable Vertex Arrays
glDisableClientState( GL_TEXTURE_COORD_ARRAY );             // Disable Texture Coord Arrays

liniergb();

glutSwapBuffers();

Sie müssen den Rest in eine separate Funktion verschieben, die beim Start (oder wenn sich das Gelände ändert) nur einmal aufgerufen wird.

Andere Tipps

Sie laden alle Ihre Puffer neu und geben sie in jedem einzelnen Frame wieder frei?Wenn Sie damit aufhören, steigt Ihre Bildrate.

Beachten Sie, dass Ihrem aktuellen Code möglicherweise die VBO-Kennungen ausgehen, da Sie die von Ihnen erstellten VBOs niemals löschen.

Das Verknüpfen von Erweiterungsfunktionen definitiv muss auch nicht in jedem Frame erfolgen.

Einige Dinge fallen auf:

In Ihrer Zeichenfunktion weisen Sie Speicher für Ihre Geometriedaten zu

    m_pVertices = new CVec[m_nVertexCount];
    m_pTexCoords = new CTexCoord[m_nVertexCount];

Die Speicherzuweisung ist eine extrem teure Operation. Dies ist eines der Dinge, die nur einmal ausgeführt werden sollten. OpenGL soll nicht "initialisiert" werden - aber die Datenstrukturen, die Sie an OpenGL übergeben werden, sind!

Hier kopieren Sie die neu zugewiesenen Puffer immer wieder mit jedem Frame nach OpenGL. Dies ist genau das Gegenteil von dem, was zu tun ist.

// Generate And Bind The Vertex Buffer
glGenBuffersARB( 1, &m_nVBOVertices );                          // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );         // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB );

// Generate And Bind The Texture Coordinate Buffer
glGenBuffersARB( 1, &m_nVBOTexCoords );                         // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );        // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB );

Die ganze Idee von VBOs ist, die Daten nur einmal zu laden, sie in OpenGL zu kopieren und sie dann nie wieder neu zuzuweisen. Beachten Sie, dass dies keine OpenGL-Initialisierung ist, sondern eine Dateninitialisierung, was völlig vernünftig ist. Ich sehe, dass Sie Ihre Variablen m_pVertices und m_pTexCoords benannt haben, um anzuzeigen, dass dies Klassenmitgliedsvariablen sind. Dann ist die Lösung einfach: Verschieben Sie den gesamten Initialisierungscode in eine Ladefunktion. Anstelle von nackten C ++ - Arrays empfehle ich dringend die Verwendung von std::vector.

Beheben wir also Folgendes:

// Load Extensions only once. Well, once per context actually, however
// why don't you just use an extension wrapper and forget about those
// gritty details? Google GLEW or GLee
void init_extensions()
{
    if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
    {
    // Pobierz wska\u017aniki na funkcje OpenGL 
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
    glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
    glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB"); 
    }
}

class Block0r
{
protected:
    GLuint m_nTextureId;
    GLuint m_nVBOVertices;
    GLuint m_nVBOTexCoords;
    GLuint m_nVertexCount;

    // Call this one time to load the data    
    void LoadVBO()
    {
        std::vector<CVert> vertices;
        std::vector<CTexCoord> texCoords;
        // my function counting how many quads I will draw

        todrawquads = 0;

        for(int i=0; i < MAX_CHUNKS_LOADED; i++) {
            if( chunks_loaded[i].created == 1 ) {
                countquads(i);
            }
        }

        m_nVertexCount = 4*todrawquads;

        vertices.resize(vertexcount);
        texcoords.resize(vertexcount);


        for (i=0;i<MAX_CHUNKS_LOADED;i++) {
            if (chunks_loaded[i].created==1) {
                addchunktodraw(i, &vertices[0], &texcoords[0]);
            }
        }

        glGenBuffersARB( 1, &m_nVBOVertices );
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
            glBufferDataARB( GL_ARRAY_BUFFER_ARB, vertices.size()*sizeof(CVert), &vertices[0], GL_STATIC_DRAW_ARB );

        glGenBuffersARB( 1, &m_nVBOTexCoords );
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
        glBufferDataARB( GL_ARRAY_BUFFER_ARB, texCoords.size()*sizeof(CTexCoord), &texCoords[0], GL_STATIC_DRAW_ARB );
    }

    void DrawVBO()
    {
        glClearColor (1,1,1, 0.0);
        glColor3f(1,1,1);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_PROJECTION);
            setup_projection(); // this should really be done in the drawing handler

        glMatrixMode(GL_MODELVIEW); // don't asssume a certain matrix being active!
        glLoadIdentity();

        fps++;

        gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
        glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
        glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
        glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_TEXTURE_COORD_ARRAY );

        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
        glVertexPointer( 3, GL_FLOAT, 0, (GLvoid *) 0 );

        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
        glTexCoordPointer( 2, GL_FLOAT, 0, (GLvoid *) 0 );

        glDrawArrays( GL_QUADS, 0, m_nVertexCount);
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_TEXTURE_COORD_ARRAY );
        liniergb();

        glutSwapBuffers();
    }
}

Nebenbei bemerkt: Kommentare wie // Generate And Bind The Vertex Buffer oder // Set The Vertex Pointer To The Vertex Buffer sind nicht sehr nützlich. Diese Kommentare sagen nur redundant aus, was man sowieso aus dem Code lesen kann. Dem Code sollten Kommentare hinzugefügt werden, deren Innenleben nicht sofort verständlich ist, oder wenn Sie eine Art Hack ausführen müssten, um etwas zu reparieren, und dieser Hack würde in ein paar Monaten jemand anderen oder sich selbst rätseln.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top