VAO_VBO

1. 函数解析

1
initializeOpenGLFunctions();

初始化OpenGL函数,将Qt里的函数指针指向显卡的函数,这样如glGenBuffers()这样的函数实际操作的就是显卡上的内存了。

1.1 VBO

VBO(Vertex Buffer Object):顶点缓冲区对象

  • VBO 是一种用于在 GPU 中存储数据(例如顶点数据)的缓冲区对象。
  • VBO 存储的是实际的顶点数据、索引数据,如坐标分量,颜色等。
  • 通过把顶点数据上传到 VBO 中,可以让 OpenGL 在渲染过程中直接从显存读取数据。
  • VBO 不保存顶点数据的布局或如何处理这些数据的信息。它只是简单地存储一段内存区域,数据是原始的顶点数据。
1
2
unsigned int VBO;
glGenBuffers(1, &VBO);

unsigned int VBO;是在CPU上创建了一个int类型的缓冲Id。

glGenBuffers(1, &VBO);相当于在GPU上创建了一个缓冲区对象标识符(buffer object identifier),也就是一个在 OpenGL 上下文中使用的唯一 整数标识符。

1
glBindBuffer(GL_ARRAY_BUFFER, VBO);

将OpenGL中的GL_ARRAY_BUFFER缓冲区指向通过glGenBuffers(1, &VBO);生成的缓冲区对象标识符。

1
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

在显卡的显存中分配一块区域,并将顶点数据从主机内存CPU传到显卡内存GPU。

1.2 VAO

VAO(Vertex Array Object):顶点数组对象

  • VAO 是一个用来存储与顶点数据相关的状态的对象。它用于记录顶点数据的绑定情况(比如,顶点缓冲区对象 VBO 的绑定,顶点属性指针等)。
  • 在渲染过程中,OpenGL 不直接处理顶点数据,而是通过绑定一个 VAO 来告知 OpenGL 如何从相应的缓冲区中获取顶点数据。VAO 记录了顶点数据的格式(例如每个顶点有多少个属性,属性的类型是什么,如何从缓冲区中获取这些数据等)。
1
2
unsigned int VAO;
glGenVertexArrays(1, &VAO);
  • VBO不同的是,glGenVertexArrays(1, &VAO);会在 GPU 上创建一个 唯一的标识符,该标识符代表一个顶点数组对象。
  • 会生成一个唯一的整数 VAO,它是一个指向顶点数组对象的 句柄(或标识符),你可以用它来进行 glBindVertexArray() 操作,将该 VAO 绑定到当前的上下文中。
  • 一旦 VAO 被绑定,它将为该状态生效,之后的顶点缓冲区和顶点属性设置都会与该 VAO 关联。这样,通过切换不同的 VAO,你可以快速切换多个渲染对象的顶点数据和配置。
1
glBindVertexArray(VAO);

VAO 绑定到当前的OpenGL上下文中,同一时刻只能绑定一个 VAO(顶点数组对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
////////////////////-----只是用来举例的数据-----///////////////////////////////
void glVertexAttribPointer(
GLuint index, // 顶点属性的索引,通常是顶点着色器中的位置
GLint size, // 每个顶点属性的组件数量(例如,3表示 x, y, z)
GLenum type, // 数据类型(GL_FLOAT, GL_INT, GL_UNSIGNED_BYTE等)
GLboolean normalized, // 是否将数据归一化
GLsizei stride, // 相邻顶点间的字节偏移量
const void *pointer // 顶点数据的起始位置
);
float vertices[20] = {
// position(-1~1) // texture coords(0~1)
1, 1, 0.0f, 1.0f, 1.0f, // top right
1, -1, 0.0f, 1.0f, 0.0f, // bottom right
-1, -1, 0.0f, 0.0f, 0.0f, // bottom left
-1, 1, 0.0f, 0.0f, 1.0f, // top left
};
///////////////////////////////////////////////////////////////////////////

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
  • 第一个参数是指传到顶点着色器的位置索引,是用来给顶点着色器使用的。

image-20241210102940749

  • 第二个参数是每个顶点属性的大小。比如位置顶点属性是一个vec3(xyz),由3个值组成,大小就是3。纹理属性是一个vec2,大小就是2。
  • 第三个参数指定数据的类型。
  • 第四个参数指是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。这里我们把它设置为GL_FALSE。
  • 第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在5个float之后,我们把步长设置为5 * sizeof(float)。
  • 最后一个参数的类型是void*,数据指针,表示这个属性的数据在缓冲中起始位置的偏移量(Offset),在本例中position偏移量为0,texture为3 * sizeof(float)。
1
glEnableVertexAttribArray(0); // 启用某个位置的索引
1
glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑
1
glBindVertexArray(0); // 解绑
1
2
3
4
5
6
7
8
// 每当需要绘制新的一帧时,通常会先清除当前帧缓冲区,以确保上一帧的图像不干扰当前帧的渲染
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置清除颜色
glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

glBindVertexArray(VAO);
//使用当前绑定的 VAO 中的顶点数据,从第一个顶点开始绘制 3 个顶点,形成一个三角形
//OpenGL可以绘制多种类型的图形,比如点(GL_POINTS)、线(GL_LINES)、三角形(GL_TRIANGLES)等。
glDrawArrays(GL_TRIANGLES, 0, 3);