顶点缓存对象(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));
}
相关推荐
:mnong10 小时前
Web 三维可视化技术对比:ParaView Web vs 本项目 wasm + Three.js
前端·webgl·opengl·opencl·科学可视化
扶尔魔ocy1 天前
【qt openGL入门笔记】OSG实现显示飞机模型飞行的点迹(二)
qt·opengl·osg
扶尔魔ocy2 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行(三)
opengl·osg
扶尔魔ocy3 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行
qt·opengl·osg
扶尔魔ocy7 天前
【qt openGL入门笔记】FPS相机
qt·opengl
扶尔魔ocy7 天前
qt openGL入门笔记】FPS相机和轨道相机
qt·opengl
扶尔魔ocy8 天前
【qt openGL入门笔记】基础光照
qt·opengl
扶尔魔ocy9 天前
【qt openGL入门笔记】坐标系统和摄像机
qt·opengl
茉莉玫瑰花茶12 天前
OpenGL [ 纹理 ]
开发语言·c++·opengl
mmsx23 天前
Android 地图十万要素不卡顿:空间网格 + 渐进式加载的移动端实践
android·大数据·opengl