Много квадов, не много фпс, несмотря на VBO - PullRequest
1 голос
/ 13 июня 2011

У меня есть время, и я прочитал о VBO, и вот что я получил:

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

Хорошо, это намного лучше, чем раньше. Он скомпилирован в Release. Я использую VBO (возможно, если все в порядке) и glDrawArrays для рисования.

Вот код для рисования. Пожалуйста, дайте мне совет, как его оптимизировать. Я хотел с ландшафтом ... э-э, несколько тысяч FPS, это правда?

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;
}

Так что я могу с этим сделать? (Код выше является основной функцией розыгрыша)

редактировать

Я переместил это:

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"); 
}

к моей основной функции. Вероятно, нет улучшения.

edit2

Теперь я также вижу, что это ест память. Каждые несколько секунд использование памяти программы растет все больше и больше ... Что не так? Что я не удаляю?

Edit3

Хорошо, спасибо оооочень большое. Я переместил некоторый код за пределы функции рисования и ... намного больше кадров в секунду! Большое спасибо!

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

Это карта размером 640x640 блоков (так в 40 раз больше) с 650'000 квадов (примерно в 70 раз больше) и ~ 170 кадров в секунду. Большой ! И никаких утечек памяти. Еще раз спасибо!

Ответы [ 3 ]

8 голосов
/ 13 июня 2011

Вы перезагружаете все свои буферы и снова освобождаете их в каждом отдельном кадре?Прекратите это делать, и ваша частота кадров увеличится.

Обратите внимание, что в вашем текущем коде в конечном итоге закончатся идентификаторы VBO, поскольку вы никогда не удаляете созданные вами VBO.* определенно тоже не нужно делать каждый кадр.

1 голос
/ 13 июня 2011

Несколько вещей выделяются:

В вашей функции рисования вы выделяете память для ваших геометрических данных

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

Распределение памяти - чрезвычайно дорогая операция, это одна из техвещи, которые должны быть сделаны только один раз.OpenGL не предназначен для «инициализации» - , но структуры данных, которые вы собираетесь ему передать, это!

Здесь вы копируете вновь выделенные буферы в OpenGL, снова иснова с каждым кадром.Это прямо противоположно тому, что нужно сделать.

// 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 );

Вся идея VBO состоит в том, чтобы загрузить данные только один раз, скопировать их в OpenGL и затем никогда не перераспределять.Обратите внимание, что это не инициализация OpenGL, это инициализация данных, что-то совершенно разумное.Я вижу, что вы назвали свои переменные m_pVertices и m_pTexCoords, что указывает на то, что это переменные члена класса.Тогда решение простое: переместите весь код инициализации в некоторую функцию загрузчика.Также вместо голых массивов C ++ я настоятельно рекомендую использовать std::vector.

Так что давайте исправим это:

// 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();
    }
}

Примечание: комментарии типа // Generate And Bind The Vertex Buffer или // Set The Vertex Pointer To The Vertex Buffer не являютсяочень полезноЭти комментарии просто излишне говорят, что в любом случае можно прочитать из кода.К коду следует добавить комментарии, внутренняя работа которых не сразу понятна, или если вам нужно было сделать какой-то хак, чтобы что-то исправить, и этот хак озадачил бы кого-то другого или вас самих через несколько месяцев.

1 голос
/ 13 июня 2011

Ваша функция DrawVBO должна содержать только:

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();

Вам необходимо переместить остальные в отдельную функцию, вызываемую только один раз при запуске (или при изменении местности).

...