介绍
- VBO(Vertex Buffer Objects)顶点缓冲区对象,指的是在 GPU 显存里面存储的顶点数据(位置、颜色)
- EBO/IBO(Element/Index Buffer Object)索引缓冲区对象,指的是为了更高效的利用数据,存储索引来达到减少重复数据的索引数据
- VAO(Vertex Array Object)顶点数组对象,主要作用是用于管理 VBO 或 EBO,减少 glBindBuffer、glEnableVertexAttribArray、glVertexAttribPointer 这些调用操作,高效地实现在顶点数组配置之间切换。
VBO与EBO
OpenGL在调用glDraw*函数的时候,需要从内存中拷贝顶点数据到显存中,这样就存在一些性能消耗,如果在GPU显存中直接缓存这些数据的话,就可以大幅减少 CPU 内存到 GPU 显存的数据拷贝的开销,这就是 VBO 和 EBO 出现的原因。VBO 和 EBO 的作用是在 GPU 显存中开辟一块存储空间来缓存顶点数据或者图元索引数据,避免每次绘制时 CPU 内存到 GPU 显存的数据拷贝,从而提升渲染性能。
VBO是用来缓存顶点数据
VBO的内存布局
如有以下的顶点数据,他的内存布局
GLfloat vertices[] = {
// 位置 // 颜色
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.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
EBO是用用来缓存glDrawElements函数时的索引数据
样例代码:
// 这次我们只定义了 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 显存)
// 绘制:
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 使用 glDrawElements 来绘制
VAO
VAO的作用与VBO和EBO有所不同,VAO主要是用来管理VBO或者EBO,减少 glBindBuffer、glEnableVertexAttribArray、glVertexAttribPointer 这些调用操作
// 创建 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);