Opengl 使用 1 个缓冲区存储所有顶点数据

Opengl storing all vertex data using 1 buffer

我用我所有的顶点数据(位置、纹理坐标、法线)创建了 1 个浮点缓冲区和 1 个 vbo,它们存储如下:

            bf.put(vertices[i].position.x);
            bf.put(vertices[i].position.y);
            bf.put(vertices[i].position.z);
            bf.put(vertices[i].texCoords.x);
            bf.put(vertices[i].texCoords.y);
            bf.put(vertices[i].normals.x);
            bf.put(vertices[i].normals.y);
            bf.put(vertices[i].normals.z);

如何使用 glVertexAttribPointer 将它们传递给着色器?

是否可以这样做:

 glEnableVertexAttribArray(0);

            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glVertexAttribPointer(/*arguments for sending position*/);
 glEnableVertexAttribArray(1);

            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glVertexAttribPointer(/*arguments for sending texture coordinates*/);

glEnableVertexAttribArray(2);

            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glVertexAttribPointer(/*arguments for sending normals*/);

?

如果是,请帮助我理解 glVertexAttribPointer 以及我应该输入的参数。

您用于属性的数据排列通常称为 "interleaved",实际上这是在 VBO 中存储多个属性的推荐方式。它有利于本地数据访问,因为一个顶点的所有属性在内存中彼此相邻,这反过来往往会导致高缓存命中率。

让我们看看glVertexAttribPointer()的签名,然后更详细地解释参数。我有意不从文档中复制解释,希望替代措辞能帮助您更好地理解它们。在LWJGL中,定义为:

static void glVertexAttribPointer(
    int index, int size, int type, boolean normalized,
    int stride, long pointerOffset)
  • index:顶点属性在顶点着色器中的位置,由 glBindAttribLocation() 指定,由 glGetAttribLocation() 获取,或在着色器代码中由 [=16= 指定] 布局限定符。
  • size:属性中的组件数。例如。 3 个用于具有 3 个坐标的位置,2 个用于具有 2 个分量的纹理坐标,等等
  • type:属性类型。主要是 GL_FLOAT.
  • normalized:浮点属性无关紧要,如果您开始使用整数类型属性,请仔细阅读。
  • stride:后续顶点之间的间距(以字节为单位)。除非顶点之间有填充(这种情况很少见),否则这与以字节为单位的顶点大小相同。
  • pointerOffset:由于历史原因,它的名称中有 "pointer",但实际上是相对于缓冲区开始的属性第一次出现的偏移量(以字节为单位)。在交错排列中,这对应于顶点内属性的偏移量,以字节为单位。

在您的例子中,stride 将为 32,因为每个顶点由 8 个浮点分量组成,每个分量为 4 个字节。

pointerOffset第一个属性为0,然后是所有其余属性的相对字节偏移量,这导致其余两个属性为12和20。

这会调用您的示例:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * 4, 3 * 4);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * 4, (3 + 2) * 4);