2014-10-04 64 views
0

我有以下全局變量:OpenGL的 - 從顯示列表轉換爲使用VBO

vector<vector<unsigned int> > faces; 
vector<float> vertexCoords; 
unsigned int modelList; 

在我的初始化有這樣的代碼:

glEnableClientState(GL_VERTEX_ARRAY); // vertex array 
glVertexPointer(3, GL_FLOAT, 0, &vertexCoords[0]); 

modelList = glGenLists(1); // generate display list 
glNewList(modelList, GL_COMPILE); 
for (unsigned int i = 0; i < faces.size(); i++) { 
    glBegin(GL_TRIANGLE_STRIP); 
    for (vector<unsigned int>::iterator it = faces[i].begin(); 
      it != faces[i].end(); it++) 
     glArrayElement(*it - 1); 
    glEnd(); 
} 
glEndList(); // End display list. 

這在我glutDisplayFunc,我呼籲:

glCallList(modelList); // Execute display list. 

而不是顯示列表,我想現在使用VBO。我怎樣才能轉換此代碼?提前致謝。

回答

1

你很幸運。你的程序結構已經包含了一切。我們甚至可以避開那個煩人的基於1的索引。

首先創建一個VBO:

GLuint vbo_id; 
GLuint eabo_id; /* EIB = Element Array Buffer */ 
size_t eabo_n_elements; 

void make_vbo() 
{ 
    GLuint genbuf_ids; 
    glGenBuffers(2, genbuf_ids); 

    vbo_id = genbuf_ids[0]; 
    eabo_id = genbuf_ids[1]; 

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id); 

分配空間的數據,任何拷貝頂點數據到緩衝區中。由於您的頂點元素索引數組移動了一個,所以我們爲其中一個頂點分配更多的數據並將其複製到偏移量中(我們也可以使用GL_ARB_draw_elements_base_vertex擴展名,但我想這樣展示它:

glBufferData(
     GL_ARRAY_BUFFER, 
     (vertexCoords.size() + 3)*sizeof(vertexCoords[0]), 
     NULL, 
     GL_STATIC_DRAW); 

    glBufferSubData(
     GL_ARRAY_BUFFER, 
     sizeof(vertexCoords[0])*3, /* offset by 1 vertex */ 
     (vertexCoords.size())*sizeof(vertexCoords[0], 
     &vertexCoords[0]); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 

對於元素數組緩衝區也是一樣的;你將兩個向量「堆棧」在一起......這種方法效率不高,讓我們展開這個,首先爲緩衝區分配內存,但不要複製數據,因爲每個子向量可能具有不同的長度(儘管如果用於特定的原始繪製模式,它們應該都是相同的大小)首先確定元素的總數(使用C++ 11功能auto來保存一些輸入並且我們可以使用迭代器);稍後我們需要知道這個num BER吸引他們:

eabo_n_elements = 0; 
    for(auto i = faces.begin(); i != faces.end(); i++) { 
     eabo_n_elements += i.size(); 
    } 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id); 
    glBufferData(
     GL_ELEMENT_ARRAY_BUFFER, 
     sizeof(faces[0][0]) * eabo_n_elements, 
     NULL, 
     GL_STATIC_DRAW); 

展開拷貝面部數據到EAB

size_t offset = 0; 
    for(auto i = faces.begin(); i != faces.end(); i++) { 
     size_t const len = i.size() * sizeof(i[0]); 
     glBufferSubData(
      GL_ELEMENT_ARRAY_BUFFER, 
      offset, 
      len, 
      &i[0]); 
     offset += len; 
    } 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
} 

現在我們可以得出。從技術上講,我們可以使用VAO(並且使用OpenGL-4,我們必須擁有一個),但我們要保證這一點。繪製VBOs與從客戶端頂點數組繪製非常相似。現在您使用了glVertexPointer這表明您正在使用固定功能流水線。我們可以使用它。但是,然後,維也納組織成爲OpenGL核心功能,只有OpenGL-3(在此之前它已經作爲一個擴展可用很長時間)。所以它是glVertexAttribPointer加上匹配的着色器。爲了保持儘可能小的過渡,讓我們回收您使用glVertexPointer。主要的區別是,我們使glVertexPointer呼叫之前結合VBO並傳遞一個integer-cast-to-a-pointer (which actually may invoke UB for anything other than 0)偏移到數據參數:

void draw_vbo() 
{ 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id); 
    glVertexPointer(3, GL_FLOAT, 0, (void*)0); 

一旦VBO已經「鏈接」到一個頂點數組訪問,我們可以解除綁定。數據仍將從VBO中獲取。

glBindBuffer(GL_ARRAY_BUFFER, 0); 

最後進行繪製調用。請記住,我們在將頂點數據複製到VBO時應用了1單元的偏移量。所以我們只是通過臉部頂點元素索引。與VBO的模式相同:綁定,將指數轉換爲指針並將其傳遞給glDrawElements

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id); 
    glDrawElements(GL_TRIANGLE_STRIP, eabo_n_elements, GL_UNSIGNED_INT, (void*)0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
}