顶点缓存对象(VBO)与顶点数组对象(VAO)

我们的顶点数组在CPU端的内存里是以数组的形式存在,想要GPU去绘制三角形,那么需要将这些数据传输给GPU。那这些数据在显存端是怎么存储的呢?VBO上场了,它代表GPU上的一段存储空间对象,表现为一个unsigned int类型的变量,GPU端内存对象的一个ID编号、地址、大小。一个VBO对象既代表了GPU端的一段区域。

VBO的创建

VBO的销毁

cpp 复制代码
  // 1 创建一个vbo /*还没有真能正分配显存*/
  GLuint vbo = 0;
  GL_CALL(glGenBuffers(1, &vbo));
  // 2 销毁一个vbo
  GL_CALL(glDeleteBuffers(1, &vbo));
  // 3 创建n个vbo
  GLuint vboArr[] = { 0,0,0 };
  GL_CALL(glGenBuffers(3, vboArr));
  // 4 销毁n个vbo
  GL_CALL(glDeleteBuffers(sizeof(vboArr), vboArr));

VBO绑定+数据更新

VBO绑定

VBO填入数据

该函数会对现存进行销毁重建操作,需要谨慎调用。

多属性数据

通常,一个三角形不仅仅有位置信息,也可能存在颜色、法向、纹理等数据。 这时候我们该怎么存储呢?

针对以上问题,我们能想到创建两个vbo去存放。

还有一种办法是将两种数据存储在一个buffer中,且数据是交叉的。

不管使用哪种方式,我们都应该对数据进行描述,以便GPU对数据进行合理的使用,否则在GPU端也不知道那几个数字代表一个顶点。所以我们需要告诉GPU每个顶点的布局。

什么是VAO?

VAO用来记录每种数据的描述信息的。每个描述信息都描述了某个信息,位置或者颜色。

对于位置颜色在同一个vbo时,我们应该如何去描述,让GPU能够理解这对数据?

对于一个vb中仅有位置数据时,只需要知道

  • 每个顶点有几个数据
  • 每个数字的类型
  • 每个顶点数据的步长
  • 该属性存储在几号vbo(1号)

只要知道这些数据即可准确的描述顶点数据。

对于一个vbo 中既有位置信息又有其他属性时

我们凭借以上信息不能准确地拿到某个属性数据,比如下图中的颜色信息。

位置数据处于每组数据的开头,颜色信息处于每组数据的其中,针对每组数据,位置信息存在一个固定的偏移量,这个偏移量就是每个顶点数据的大小。

综上,总结如下:

VAO的创建与删除

VAO加入VBO描述

DEMO1(顶点数据独立存放)

cpp 复制代码
void prepareSingleBuffer()
{
  float positions[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
  };

  float colors[] = {
    1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    0.0f,  0.0f, 1.0f
  };
  // 1 生成一个vbo
  GLuint vboPos = 0, vboColor = 0;
  GL_CALL(glGenBuffers(1, &vboPos));
  GL_CALL(glGenBuffers(1, &vboColor));

  // 2 绑定当前vbo,到opengl状态机的当前vbo插槽
  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vboPos));
  GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW));

  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vboColor));
  GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW));

  // 创建及绑定vao
  GLuint vaoPos = 0;
  GL_CALL(glGenVertexArrays(1, &vaoPos));
  GL_CALL(glBindVertexArray(vaoPos));
  // 描述为指数型
  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vboPos)); // 只有绑定了vbo,下面的属性描述才会有当前vbo有关系
  GL_CALL(glEnableVertexAttribArray(0));
  GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (GLvoid*)0));

  // 创建及绑定vao
  GLuint vaoColor = 0;
  GL_CALL(glGenVertexArrays(1, &vaoColor));
  GL_CALL(glBindVertexArray(vaoColor));
  // 描述为指数型
  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vboColor)); // 只有绑定了vbo,下面的属性描述才会有当前vbo有关系
  GL_CALL(glEnableVertexAttribArray(1));
  GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*)0));

  GL_CALL(glBindVertexArray(0));
}

DEMO(顶点数据混合存放)

cpp 复制代码
void prepareInterleavedBuffer()
{
  float 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
  };

  GLuint vbo = 0;
  GL_CALL(glGenBuffers(1, &vbo));
  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
  GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));

  GLuint vao = 0;
  GL_CALL(glGenVertexArrays(1, &vao));
  GL_CALL(glBindVertexArray(vao));

  GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));

  GL_CALL(glEnableVertexAttribArray(0));
  GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)0));

  GL_CALL(glEnableVertexAttribArray(1));
  GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT))));

  GL_CALL(glBindVertexArray(0));
}
相关推荐
刘好念1 天前
[OpenGL]使用TransformFeedback实现粒子效果
c++·计算机图形学·opengl
吃豆腐长肉3 天前
着色器 (三)
opengl·着色器
吃豆腐长肉3 天前
opengl 着色器 (四)最终章收尾
opengl·着色器
德林恩宝5 天前
WebGPU、WebGL 和 OpenGL/Vulkan对比分析
web·webgl·opengl·webgpu
zaizai10078 天前
LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)
opengl
刘好念8 天前
[OpenGL] Transform feedback 介绍以及使用示例
c++·计算机图形学·opengl
爱看书的小沐8 天前
【小沐学GIS】基于C++绘制三维数字地球Earth(OpenGL、glfw、glut、QT)第三期
c++·qt·opengl·earth·osm·三维地球·数字地球
闲暇部落11 天前
OpenGL ES详解——多个纹理实现混叠显示
opengl·纹理叠加
LiQingCode12 天前
OpenTK中文教程——1.7变换
c#·opengl
zaizai100713 天前
LearnOpenGL学习(高级OpenGL --> 帧缓冲,立方体贴图,高级数据)
opengl