OpenGL一点错误理解

OpenGL的一些记录。

小章节

内容来自 OpenGL:动态修改VBO/EBO_六月的翅膀的博客-CSDN博客
主要的错误有:

  • VAO 和 VBO 的理解错误。
  • VAO 中的 stride 理解错误。
  • 面上节点顺序剔除问题。

VAO

第一个问题可以用 你好,三角形 - LearnOpenGL CN 的讲解解释:

顶点数组对象 (Vertex Array Object, VAO) 可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个 VAO 中。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的 VAO 就行了。这使在不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的 VAO 就行了。刚刚设置的所有状态都将存储在 VAO 中

注意这里说的是顶点属性调用。一个顶点数组对象会储存以下这些内容:

  • glEnableVertexAttribArrayglDisableVertexAttribArray 的调用。
  • 通过 glVertexAttribPointer 设置的顶点属性配置。
  • 通过 glVertexAttribPointer 调用与顶点属性关联的顶点缓冲对象。

pFD87fe.png

也就是说,VAO 和 VBO 是相对独立的。所以修改 VBO 的数据的时候,不用考虑 VAO 的问题。
其实对于 EBO,VAO 也会进行记录,但是记录的方式不同。glDrawElements 函数从当前绑定到 GL_ELEMENT_ARRAY_BUFFER 目标的 EBO 中获取其索引。这意味着我们每次想要使用索引渲染对象时都必须绑定相应的 EBO,这又有点麻烦。碰巧顶点数组对象也跟踪元素缓冲区对象绑定。在绑定 VAO 时,绑定的最后一个元素缓冲区对象存储为 VAO 的元素缓冲区对象。然后,绑定到 VAO 也会自动绑定该 EBO。

pFD8bSH.png

也就是说,VAO 记录的是最后一个绑定的 GL_ELEMENT_ARRAY_BUFFER,所以在 VAO 解绑之前,不能解绑 EBO。而 VAO 记录的 VBO 都是指针,解不解绑是无所谓的,所以无需紧张。

Stride

第二个问题也是看书就得知的。
glVertexAttribPointer 函数的参数非常多,所以我会逐一介绍它们:

  • 第一个参数指定我们要配置的顶点属性。还记得我们在顶点着色器中使用 layout(location = 0) 定义了 position 顶点属性的位置值 (Location) 吗?它可以把顶点属性的位置值设置为 0。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入 0
  • 第二个参数指定顶点属性的大小。顶点属性是一个 vec3,它由 3 个值组成,所以大小是 3。
  • 第三个参数指定数据的类型,这里是 GL_FLOAT(GLSL 中 vec* 都是由浮点数值组成的)。
  • 下个参数定义我们是否希望数据被标准化 (Normalize)。如果我们设置为 GL_TRUE,所有数据都会被映射到 0(对于有符号型 signed 数据是 -1)到 1 之间。我们把它设置为 GL_FALSE
  • 第五个参数叫做步长 (Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在 3 个 float 之后,我们把步长设置为 3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为 0 来让 OpenGL 决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔,我们在后面会看到更多的例子(译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组 0 位置之间有多少字节)。
  • 最后一个参数的类型是 void*,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量 (Offset)。由于位置数据在数组的开头,所以这里是 0。我们会在后面详细解释这个参数。
    这个问题就很简单了,填零的时候是自动计算的,而不是说紧密排布。

正向剔除

这个也是看书就能得到的事情。OpenGL 提供剔除的功能,可以自行设置。这也要求点是按照逆时针的顺序排布,不能乱序。

Program 的 uniform 设置

要想设置 program 的变量,必须首先 bind 这个程序。debug 用时一小时。

1
2
program->bind();
f->glDrawArrays(GL_POINTS, 0, nbr);

解决方案:以后动手之前,必须整理好学习资料。出现问题,第一时间查看手册。