38

我在 OpenGL 中设置了一个顶点缓冲区,如下所示:

int vboVertexHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);

稍后,如果我想向“vertexData”添加或删除顶点,那么正确的方法是什么?甚至可能吗?我假设我不能直接修改数组而不将其重新发送到 GPU。

如果我修改了 vertexData 数组,那么再次调用它:

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);

...这会用我的新数据覆盖旧缓冲区吗?还是我也必须删除旧的?有没有更好的办法?

4

3 回答 3

40

任何 OpenGL 缓冲区对象的大小都是在您调用glBufferData. 也就是说,OpenGL 将分配您在第二个参数中指定的内存量glBufferData(OP 中没有列出)。事实上,如果你调用,例如glBufferData( GL_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW );OpenGL 将创建一个未初始化数据bufferSize字节的缓冲区。

glBufferSubData您可以使用、glMapBuffer或任何其他用于传递数据的例程加载任意数量的数据(最多为缓冲区的大小) 。调整缓冲区大小的唯一方法是glBufferData使用相同缓冲区 id 的新大小(从 返回的值glGenBuffers)调用。

也就是说,您始终可以使用缓冲区中的数据子集(这类似于删除顶点),并且如果您使用 渲染glDrawElements,则可以随机访问缓冲区中的元素。将顶点添加到缓冲区需要分配更大的缓冲区,然后您需要重新加载缓冲区中的所有数据。

于 2013-04-05T00:09:14.687 回答
7

http://www.opengl.org/wiki/GLAPI/glBufferData

glBufferData 为当前绑定到目标的缓冲区对象创建一个新的数据存储。任何预先存在的数据存储都将被删除。

这解释了调用glBufferData将“重新分配”数据,缓冲区将具有新的大小。所有旧数据都将丢失。如果您只想写入缓冲区的一部分,请glBufferSubData改用。

http://www.opengl.org/wiki/GLAPI/glBufferSubData

编辑:glBufferSubData仅当您要替换数据时;要调整缓冲区大小,您必须调用glBufferData.

此外,您不必先销毁缓冲区并生成一个新缓冲区。请记住,GLuint 只是 OpenGL 的一种“指针”。它不是实际的存储,因此重用相同的“指针”是完全可以的(当然,如果你还没有删除它)。

于 2013-04-04T23:03:57.137 回答
3

1 通过使用 glMapBuffer

void mapBuffer(uint &id, void *data, uint size, uint type) {
    glBindBuffer(type, id);
    // get pointer
    void *ptr = glMapBuffer(type, GL_WRITE_ONLY);
    // now copy data into memory
    memcpy(ptr, data, size);
    // make sure to tell OpenGL we're done with the pointer
    glUnmapBuffer(type);
}

2 通过使用 glBufferSubData

 void updateBuffer(uint &id, uint offset, void *data, uint size, uint type) {
        glBindBuffer(type, id);
        glBufferSubData(type, offset, size, data);
    }

指定要替换的数据存储区域的大小(以字节为单位)

mapBuffer(vbo, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);
resetBuffer(vbo, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);
updateBuffer(vbo, 0, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);

如果你想要你也可以使用 glBufferData-> 但它会删除所有旧数据并重用相同的缓冲区 glInvalidateBufferSubData-> 它在所有地方都设置为 NULL,现在你可以提供自己的数据。

于 2019-04-25T12:05:19.837 回答