VAO,VBO 概念整理總結

現在的OpenGL,如果想繪製一個基本圖元,必須有 VAO 和 VBO,否則無法完成基礎繪製。但是直接擺在眼前兩個英文簡稱,讓人不明所以。今天重新看了一下VAO,VBO 的概念,在此做一個整理總結。

OpenGL 已經拋棄了固定管線,想要 繪製一個 三角形圖元,必須使用自定義着色器.至少要有一個頂點着色器,告訴gl每個頂點如何處理;一個像素着色器,告訴gl每個像素的顏色值。

簡單的 vertex shader 寫法如下:

#version 330 core
layout(location=0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}

簡單的 fragment shader 寫法如下:

#version 330 core
out vec3 color;
void main(){
  color = vec3(1,0,0);
}


寫好了這個shader,程序就具備了繪製頂點的能力。




但是光有着色器,光具備繪製頂點的能力還不夠,因爲gl並不知道具體要繪製什麼內容。要想畫一個正經的三角形,必須告訴gl三角形3個頂點的位置。




可以簡單的定義一個一維數組,當做描述三角形3個頂點位置的數據,分別代表3個座標點(-1,-1,0),(1,-1,0),(0,1,0)


static const GLfloat testVerticePosData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};


由於 gl 的視口裏,只能繪製 [-1,1] 之間的內容,所以我們的默認頂點位置數據裏 ,沒有超出這個取值範圍的數據。




有了這樣的數據描述三角形3個頂點的位置已經夠了,但是電腦只認爲他是一個一維數組,要想把這些數據繪製出來,就需要把這些數據,按照我們所理解的格式,傳到 對應的 shader 中。這時,就需要一個把 內存中的數組數據,傳遞到 shader中的 橋樑。


這時,終於輪到主角出場了:
這個把內存數據,傳遞到 shader 中的橋樑,就是 VAO;
存儲 數據的場所 ,就是 VBO.




VBO 是 Vertex Buffer Object ,頂點緩存對象 的簡稱。
它的作用是,用於存儲內存裏的數據。比如上面描述三角形位置的一維數組 testVerticePosData,可以把它存到一個 VBO 裏。




VAO 全稱, Vertex Array OBject,頂點數組對象。
它負責把 VBO 裏的數據,傳遞到 shader 裏。




創建VBO,設置VBO 數據的 代碼一般是這樣:


GLuint _vboPos;
glGenBuffers(1, &_vboPos);
glBindBuffer(GL_ARRAY_BUFFER, _vboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(testVerticePosData), testVerticePosData,GL_STATIC_DRAW);




創建 VAO 的 代碼是樣:
GLuint _vao;
glGenVertexArrays(1, &_vao);




有了 VAO 和 VBO 可以這樣把他們聯繫起來:


glGenVertexArrays(1, &_vao); // 創建 VAO
glBindVertexArray(_vao); // bind 函數,告訴GL 我現在要操作 _vao 這個 VAO 對象了




glGenBuffers(1, &_vboPos); // 創建用於描述位置信息的vbo
glBindBuffer(GL_ARRAY_BUFFER, _vboPos); // 注意這裏參數是 GL_ARRAY_BUFFER,告訴 GL 這個 vbo 要裝載 頂點數組信息(與之對應的是 頂點索引信息,這裏先不討論)
glBufferData(GL_ARRAY_BUFFER, sizeof(testVerticePosData), testVerticePosData,GL_STATIC_DRAW); // 這裏要真正讓 vbo 真正承載數據了.GL_ARRAY_BUFFER 表示它所描述的是 頂點數組信息,內存大小有 sizeof(testVerticePosData) 那麼大 ,內存數據起始位置 是 testVerticePosData ,GL_STATIC_DRAW 這個位置的參數表示 這段數據是否會 頻繁改變




上面的代碼,在給 vbo 設置數據時,由於已經 glBindVertexArray(_vao); 做了 bind _vao 的操作,所以 GL 明確知道 下面操作 vbo 的數據,是給 _vao 這個 VAO 對象所準備的。


此時, 數據有了--存儲在 _vbo 這個 VBO 對象裏,橋樑有了 -- 是 _vao 這個 VAO 對象.接下來,要把 vbo 裏的數據,通過 vao ,映射到 我們 上面自定義的 vertex shader 裏。




這裏再貼一遍 vertex shader 的代碼:


#version 330 core
layout(location=0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}

in 代表 shader 裏的這個數據是要由 cpp 代碼裏的 VAO 傳進來的。
location = 0 表示,這個 shader 變量的位置index 是 0.

由此,可以用下面glVertexAttribPointer() 函數,來把 vbo 的數據,通過 vao 傳遞到 shader 裏面去:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);


//typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
第1個參數 index,表示 我們 接下來的 vbo 裏面的數據,要傳遞給 vertex shader 裏 location = 0 的 in 的 變量裏面去;
第2個參數 size ,表示 shader 裏面對應變量得緯度。比如 position 是3 (x,y,z),顏色是 4 (r,g,b,a)
第3個參數 type GL_FLOAT 表示 我們用的每個數據 都是浮點數
第4個參數 GLboolean normalized 表示是否 應該被歸一化(這裏我還不是很明白 這裏 GL_TRUE/GL_FALSE 的區別),我的理解是,這個如果是 TRUE 的話,無論你傳什麼樣的數據,有多少維度,到 shader 裏 會被 當做向量 normalize 一次。
第5個參數 stride 和 第6個參數 pointer ,分別表示 vbo 裏的數組數據 之間的間隔,和 起始偏移。正因爲有了這樣兩個參數,可以讓一個 一維數組,同時可以包含很多種類型的數據。


比如 1維數組數據 如果只包含 位置信息

[pt1.x,pt1.y,pt1.z,pt2.x,pt2.y,pt2.z ... ] 則 stride 間隔爲 0,起始偏移 pointer 也是0

比如 1微數據 ,假設同時包含 位置,顏色兩種信息
[pt1.x,pt1.y,pt1.z,pt1.r,pt1.g,pt1.b,pt1.a,pt2.x,pt2.y,pt2.z,pt2.r,pt2.g,pt2.b,pt2.a,....]


這樣一來, 一個 VBO 裏面存儲的數據,就能夠給 shader 提供包括位置,顏色等 多種 數據了.


同時,多個 VBO 也可以同時對應一個 VAO.
例如,vbopos 只存儲位置信息,stride,pointer 都是 0
另一個 vbocolor 只存儲顏色信息,stride,pointer 都是0


只要是 在  glBindVertexArray(_vao); 後, 連續給多個 vbo 賦值,即可實現 多個 vbo 對應一個 vao 的效果。


在 c++數組 ---> VBO ---> VAO ---> shader 這個流程完成以後,需要 依賴 VAO 來開啓 shader 裏面的 參數

glEnableVertexAttribArray(0); // 參數是 shader 參數裏的 location

最後再用  glDrawArrays(),配合 對應的 shader , 即可進行最後的圖元繪製。


glDrawArrays(GL_TRIANGLES, 0, 3);


斷斷續續總結了很久,一直在加班,中間還修改了 bug,現在已經凌晨 4:20了。。語無倫次。
下次思路清晰一些,並且把一些 不明白的再摸得透徹一些,再做 補充和 更改吧。


VAO VBO 的概念非常重要,必須有清晰的認識,才能把 OpenGL 的學習進行下去。
今天的 VAO VBO 筆記先到此爲止。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章