哎,很离谱,上个月学learnopengl学到一半跑去看庄懂老师的视频,结果该还的东西迟早得还,再打开之前的工程有些东西已经记不清楚了,特别是VAO、VBO与EBO这三个东西,之前就总是分不清,这里再做个笔记,以后要是忘了就再回来翻翻好了。
VAO(Vertex Buffer Object),为顶点缓冲区对象,是显卡存储空间里的一块缓存区(Buffer),用于存储 顶点坐标 / 顶点uv / 顶点法线 / 顶点颜色等数据信息。
那怎么解决?
// 顶点数据:
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// 使用 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 把新创建的 VBO 绑定到 GL_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据 (CPU 内存) 拷贝到 VBO(GPU 显存)
// 绘制:
glDrawArrays(GL_TRIANGLES, 0, 3); // 使用 glDrawArrays 来绘制
整个过程还是比较浅显易懂的:做了一次 CPU 到 GPU 的数据拷贝。
EBO(Element Buffer Object),和顶点缓冲对象一样,EBO也是一个缓冲,它专门储存索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。
// 这次我们只定义了 4 个顶点:
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
// 但是通过索引指定了每个三角形的 3 个顶点:
GLuint indices[] = { // 注意索引从 0 开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
// 使用 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 把新创建的 VBO 绑定到 GL_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据 (CPU 内存) 拷贝到 VBO(GPU 显存)
// 使用 EBO:
GLuint EBO;
glGenBuffers(1, &EBO); // 创建 EBO 对象
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // 把新创建的 EBO 绑定到 GL_ELEMENT_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 将所有顶点数据 (CPU 内存) 拷贝到 EBO(GPU 显存),并设定按照indices顺序来渲染
// 绘制:glDrawElements替换掉glDrawArrays函数,表示我们要从索引缓冲区渲染三角形
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 使用 glDrawElements 来绘制
VAO(Vertex Array Object),VAO是所有顶点数据的状态集合。它存储了顶点数据的格式以及顶点数据所需的缓存对象的引用,任何随后的顶性调用都会储存在这个VAO中。
// 顶点数据:
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// 创建 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象
// 创建 VAO:
GLuint VAO;
glGenVertexArrays(1, &VAO); // 创建 VAO 对象,注意这里用的是 glGenVertexArrays
// 在绑定 VAO 后操作 VBO,当前 VAO 会记录 VBO 的操作,我们下面用缩进表示操作 VBO 的代码:
glBindVertexArray(VAO); // 绑定 VAO,注意这里用的是 glBindVertexArray
// 绑定 VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 把顶点数组复制到缓冲中供 OpenGL 使用
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *) 0);
glEnableVertexAttribArray(0);
// 解绑 VAO
glBindVertexArray(0);
// ...省略其他代码...
// 会被调用多次的绘制代码:
glBindVertexArray(VAO); // 绑定使用 VAO 绘制
glDrawArrays(GL_TRIANGLES, 0, 3); // 使用 glDrawArrays 来绘制
glBindVertexArray(0); // 解绑 VAO
上面的代码相比我们用 VBO 绘制三角形的代码还是复杂一些的,上面的代码可以理解为:使用 VAO 记录 VBO 的操作相当于创建了一个快捷方式,后面直接用 VAO 快捷方式绘制。
参考来自: