修改OpenGL顶点缓冲区的正确方法是啥?
Posted
技术标签:
【中文标题】修改OpenGL顶点缓冲区的正确方法是啥?【英文标题】:What is the proper way to modify OpenGL vertex buffer?修改OpenGL顶点缓冲区的正确方法是什么? 【发布时间】:2013-04-04 21:22:36 【问题描述】:我正在 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);
...这会用我的新数据覆盖旧缓冲区吗?还是我也必须删除旧的?有没有更好的办法?
【问题讨论】:
【参考方案1】:当您调用glBufferData
时,会设置任何 OpenGL 缓冲区对象的大小。也就是说,OpenGL 将分配您在 glBufferData
的第二个参数中指定的内存量(在 OP 中没有列出)。事实上,如果你调用,例如glBufferData( GL_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW );
OpenGL 将创建一个bufferSize
字节的未初始化数据 的缓冲区。
您可以使用glBufferSubData
、glMapBuffer
或任何其他用于传递数据的例程加载任意数量的数据(最多为缓冲区大小)。调整缓冲区大小的唯一方法是调用 glBufferData
并为相同的缓冲区 id(从 glGenBuffers
返回的值)设置新的大小。
也就是说,您始终可以使用缓冲区中的数据子集(这类似于删除顶点),如果您使用glDrawElements
进行渲染,则可以随机访问缓冲区中的元素。向缓冲区添加顶点需要分配更大的缓冲区,然后您需要重新加载缓冲区中的所有数据。
【讨论】:
【参考方案2】:http://www.opengl.org/wiki/GLAPI/glBufferData
glBufferData 为当前绑定到目标的缓冲区对象创建一个新的数据存储。任何预先存在的数据存储都将被删除。
这解释了对glBufferData
的调用将“重新分配”数据,缓冲区将具有新的大小。所有旧数据都将丢失。如果您只想写入缓冲区的一部分,请改用glBufferSubData
。
http://www.opengl.org/wiki/GLAPI/glBufferSubData
编辑:glBufferSubData
仅用于替换数据;要调整缓冲区大小,您必须调用 glBufferData
。
此外,您不必先销毁缓冲区并生成新缓冲区。请记住,GLuint 只是 OpenGL 的一种“指针”。它不是实际的存储,因此重复使用相同的“指针”是完全可以的(当然,如果你还没有删除它)。
【讨论】:
与其说 GLuint 是一个指针,不如说 GLuint 是一个句柄。【参考方案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,现在你可以提供自己的数据了。
【讨论】:
以上是关于修改OpenGL顶点缓冲区的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章