OpenGL开发关于VAO和VBO的理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xyh930929/article/details/83352645

OpenGL渲染时涉及到的数据传输

  • 准备好需要绘制的顶点数据。(自己定义的或者是从某些模型文件中读取出来的)
  • 在GPU中开辟一块内存。
  • 将顶点数据传到上一步开辟的GPU的内存中。
  • 将着色器代码转化为着色器程序,并链接到当前的执行程序中。
  • GPU根据着色器的逻辑将这块内存的数据进行计算。(指定该如何将数据发送给显卡)
  • 将这块已经计算完的数据一并发送给显卡进行渲染绘制。

上述流程中涉及到的内存

  1. 根据上面的流程,可知整个数据渲染的流程中,涉及到两个数据传输的流程,一个是将数据传输到GPU中的内存、另一个是将GPU中的数据传输给显卡
  2. GPU的内存通过顶点缓冲对象(Vertex Buffer Objects),也就是VBO来管理这个内存,它会在GPU内存(通常被称为显存)中储存大量顶点。
  3. 使用这VBO的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。

一、VBO的相关API调用

  • 生成一个VBO对象:
int vboId = glGenBuffers();
  • 设置顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER,将创建的vbo对象绑定到当前的执行程序上,也可以理解为激活
glBindBuffer(GL_ARRAY_BUFFER, vboId);
  • 将准备好的顶点数据复制到缓冲的内存中,posBuffer为顶点数据,GL_STATIC_DRAW表示数据不会改变和几乎不会改变。第三个参数一共有三个选择:GL_STATIC_DRAW 表示数据不会或几乎不会改变、GL_DYNAMIC_DRAW表示数据会被改变很多、GL_STREAM_DRAW 表示数据每次绘制时都会改变。
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);

比如说一个缓冲中的数据将频繁被改变,那么使用的类型就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,这样就能确保显卡把数据放在能够高速写入的内存部分。

在这里插入图片描述

  • 指定输入数据的哪一个部分对应顶点着色器的哪一个顶点属性,也就是在渲染前指定OpenGL该如何解释VBO中的顶点数据。glVertexAttribPointer中的参数的意义分别是:

    • 第一个参数为顶点着色器中layout (location=0) in vec3 position;中的location的值。
    • 第二个参数为第二个参数指定顶点属性的维数,如果是vec3,它由3个值组成,所以大小是3
    • 第三个参数为数据的类型
    • 第四个参数为是否希望数据被标准化,如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。
    • 第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。设置为0的意思是让OpenGL自己去识别步长。
    • 最后一个参数表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0。
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

二、渲染vbo内存中的数据需要调用的API

进行完上面的步骤,准备工作已经做完,接下来就是要准备渲染了。

glEnableVertexAttribArray(0);//使vbo的内存变为可用状态。
glUseProgram(shaderProgram);//调用着色器程序。
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);//绘制方法

当一个vbo中的数据准备完成以后,绘制的过程是需要执行以上三步,如果程序中只有一种顶点类型的vbo,那倒还好;如果有很多种vbo(在激活vbo时,调用glBindBuffer时是可以选择很多种类型的),这样一来,在绘制这些vbo时,就需要重复调用很多次上面的三个步骤。为了简化这个流程,也减少GPU和显卡的交互次数。思考:有没有一些方法可以使我们把所有这些状态配置储存在一个对象中,并且可以通过绑定这个对象来恢复状态,此时就提出了VAO的概念。

三、VAO的相关调用的API

顶点数组对象(Vertex Array Object )VAO可以像VBO顶点缓冲对象那样被创建和绑定。当一个VAO被创建绑定之后,任何随后的顶点属性调用都会储存在这个VAO中。 这样一来如果有多个vbo对象,在渲染绘制时,就不用执行很多次前面提到的渲染程序,只需要执行一次绑定的VAO的渲染API即可。

  • 创建VAO的流程与VBO类似。
int vaoId = glGenVertexArrays();//创建
glBindVertexArray(vaoId);//绑定,激活
  • VAO渲染
glBindVertexArray(getVaoId());
glEnableVertexAttribArray(0)glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);

四、VBO和VAO的解绑

  • VBO解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
  • VAO解绑
glDisableVertexAttribArray(0);
glBindVertexArray(0);

猜你喜欢

转载自blog.csdn.net/xyh930929/article/details/83352645