opengl中VAO和VBO的关系
什么是VBO
VBO(vertex buffer object)顶点缓冲对象,用来存储顶点信息,并把这些信息发送给顶点着色器。
VBO是CPU和GPU传递信息的桥梁,我们把数据存入VBO是在CPU上操作,VBO会自动将数据送至GPU。送至GPU不需要任何人为操作。关于VBO另外补充解释:使用VBO管理内存(GPU上储存顶点数据),使用VBO好处就是将内存一次性发送大批数据到显卡,而不是每次发送一个顶点数据。从CPU把这些数据发送到显卡相对较慢,所以只要可能就尝试尽量一次性尽可能多的数据。发送到显卡的内存后,顶点着色器几乎能立即访问顶点,过程比较快。
什么是VAO
VBO将顶点数据传送至GPU只是一堆数字,要怎么向GPU解释它们呢,就需要VAO了。有的读者会奇怪,顶点数据无非是一个个三维坐标,三个为一组,传就传了,为什么还需要解释呢?那么我们来看下面这个VBO中的数据:
float vertices[] = {
// 位置 // 颜色 //纹理坐标
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.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f 0.0f, 0.0f // 顶部
};`
由以上数据可以看出顶点数据并不是三个为一组的三维坐标,也有两个数字一组的。
如果我们向VBO中传入了以上buffer,并且VBO把它们送入了GPU。
然而,顶点着色器不知道该如何解释这些数字,到底是把它们3个一组,还是先3个一组、后2个一组,或者是3个、2个、3个?
GPU并不知道。这就需要VAO来告诉GPU怎么解释这些缓存数据了,如下:
//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);
上面看似解释了顶点坐标属性、颜色属性、纹理坐标属性三段,其实它们同时绑定在一个VAO中。
总结
VBO是顶点缓冲对象,是CPU和GPU中间的桥梁,开发者只需要将数据存入VBO中,VBO自动将数据送入GPU中。而VBO传输的只是一堆数字,GPU怎么解释这些顶点数据,就需要VAO来解释。
补充
一个VAO可以解释多个VBO,这就涉及到OpenGL的上下文知识:一个完整的OpenGL程序相当于一个容器,我们在用到VAO、VBO时,需要先绑定(Bind操作)、再使用,没有经过绑定的VAO/VBO是不起作用的
绑定VAO,告诉OPenGL用这个VAO来解释这个VBO
绑定第一个VBO, 向VBO中写入数据,告知VAO该如何解释VBO
解绑第一个VBO
绑定第二个VBO, 向VBO中写入数据,告知VAO该如何解释VBO
解绑第二个VBO
//========================生成VBO,VAO==========================
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);
//=============================================================
好辣,今天就到这里了~