OpenGL 理解VAO VBO 和 IBO

VAO VBO 和 IBO

 

曾經有一個老師在教我們的時候,給我們說了一句很實在的話,當你接觸一個新的領域的時候,什麼最壓人?名詞最壓人,隨便一個專有名詞都夠你吃一壺的。事實上確實如此。

 

學習OpenGL首先,先要弄明白的三個名詞就是VAO,VBO和IBO。我們學習一個東西的時候,往往被過多,過詳細的數據,淹沒真正核心的那幾句話,這可能也是不同人學習能力不一樣的原因把,我應該屬於學習能力比較弱的那種,總是要一邊叮囑自己,關鍵那幾句話在哪?一邊看東西,才能勉強找到關鍵那幾句話。

 

本篇不是教程,不會說明這三個玩意的來龍去脈以及用法,只是在你已具備相應基礎的前提下,加深一下認知。

 

VAO:頂點數組對象,Vertex Array Object

VBO:頂點緩存對象,Vertex Buffer Object,VBO

IBO:頂點索引對象,Element Buffer Object,EBO或Index Buffer Object,IBO

 

借用一下LearnOpenGL網站上的圖。

 

最讓我迷惑的不是IBO,而是VAO的作用,其實這VAO和IBO一樣,都是爲了“複用”。而VBO關鍵作用在於“打包”上傳。

 

從上圖看來,VAO,其實是VBO的約束器,解讀器。它管理一類VBO的配置。VAO1,只用到一個屬性,VAO2則有兩個屬性,位置和顏色。同時還要用AttributePointer去描述VBO。

 

1、VAO

頂點數組對象:

使用VAO的好處——複用屬性設置。

1、VAO是可複用的

2、VAO可以綁定一系列頂點屬性

3、VAO只能和匹配的VBO綁定,比如你VAO只描述了位置,而VBO包含了頂點和顏色信息,他們不能綁定,否則數據就錯亂了

4、VAO解綁後可以綁定給其他匹配的VBO,這就是“複用”。

2、VBO

頂點緩存對象:

使用VBO的好處——批量數據傳輸。

具體來講:使用VBO好處是可以一次發送大量頂點到顯卡,而不是每次只發送一個頂點。

 

這裏額外思考一下,既然IO是相當費時的,那麼如果內存和顯卡可以異步傳輸數據是不是能節省掉一部分時間?比如先傳A數據,然後渲染A的同時傳B的樹呢?這應該就是多線程渲染做的事情,並不是真的多線程渲染,而是把渲染和IO交錯以節省時間。當然如果瓶頸不是IO,而是渲染本事,那多線程渲染也無力迴天了。

3、IBO

先對來講IBO是最好理解的,假定一個四邊形由兩個三角形組成,共六個頂點,實際上有兩對頂點共享,所以只有四個頂點,IBO用來告訴你,如何複用這些頂點。

比如0,1,3是一個三角形,1,2,3是另一個三角形。

 

這就是IBO的複用。

 

依據以上總結,在回頭來看這段源代碼,就思路就相對清晰了。

 

//聲明頂點數據,實際應用的時候,應該是從FBX等文件裏面讀取的。
//很少自己生成
float vertices[] = {
    -0.5f, -0.5f, 0.0f, // left  
    0.5f, -0.5f, 0.0f, // right 
    0.0f,  0.5f, 0.0f  // top   
};

//創建頂點數組對象和頂點緩存對象
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

//綁定,或者說“選用”這個頂點緩存對象。
glBindVertexArray(VAO);	

//綁定VBO對象,並拷貝數據到VBO
//注意數據不是拷貝給VAO的,VAO裏面不存頂點數據
//GL_STATIC_DRAW,這是不是Unity區分Static和non-static物件的原因?
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), 
             vertices, GL_STATIC_DRAW);

//描述頂點,並把它在0號位置激活,一個VAO可以有多個描述對象。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

//相當於解除綁定。注意是解綁,不是刪除。
glBindBuffer(GL_ARRAY_BUFFER, 0);
//簡單來講,按照綁定的反順序進行解綁就對了。先解綁VBO,再解綁VAO
glBindVertexArray(0);
//到此位置,該送入GPU的數據以及都“送”進去了

//開始進入渲染主循環
while (!glfwWindowShouldClose(window))
{
    //處理輸入
    processInput(window);
    //清屏
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    //選擇shader,這裏不是本篇要講的內容,略過
    glUseProgram(shaderProgram);
    //因爲沒有其他數據,所以不用綁定解綁也沒事,這麼做是爲了規範。
    //思考:當VBO有多個的時候,這裏要怎麼做?
    glBindVertexArray(VAO); 
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
    
    glfwSwapBuffers(window);
    glfwPollEvents();
}

//這裏纔是刪除緩存
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);    

 

發佈了54 篇原創文章 · 獲贊 50 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章