其他分享
首页 > 其他分享> > OpenGL缓冲对象:VBO、IBO和VAO

OpenGL缓冲对象:VBO、IBO和VAO

作者:互联网

VBO

VBO即Vertex Buffer Object(顶点缓冲对象),顶点数据块,在显存中,可被GPU直接访问。

 

创建并填充VBO

创建VBO,并将顶点数组中数据来填充到VBO(内存 --》显存)。

float vertices[] = {
    // postion              // color
     0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
    -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
    -0.5f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 左上
     0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 1.0f    // 右上
};

unsigned int VBO;
glGenBuffers(1, &VBO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);  // 把id为VBO绑定到GL_ARRAY_BUFFER类型的Buffer上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 拷贝vertices数组(内存)到GL_ARRAY_BUFFER类型的Buffer(显存)

 

VBO显存布局

 

IBO

IBO即Index Buffer Object(索引缓冲对象),又称EBO(Element Buffer Object,元素缓冲对象)。索引数据块,在显存中,可被GPU直接访问。

 

创建并填充IBO

创建IBO,并将索引数组中数据来填充到IBO(内存 --》显存)。

unsigned int indices[] = {  // note that we start from 0!
      0, 1, 3,  // first Triangle
      1, 2, 3   // second Triangle
};
unsigned int IBO;
glGenBuffers(1, &IBO);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);  // 把id为IBO绑定到GL_ELEMENT_ARRAY_BUFFER类型的Buffer上
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 拷贝indices数组(内存)到GL_ELEMENT_ARRAY_BUFFER类型的Buffer(显存)

 

IBO显存布局

 

使用IBO来绘制图元

有了IBO,就不需要为了组合出图元在VBO中保存重复的顶点。在渲染循环中,使用glDrawElements取代glDrawArrays来绘制图元。

while (1)
{
// Sleep for a while
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); //glDrawArrays(GL_TRIANGLES, 0, 3); // 参数1为绘制的图元类型;参数2为顶点数组的起始索引;参数3为绘制的顶点数 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 参数1为绘制的图元类型;参数2为绘制的顶点数;参数3为索引的类型;参数4为IBO的起始偏移 }

 

VAO

VAO即Vertex Array Object(顶点数组对象),在显存中,用来记录顶点属性(Vertex Attribute)和IBO的上下文信息。创建并绑定VAO后,后续的顶点属性调用都会储存在这个VAO中。

使用VAO好处是,当配置顶点属性指针时,只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。

 

创建并记录上下文信息到VAO

glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);  // 把id为VBO绑定到GL_ARRAY_BUFFER类型的Buffer上

// position顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); // 启用location为0的顶点属性  注:顶点属性默认是禁用的
// color顶点属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);   // 启用location为1的顶点属性  注:顶点属性默认是禁用的


glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); // 把id为IBO绑定到GL_ELEMENT_ARRAY_BUFFER类型的Buffer上

 

glVertexAttribPointer函数的参数非常多,各参数含义如下:

① 第一个参数index指定vs中layout的location值。如上在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location)。

② 第二个参数size指定顶点属性的大小。如position顶点属性是一个vec3,它由3个值组成,所以大小是3。

③ 第三个参数type指定数据的类型,这里是GL_FLOAT(GLSL中vec3都是由浮点数值组成的)。

④ 第四个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。如果不需要,则设置为GL_FALSE。

⑤ 第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后,我们把步长设置为3 * sizeof(float)。

     要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为0来让OpenGL决定具体步长是多少(只有当数值是紧密排列【Tightly Packed】时才可用)。

     一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔,我们在后面会看到更多的例子(译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组0位置之间有多少字节)。

⑥ 最后一个参数的类型是void*。表示位置数据在缓冲中起始位置的偏移量(Offset)。如postion数据在数组的开头,所以这里是0。

 

顶点着色器(vs)代码如下:

#version 330 core
layout (location = 0) in vec3 aPos;   // position的属性位置值为 0 
layout (location = 1) in vec3 aColor; // color的属性位置值为 1

out vec3 ourColor; // 向片段着色器输出一个颜色

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}

 

VAO显存布局

 

使用VAO来绘制对象

有了VAO,在渲染循环中,就可以直接使用VAO来切换顶点属性和IBO的上下文信息,然后调用Draw命令来绘制对象了。

while (1)
{
// Sleep for a while
glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 参数1为绘制的图元类型;参数2为绘制的顶点数;参数3为索引的类型;参数4为IBO的起始偏移 }

 

参考

LearnOpenGL CN(你好,三角形)

 

标签:VAO,OpenGL,BUFFER,IBO,VBO,顶点,GL
来源: https://www.cnblogs.com/kekec/p/16391957.html