關於VBO

關於VBO


  有時候你不得不承認,OPENGL的開發真的不如DIRECTX,特別對於入門的人來說,一個簡單的概念可以讓我嚼上幾天不得騎姐。
  VBO可以說是OPENGL中里程碑似的東西,通過VBO我們可以把需要渲染的圖元的頂點信息,直接上傳存儲在GPU的顯存中。由於最早的OPENGL不支持實例化繪製,導致在繪製大量相似圖元的時候,需要反覆向GPU提交代碼渲染,這點在OpenGL中的二次方圖元和實例化繪製已經提到過了,會嚴重導致瓶頸效應,而VBO的誕生正好解決了這一問題,當然這特性需要OPENGL3.1以上或者擴展的支持。
  
  說到VBO自然要說到VAO,但是實際上兩者可以完全不相關,只是瞭解了VAO的機制,更容易瞭解VBO而已。

  說到底,VBO就是通過那幾個函數,在GPU顯存中創建一塊BUFFER,用於存儲和頂點以及其屬性相關的信息。瞭解了VAO並且瞭解了頂點數組和頂點索引以後,我們纔可以進一步去了解VBO的使用。
所謂的頂點數組,就是如下的東西:
 GLfloat vertices[] = {
-1.0, -1.0, -1.0 ,
-1.0, -1.0, 1.0 ,
-1.0, 1.0, -1.0 ,
-1.0, 1.0, 1.0 ,
1.0, -1.0, -1.0 ,
1.0, -1.0, 1.0 ,
1.0, 1.0, -1.0 ,
1.0, 1.0, 1.0 ,
};

  上面是一個立方體的一共8個頂點,而頂點索引即如下
 static GLshort frontIndices[] = {0, 1, 3, 2};
  
  上面這個索引只包含了立方體的四個頂點即其中一個面而已,然後我們將這些個頂點數組和頂點索引上傳至GPU的顯存,如下

glGenBuffers(3,buffers);//創建3塊buffer
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);//先將第一塊buffer綁定到當前
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices, GL_STATIC_DRAW);//將頂點數組放入這個buffer
glVertexPointer(3, GL_FLOAT, 0, 0);//指定這個buffer的格式,3代表3個float值爲一個頂點,第一個0代表跨度,這裏數值是緊密排列的,最後一個是數組的入口地址*point,由於已經將buffer綁定到當前,所以填0
glEnableClientState(GL_VERTEX_ARRAY);//使用這個buffer,一定不要忘記

glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);//這裏開始是將第二塊buffer綁定到當前,上傳color數據,和頂點的做法一樣,不多贅述了
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glColorPointer(3, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);


glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);//將第三塊buffer綁定到當前,用於上傳存儲頂點索引的數據,因此BUFFER類型變更爲GL_ELEMENT_ARRAY_BUFFER

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frontIndices),frontIndices,GL_STATIC_DRAW);//同樣是對buffer進行填充

  經過以上代碼,某個圖元的頂點位置以及顏色和索引信息就已經放入GPU了,接下來只要在display函數中,調用glDrawElements就可以繪製了

glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));//由於索引定義的是4個點,因此第一個參數mode是四邊形,第二個是索引的size,第三個是索引的數據類型。
  注意!glDrawElements只接受3種數據類型,當時我因爲指定索引類型爲GL_INT導致無法繪製被卡住了N長時間,坑人啊!最後一個是指針地址,由於當前綁定的buffer是buffer[2],因此填0即可。
最後別忘記了,VBO是需要glew庫支持的,所以要記得在頭文件中添加。

  需要補充的是,關於另外一個函數:glVertexAttribPointer

  這個函數可以在很多人的代碼中見到,普遍是用於GLSL。什麼是GLSL,想想我就頭大,簡單圖形的繪製完全用不到自己編寫渲染器,自定義的渲染器這塊內容我覺得和OPENGL本身一樣水深的很,如果不是從事3D遊戲開發,完全沒必要去碰。
  言歸正傳,因爲大量的這個函數的例子都出現在GLSL中,所以我也是費了很大的勁才搞清楚如何將它用在簡單的OPENGL函數中。
  簡單的來說,它和之前我們用的glVertexPointer是同一個東西,只是如果用了glVertexAttribPointer,那麼我們就不需要死板的只指定vertice爲頂點位置,而是可以創建一個包含了所有頂點位置+頂點顏色+頂點法線+頂點xxx的數組,通過一次將其送入顯存,然後調用glVertexAttribPointer索引其屬性就可以實現。
  比方說我有個attrib[]數組,前3位爲位置,後面依次爲顏色,法線,這樣子就有3個index,依次爲0,1,2.在調用glVertexAttribPointer的時候,先 glEnableVertexAttribArray(0);  使能,在用代碼glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, 0,0);就表示指定了buffer中的第一個索引爲pos,然後用,顏色和法線如法炮製。

總結:其實VBO是很簡單的東西,實現也是很簡單的概念,但是大量的文章不是把關鍵的地方省略了,就是說的不夠通俗易懂,所以還是比較坑人的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章