glGenBuffers(int n, ByteBuffer buffer)
生成n个顶点缓冲对象(VBOs),您可以使用它们来存储数据,并将它们放入指定的缓冲区中。这个缓冲区实际上并不是保存您的数据,而是刚刚生成的VBO的ids。您必须使用glBufferData
手动定义VBO数据。
如果您想一次创建多个VBO,则此函数非常有用。每个VBO id都是一个整数,缓冲区必须足够大以容纳n个(在本例中为4)缓冲区。
ByteBuffer buffer = BufferUtils.createByteBuffer(4 * Integer.BYTES);
glGenBuffers(4, buffer);
然而,为了让事情变得更简单,您也可以使用
IntBuffer
。
IntBuffer buffer = BufferUtils.createIntBuffer(4);
glGenBuffers(4, buffer);
你可以将数据附加到每个VBO上。
glBindBuffer(GL_ARRAY_BUFFER, buffer.get(2);
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW);
如果您使用的是 ByteBuffer
,则必须调用 buffer.getInt(2)
。
通常情况下,将所有数据放入单个缓冲区中更加高效。但请注意,在此情况下,您必须使用至少两个缓冲区,因为索引必须位于 GL_ELEMENT_ARRAY_BUFFER
中。 然而,性能差异非常小,因此可能更容易使用几个不同的 VBOs。
推荐紧密打包所有数据到一个缓冲区,并使用 glBufferData
上传,而不是针对每种类型的数据调用 glBufferSubData
。您的数据布局将如下所示(P = 位置,T = 纹理坐标,N = 法向量):
PPPTTNNNPPPTTNNNPPPTTN...
现在您可以设置顶点属性指针,以正确地从此缓冲区读取值。
int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, tightlyPackedData, GL_STATIC_DRAW);
int stride = (3 + 2 + 3) * Float.BYTES;
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, false, stride, 0);
glVertexAttribPointer(texCoordIndex, 2, GL_FLOAT, false, stride, 3 * Float.BYTES);
glVertexAttribPointer(normalIndex, 3, GL_FLOAT, false, stride, (3 + 2) * Float.BYTES);
positionIndex
、texCoordIndex
和normalIndex
是你的顶点着色器属性的属性位置。你可以使用glGetAttribLocation
获取它们。
stride
是一个顶点值与下一个顶点值之间的字节数。我们有3个位置、2个纹理坐标和3个法线,它们都是浮点数,所以我们用Float.BYTES
乘以它们。
glVertexAttribPointer
的最后一个参数是偏移量(以字节为单位),即从缓冲区开头到第一个值所在位置的字节数。
glGenBuffers()
并不会生成VBO,它只是为缓冲对象生成名称(或者如果你更喜欢这样称呼的话,id)。只有在第一次绑定名称时才会创建VBO。此外,如果使用索引,您不必使用两个VBO。尽管这不常见,但在同一个缓冲区中存储索引和顶点数据是完全合法的。 - Reto Koradi