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);
我用我所有的顶点数据(位置、纹理坐标、法线)创建了 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);