2012-12-14 42 views
1

我試圖顯示在以有效的方式使用OpenGL和C++一個XY規則的網格限定的數學表面F(X,Y):如何優化在OpenGL中顯示大量四邊形?

struct XYRegularSurface { 
    double x0, y0; 
    double dx, dy; 
    int nx, ny; 
    XYRegularSurface(int nx_, int ny_) : nx(nx_), ny(ny_) { 
     z = new float[nx*ny]; 
    } 
    ~XYRegularSurface() { 
     delete [] z; 
    } 
    float& operator()(int ix, int iy) { 
     return z[ix*ny + iy]; 
    } 

    float x(int ix, int iy) { 
     return x0 + ix*dx; 
    } 
    float y(int ix, int iy) { 
     return y0 + iy*dy; 
    } 
    float zmin(); 
    float zmax(); 
    float* z; 
}; 

這裏是到目前爲止我的OpenGL油漆代碼:

void color(QColor & col) { 
    float r = col.red()/255.0f; 
    float g = col.green()/255.0f; 
    float b = col.blue()/255.0f; 
    glColor3f(r,g,b); 
} 

void paintGL_XYRegularSurface(XYRegularSurface &surface, float zmin, float zmax) { 
    float x, y, z; 

    QColor col; 
    glBegin(GL_QUADS); 
    for(int ix = 0; ix < surface.nx - 1; ix++) { 
     for(int iy = 0; iy < surface.ny - 1; iy++) { 
      x = surface.x(ix,iy); 
      y = surface.y(ix,iy); 
      z = surface(ix,iy); 
      col = rainbow(zmin, zmax, z);color(col); 
      glVertex3f(x, y, z); 

      x = surface.x(ix + 1, iy); 
      y = surface.y(ix + 1, iy); 
      z = surface(ix + 1,iy); 
      col = rainbow(zmin, zmax, z);color(col); 
      glVertex3f(x, y, z); 

      x = surface.x(ix + 1, iy + 1); 
      y = surface.y(ix + 1, iy + 1); 
      z = surface(ix + 1,iy + 1); 
      col = rainbow(zmin, zmax, z);color(col); 
      glVertex3f(x, y, z); 

      x = surface.x(ix, iy + 1); 
      y = surface.y(ix, iy + 1); 
      z = surface(ix,iy + 1); 
      col = rainbow(zmin, zmax, z);color(col); 
      glVertex3f(x, y, z); 

     } 
    } 
    glEnd(); 
} 

問題是,這很慢,nx = ny = 1000,fps〜= 1。 如何優化這個更快?

編輯:(!謝謝)以下你的建議,關於VBO 我說:

float* XYRegularSurface::xyz() { 
    float* data = new float[3*nx*ny]; 
    long i = 0; 
    for(int ix = 0; ix < nx; ix++) { 
     for(int iy = 0; iy < ny; iy++) { 
      data[i++] = x(ix,iy); 
      data[i++] = y(ix,iy); 
      data[i] = z[i]; i++; 
     } 
    } 
    return data; 
} 

我想我明白,我怎麼可以創建一個VBO,它初始化爲XYZ(),它在發送給GPU一個去,但如何繪圖時使用VBO。我知道這可以在頂點着色器或glDrawElements中完成?我認爲後者更容易?如果是這樣的話:glDrawElements文檔中沒有看到任何QUAD模式!

EDIT2: 這樣我就可以循環通過所有的NX * NY四邊形,並繪製每個人:

GL_UNSIGNED_INT indices[4]; 
// ... set indices 
glDrawElements(GL_QUADS, 1, GL_UNSIGNED_INT, indices); 

+1

請勿使用glBegin和glEnd,而應使用Vertex Buffers。網絡上有很多信息,只是谷歌的信息。頂點緩衝區允許你存儲,而不必重新上傳它的每一幀在GPU內存的頂點數據。這應該會給你帶來巨大的性能提升。 – s3rius

+0

現代的OpenGL沒有'GL_QUADS'或'GL_QUAD_STRIP'。它們使用'GL_TRIANGLES'進行模擬。 – dupersuper

+0

謝謝。將每個四邊形替換爲2個三角形應該很容易,但是我猜想重寫爲三角形帶會導致更高的fps,因爲我只能調用glDrawElements nx次(或者只調用一次?)而不是nx * ny次? – Andy

回答

1

那麼,你已經提出了一個相當開放的問題。我建議使用現代(3.0+)OpenGL的一切。幾乎所有新的OpenGL特性都是爲了提供更快的方式來完成任務。像其他人一樣,使用數組(頂點)緩衝區對象和頂點數組對象。也使用元素數組(索引)緩衝區對象。大多數的GPU有一個「變換後的高速緩存」,它存儲了過去幾年變換的頂點,但是當你調用glDraw *元素系列函數這隻能使用。我還建議你在VBO中存儲一個平面網格,其中每個頂點的y = 0。在頂點着色器中從高度貼圖紋理中採樣y。如果你這樣做,只要表面發生變化,你只需要更新高度貼圖紋理,這比更新VBO更容易。對高度圖使用浮點或整數紋理格式之一,因此不限於使其值介於0和1之間。

2

1 /。使用display lists來緩存GL命令 - 避免重新計算頂點和昂貴的每頂點調用開銷。如果數據更新,您需要查看客戶端頂點數組(不要與VAO混淆)。現在忽略此選項...

2 /。使用vertex buffer objects。自GL 1.5起可用。

因爲你需要爲core profile維也納組織反正(即現代GL),你至少可以得到這個第一次交手。

+0

謝謝!根據你的建議,我首先關注VBOs。 – Andy

1

如果是這樣的話:在文檔中看不到任何QUAD模式glDrawElements!?

如果你想四邊形確保你正在尋找GL 2.1-era docs,而不是new stuff

+0

謝謝!這有幫助。 – Andy