OpenGL開發關於VAO和VBO的理解
阿新 • • 發佈:2018-11-16
文章目錄
OpenGL渲染時涉及到的資料傳輸
- 準備好需要繪製的頂點資料。(自己定義的或者是從某些模型檔案中讀取出來的)
- 在GPU中開闢一塊記憶體。
- 將頂點資料傳到上一步開闢的GPU的記憶體中。
- 將著色器程式碼轉化為著色器程式,並連結到當前的執行程式中。
- GPU根據著色器的邏輯將這塊記憶體的資料進行計算。(指定該如何將資料傳送給顯示卡)
- 將這塊已經計算完的資料一併傳送給顯示卡進行渲染繪製。
上述流程中涉及到的記憶體
- 根據上面的流程,可知整個資料渲染的流程中,涉及到兩個資料傳輸的流程,一個是將資料傳輸到GPU中的記憶體、另一個是將GPU中的資料傳輸給顯示卡。
- GPU的記憶體通過頂點緩衝物件(Vertex Buffer Objects),也就是VBO來管理這個記憶體,它會在GPU記憶體(通常被稱為視訊記憶體)中儲存大量頂點。
- 使用這VBO的好處是我們可以一次性的傳送一大批資料到顯示卡上,而不是每個頂點發送一次。
一、VBO的相關API呼叫
- 生成一個VBO物件:
int vboId = glGenBuffers();
- 設定頂點緩衝物件的緩衝型別是GL_ARRAY_BUFFER,將建立的vbo物件繫結到當前的執行程式上,也可以理解為啟用。
glBindBuffer(GL_ARRAY_BUFFER, vboId);
- 將準備好的頂點資料複製到緩衝的記憶體中,posBuffer為頂點資料,GL_STATIC_DRAW表示資料不會改變和幾乎不會改變。第三個引數一共有三個選擇:
GL_STATIC_DRAW
表示資料不會或幾乎不會改變、GL_DYNAMIC_DRAW
GL_STREAM_DRAW
表示資料每次繪製時都會改變。
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
比如說一個緩衝中的資料將頻繁被改變,那麼使用的型別就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,這樣就能確保顯示卡把資料放在能夠高速寫入的記憶體部分。
-
指定輸入資料的哪一個部分對應頂點著色器的哪一個頂點屬性,也就是在渲染前指定OpenGL該如何解釋VBO中的頂點資料。glVertexAttribPointer中的引數的意義分別是:
- 第一個引數為頂點著色器中
layout (location=0) in vec3 position;
中的location的值。
- 第二個引數為第二個引數指定頂點屬性的維數,如果是
vec3,它由3個值組成,所以大小是3
。 - 第三個引數為
資料的型別
。 - 第四個引數為是否希望資料被標準化,如果我們設定為
GL_TRUE
,所有資料都會被對映到0(對於有符號型signed資料是-1)到1之間。 - 第五個引數叫做
步長(Stride)
,它告訴我們在連續的頂點屬性組之間的間隔。設定為0的意思是讓OpenGL自己去識別步長。 - 最後一個引數表示位置資料在緩衝中起始位置的
偏移量(Offset)
。由於位置資料在陣列的開頭,所以這裡是0。
- 第一個引數為頂點著色器中
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
二、渲染vbo記憶體中的資料需要呼叫的API
進行完上面的步驟,準備工作已經做完,接下來就是要準備渲染了。
glEnableVertexAttribArray(0);//使vbo的記憶體變為可用狀態。
glUseProgram(shaderProgram);//呼叫著色器程式。
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);//繪製方法
當一個vbo中的資料準備完成以後,繪製的過程是需要執行以上三步,如果程式中只有一種頂點型別的vbo,那倒還好;如果有很多種vbo(在啟用vbo時,呼叫glBindBuffer
時是可以選擇很多種型別的),這樣一來,在繪製這些vbo時,就需要重複呼叫很多次上面的三個步驟。為了簡化這個流程,也減少GPU和顯示卡的互動次數。思考:有沒有一些方法可以使我們把所有這些狀態配置儲存在一個物件中,並且可以通過繫結這個物件來恢復狀態,此時就提出了VAO
的概念。
三、VAO的相關呼叫的API
頂點陣列物件(Vertex Array Object )VAO
可以像VBO
頂點緩衝物件那樣被建立和繫結。當一個VAO被建立繫結之後,任何隨後的頂點屬性呼叫都會儲存在這個VAO
中。 這樣一來如果有多個vbo物件,在渲染繪製時,就不用執行很多次前面提到的渲染程式,只需要執行一次繫結的VAO的渲染API即可。
- 建立VAO的流程與VBO類似。
int vaoId = glGenVertexArrays();//建立
glBindVertexArray(vaoId);//繫結,啟用
- VAO渲染
glBindVertexArray(getVaoId());
glEnableVertexAttribArray(0);
glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);
四、VBO和VAO的解綁
- VBO解綁
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
- VAO解綁
glDisableVertexAttribArray(0);
glBindVertexArray(0);