2012-11-05 800 views
0

我一直在學習幾個星期的VBOs,並且我被告知here,VBOs可以渲染「大約一百萬個頂點到幾百fps」。但是,我目前的VBO測試程序只能獲得大約50 FPS的點數,並且要渲染一百萬個頂點。有沒有方法可以優化VBO效率?或者,更可能的是,我做錯了什麼?我的測試程序在這裏:VBO渲染慢

編輯:基於反饋的改進代碼。

#include <windows.h> 
#include <SFML/Graphics.hpp> 
#include <iostream> 

#include <glew.h> 
#include <gl/gl.h> 
#include <gl/glu.h> 

using namespace std; 

float cube_vertices[] = {-1, -1, 1, 
         1, -1, 1, 
         1, 1, 1, 
         -1, 1, 1, 

         -1, -1, -1, 
         -1, 1, -1, 
         1, 1, -1, 
         1, -1, -1, 

         -1, 1, -1, 
         -1, 1, 1, 
         1, 1, 1, 
         1, 1, -1, 

         -1, -1, -1, 
         1, -1, -1, 
         1, -1, 1, 
         -1, -1, 1, 

         1, -1, -1, 
         1, 1, -1, 
         1, 1, 1, 
         1, -1, 1, 

         -1, -1, -1, 
         -1, -1, 1, 
         -1, 1, 1, 
         -1, 1, -1}; 

float cube_normals[] = {0, 0, 1, 
         0, 0, 1, 
         0, 0, 1, 
         0, 0, 1, 

         0, 0, -1, 
         0, 0, -1, 
         0, 0, -1, 
         0, 0, -1, 

         0, 1, 0, 
         0, 1, 0, 
         0, 1, 0, 
         0, 1, 0, 

         0, -1, 0, 
         0, -1, 0, 
         0, -1, 0, 
         0, -1, 0, 

         1, 0, 0, 
         1, 0, 0, 
         1, 0, 0, 
         1, 0, 0, 

         -1, 0, 0, 
         -1, 0, 0, 
         -1, 0, 0, 
         -1, 0, 0}; 
class Scene { 
public: 
    void setup_projection(int w, int h) { 
     glViewport(0, 0, w, h); 
     glMatrixMode(GL_PROJECTION); 
     glLoadIdentity(); 
     gluPerspective(50, (GLdouble)w/(GLdouble)h, 1, 5000.0); 
     glMatrixMode(GL_MODELVIEW); 
    } 
}; 
int main() { 
    ///Number of models to render 
    int NumberOfCubes = 0; 
    cout << "Enter number of cubes to render: "; 
    cin >> NumberOfCubes; 
    system("cls"); 

    ///Create vectors for mesh data 
    //6 faces * 4 verts * x, y, z * number of cubes 
    std::vector<float> vertices; vertices.resize(6*4*3*NumberOfCubes); 
    std::vector<float> normals; normals.resize(6*4*3*NumberOfCubes); 
    for(int i = 0; i < NumberOfCubes; i++) 
    { 
     for(int j = 0; j < 6*4*3; j++) 
     { 
      vertices[(i*6*4*3) + j] = cube_vertices[j] + i; 
      normals[(i*6*4*3) + j] = cube_normals[j]; 
     } 
    } 

    ///Store size of the vectors 
    int SizeOfVertices = vertices.size() * sizeof(float); 
    int SizeOfNormals = normals.size() * sizeof(float); 

    ///Window setup, lighting setup 
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Test"); 
    Scene scene; 
    scene.setup_projection(window.getSize().x,window.getSize().y); 
    glewInit(); 
    glEnable(GL_DEPTH_TEST); 
    glEnable(GL_LIGHTING); 
    glShadeModel(GL_SMOOTH); 
    glEnable(GL_LIGHT0); 
    float XL = .5, YL = .1, ZL = 1; 
    GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f }; 
    GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f }; 
    GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f }; 
    GLfloat lightpos[] = {XL, YL, ZL, 0.}; 
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); 
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); 
    glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); 
    glLightfv(GL_LIGHT0, GL_POSITION, lightpos); 

    ///Generate the VBO 
    GLuint VBOID; 
    glGenBuffers(1, &VBOID); 
    glBindBuffer(GL_ARRAY_BUFFER, VBOID); 
    glBufferData(GL_ARRAY_BUFFER, SizeOfVertices + SizeOfNormals, 0, GL_STATIC_DRAW); 
    glBufferSubData(GL_ARRAY_BUFFER, 0, SizeOfVertices, &vertices[0]); 
    glBufferSubData(GL_ARRAY_BUFFER, SizeOfVertices, SizeOfNormals + SizeOfVertices, &normals[0]); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    ///FPS Stuff 
    sf::Clock FPS; 
    sf::Clock ShowFPS; 
    float fps; 

    ///Start loop 
    cout << "Rendering " << NumberOfCubes * 8 << " vertices." << endl; 
    cout << "Using graphics card: " << glGetString(GL_RENDERER) << endl; 

    while(window.isOpen()) { 
     sf::Event event; 
     while(window.pollEvent(event)) { 
      if(event.type == sf::Event::Closed) 
       window.close(); 
     } 
     fps = FPS.getElapsedTime().asSeconds(); 
     fps = 1/fps; 
     FPS.restart(); 
     if(ShowFPS.getElapsedTime().asSeconds() > 1) 
     { 
      cout << "FPS: " << fps << "\t FrameTime: " << 1000/fps << endl; 
      ShowFPS.restart(); 
     } 

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
     glMatrixMode(GL_PROJECTION); 
     glLoadIdentity(); 
     scene.setup_projection(window.getSize().x,window.getSize().y); 
     glMatrixMode(GL_MODELVIEW); 
     glLoadIdentity(); 
     gluLookAt(-25, -25, 150, 50, 50, 50, 0, 1, 0); 

     glBindBuffer(GL_ARRAY_BUFFER, VBOID); 
     glEnableClientState(GL_NORMAL_ARRAY); 
     glEnableClientState(GL_VERTEX_ARRAY); 
     glColor3f(1, 0, 0); 

     glNormalPointer(GL_FLOAT, 0, 0); 
     glVertexPointer(3, GL_FLOAT, 0, 0); 

     glDrawArrays(GL_QUADS, 0, 6*4*NumberOfCubes); 

     glDisableClientState(GL_VERTEX_ARRAY); 
     glDisableClientState(GL_NORMAL_ARRAY); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 

     window.display(); 
    } 
    return 1; 
} 
+0

你從來沒有說過你的硬件是什麼。 –

+0

我正在使用64位Windows 7家庭高級版與GeForce GT 640M LE Nvidia顯卡,12 GB內存和四核i7 – LucasS

+1

首先,構建一個[簡短的,獨立的,正確的(可編譯的),例子](http:///sscce.org/),以便我們不必梳理成百上千條的廢話。第二,當你不通過*顏色*時,你爲什麼使用色彩材料?你是否從某處複製並粘貼這些東西,以創建某種弗蘭肯代碼?如果您要剖析代碼,請確保代碼首先有意義。 –

回答

0

做進一步的研究,我發現了VBO Indexing,並能使用一百萬個頂點,以獲得幾百FPS。

0

您使用雙緩衝嗎?是的,那麼你可能已經在你的驅動程序中啓用了sync to vblank。這意味着,每個使用雙緩衝的OpengGL應用程序最多可以在顯示器的刷新率下顯示(通常在50 - 60Hz左右)。

您可以嘗試使用相同的代碼(顯着)較小的模型,以查看您的FPS是否超過此值。

+0

我目前不使用雙緩衝。我可以用更小型號獲得更高的FPS率。 – LucasS

1

上驗證碼的幾句話:

void Scene::resize(int w, int h) { 
    glViewport(0, 0, w, h); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(50, (GLdouble)w/(GLdouble)h, 1, 5000.0); 
    glMatrixMode(GL_MODELVIEW); 
} 

請你明白,設置視口和投影不是某種「調整大小」操作。他們是繪畫過程的一部分,因此應該像那樣對待。好處是,你可以在每次繪圖迭代中調用這個函數。但我不會稱之爲resize。一個更好的名字是setup_projection或類似的,要說清楚,這個函數做了什麼,而不是,它做了什麼反應。始終通過它的功能調用函數!

cout << endl << endl << "Close program when finished." << endl; 

bool ProgramRunning(true); 
while(ProgramRunning == true) {} 

可能不工作,你可能會想到。你關閉的是控制檯窗口/終端;這會讓你的程序失去它的standrd輸入和進程的領導,從而終止它。 while循環之後的任何代碼都不會被執行。你可以安裝信號處理程序,它可以將迄今爲止無效的程序運行標誌設置爲假。

但是對付這種規範的方法就是等待用戶暫停,直到用戶點擊回車鍵:

cout << "Program execution finished, hit the ENTER key to terminate" << endl; 
cin.get(); 

現在爲什麼你只得到50 FPS:最有可能的原因是,您啓用了V-Sync,並且您的顯示器的刷新頻率爲50Hz。 50Hz是不尋常的,但不是沒有聽說過。也可能是,您的顯示器運行在60Hz,但由於某種原因,您沒有爲每個回掃期限刷新最後期限,從而使您的代碼平均每6幀錯過一次。

另一個原因可能是,您沒有在GeForce上運行,也可能在筆記本電腦的芯片組GPU上運行。如果您有一個混合圖形系統,請確保您在執行程序之前將所有驅動程序正確安裝,並切換到GeForce GPU。

打印glGetString(GL_RENDERER);的輸出以確認。打開窗戶,創造OpenGL上下文後添加

cout << glGetString(GL_RENDERER) << endl; 
+0

我知道我沒有啓用V-Sync,因爲我在顯示設置中手動禁用了V-Sync。 雖然檢查渲染器是一個好主意,現在已包含在我的項目中。不幸的是,這不是問題,並且當我描述我的硬件時,它正好是我上面所說的打印出來的。 – LucasS