1. 程式人生 >實用技巧 >其它 >【影象】【OpenGL】VAO和VBO的關係

【影象】【OpenGL】VAO和VBO的關係


技術標籤:影象opengl

注: VAO和VBO都是用來儲存頂點資訊的,並把這些資訊送入頂點著色器。至於什麼是頂點和頂點著色器,這裡就不多說了,不瞭解的讀者可自行CSDN。

VBO的B為Buffer之意,用來儲存頂點資料;VAO的A為Array,但我認為理解為 Attribute(屬性) 之意更好,意思是 Buffer(VBO)的屬性。

即,我們用VBO來儲存資料,通過VAO來告訴計算機這些資料分別有什麼屬性、起什麼作用。

一、VBO的作用

VBO是 CPU 和 GPU 之間傳遞資訊的橋樑,我們把資料存入VBO(這一步在CPU執行),然後VBO會自動把資料送入GPU。

送入GPU這一步,不需任何人為操作,使用者只負責往VBO中存入資料就可以了。如下:

【影象】【OpenGL】VAO和VBO的關係

但是,對GPU來說,VBO中存的就只是一堆數字而已,要怎麼解釋它們呢?這就要用到VAO了。

二、VAO的作用

VBO是為了向GPU傳遞頂點資料,那麼VAO就是為了向GPU解釋頂點資料。有的讀者會奇怪,頂點資料無非是一個個三維座標,三個為一組,傳就傳了,為什麼還需要解釋呢?那麼我們來看下面這個VBO中的資料:

float buffer = {
   	//頂點座標(3個一組)              //頂點顏色(3個一組)              //紋理座標(2個一組)
    0.5f,  0.5f, 0.0f,                1.0f, 0.0f, 0.0f,               1.0f, 1.0f,
    0.5f, -0.5f, 0.0f,                0.0f, 1.0f, 0.0f,               1.0f, 0.0f,
   -0.5f, -0.5f, 0.0f,                0.0f, 0.0f, 1.0f,               0.0f, 0.0f,
   -0.5f,  0.5f, 0.0f,                1.0f, 1.0f, 0.0f,               0.0f, 1.0f
};
//以上資料僅為本博文編造,不具有實操意義

如果我們向VBO中傳入了以上buffer,並且VBO把它們送入了GPU。

然而,頂點著色器不知道該如何解釋這些數字,到底是把它們3個一組,還是先3個一組、後2個一組,或者是3個、2個、3個?

GPU並不知道。

這就需要VAO的參與了,它負責告訴GPU,VBO中的資訊到底該以幾個為一組。如下這一段程式,就是把對VBO中資料的描述存到了一個VAO中:

	//vertex coord
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

上面程式看似有三段(glVertexAttribPointer() + glEnableVertexAttribArray()為一段),但它們都存在同一個VAO裡。(這裡就不介紹glVertexAttribPointer()和glEnableVertexAttribArray()函式的作用了,不懂的讀者可以上網去查。)

在一些複雜的OpenGL程式中,VBO可能會有多個,但VAO只有一個。那麼,如何用一個VAO來解釋多個VBO呢?

三、一個VAO和多個VBO

在OpenGL程式中,VBO可能會有多個,但VAO只有一個。那麼,如何用一個VAO來解釋多個VBO呢?

這就涉及到OpenGL的上下文知識:一個完整的OpenGL程式相當於一個容器,我們在用到VAO、VBO時,需要先繫結(Bind操作)、再使用,沒有經過繫結的VAO/VBO是不起作用的。

一個VAO和多個VBO之間的關係大致如下所示:

【影象】【OpenGL】VAO和VBO的關係

那麼,根據一個VAO與多個VBO的關係,以及OpenGL上下文(繫結)的知識,用一個VAO來解釋多個VBO的操作流程就如下:

首先,繫結VAO,以告知OpenGL程式該使用這個VAO來對VBO做出解釋。

然後,繫結第一個VBO,向這個VBO中寫入資料,告知VAO該如何解釋這個VBO的資訊;
然後,解綁這個VBO。

然後,繫結第二個VBO,向這個VBO中寫入資料,並在VAO中儲存該如何解釋這個VBO的資訊;
然後,解綁這個VBO。
……

如下一段程式:

	unsigned int VBO[2], VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(2, VBO);

//=========================繫結VAO===============================
	glBindVertexArray(VAO); 
//===============================================================

//=======================繫結第一個VBO============================
	glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
//===============================================================
	 
	glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW); //向第一個VBO中寫入資料

//================告知VAO該如何解釋第一個VBO的資訊=================
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
//===============================================================

//=======================解綁第一個VBO===========================
	glBindBuffer(GL_ARRAY_BUFFER, 0);
//===============================================================

//=======================繫結第二個VBO============================
	glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
//===============================================================

	glBufferData(GL_ARRAY_BUFFER, sizeof(texVertrices), texVertrices, GL_STATIC_DRAW);//向第二個VBO中寫入資料

//================告知VAO該如何解釋第二個VBO的資訊=================
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(1);
//=============================================================