1. 程式人生 > >OpenGL開發關於VAO和VBO的理解

OpenGL開發關於VAO和VBO的理解

文章目錄

OpenGL渲染時涉及到的資料傳輸

  • 準備好需要繪製的頂點資料。(自己定義的或者是從某些模型檔案中讀取出來的)
  • 在GPU中開闢一塊記憶體。
  • 將頂點資料傳到上一步開闢的GPU的記憶體中。
  • 將著色器程式碼轉化為著色器程式,並連結到當前的執行程式中。
  • GPU根據著色器的邏輯將這塊記憶體的資料進行計算。(指定該如何將資料傳送給顯示卡)
  • 將這塊已經計算完的資料一併傳送給顯示卡進行渲染繪製。

上述流程中涉及到的記憶體

  1. 根據上面的流程,可知整個資料渲染的流程中,涉及到兩個資料傳輸的流程,一個是將資料傳輸到GPU中的記憶體、另一個是將GPU中的資料傳輸給顯示卡
  2. GPU的記憶體通過頂點緩衝物件(Vertex Buffer Objects),也就是VBO來管理這個記憶體,它會在GPU記憶體(通常被稱為視訊記憶體)中儲存大量頂點。
  3. 使用這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);