2011-06-13 58 views
1

我有一段時間,我讀過有關VBO,這就是我的了:許多四邊形,沒有充足的FPS儘管VBO

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

好吧,這是比以前好多了。它在Release上編譯。我使用VBO(可能,如果everthing的確定)和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

好的,非常感謝sooooo。我已經移動了一些代碼以外的繪製功能和...更多的FPS! 非常感謝!

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

這是640x640塊(40,從而更大的次)映射與650'000四邊形(約70倍以上),並仍然〜170幀。太好了!沒有內存泄漏。再次感謝 !

+2

你想要「幾千FPS」?真? – 2011-06-13 13:18:02

+0

您的渲染循環是否定時?是vsynch啓用? – 2011-06-13 13:18:27

+0

嗯也許3000-6000 fps我不知道是否只有約9000四邊形。現在的電腦真的很多嗎?事實上,後面我想畫出比這更大的地形,但如果我知道我將有50fps,我就無法繼續前進。 – dj8000 2011-06-13 13:20:33

回答

1

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

您需要休息移動到在啓動時(或當地形變化)只調用一次單獨的函數。

+0

是的,工作。非常感謝soo。這很簡單:) – dj8000 2011-06-13 14:54:03

8

您正在重新加載所有緩衝區並在每一幀中再次釋放它們?停止這樣做,你的幀率會上升。

請注意,您目前的代碼最終將耗盡VBO標識符,因爲您永遠不會刪除您創建的VBO。

鏈接擴展功能肯定也不需要每幀都做。

+0

我已經將一些代碼移到了我的主函數中,你是指這個片段? – dj8000 2011-06-13 13:26:06

+1

這不是他主要的意思。你正在創建維也納各組織,並填補每一個框架,這是不必要的,並可能導致性能下降。 – ronag 2011-06-13 13:31:18

+0

每一秒鐘它的記憶越來越多,出了什麼問題?在完成循環之前我應該​​刪除什麼? – dj8000 2011-06-13 13:32:42

1

有幾件事情中脫穎而出:

在你的繪圖功能,你爲你的幾何數據分配內存

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

駐維也納各組織的整體思路是,加載數據只有一次,把它複製到OpenGL的,然後再也沒有重新分配它。請注意,這不是OpenGL初始化,它是數據初始化,完全合理。我看到你已經命名了你的變量m_pVerticesm_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註釋不是非常有用的。這些評論只是多餘的說明,無論如何,我們可以從代碼中讀到什麼。 評論應該添加到代碼中,哪些內部工作無法立即理解,或者如果您必須做某種破解來修復某些內容,並且這種破解會在幾個月的時間內困擾其他人或您自己。