如何增加OpenGL缓冲区的大小?

3

在OpenGL中是否可能扩展缓冲区?

假设我想使用实例渲染。每次在世界中生成新对象时,我都需要用实例数据更新缓冲区。

在这种情况下,我有一个由3个浮点数组成的缓冲区。

  std::vector<GLfloat> offsets = {0.0f,0.5f,1.0f};
  auto offset_buffer = buffer::makeBuffer(BufferDraw::STATIC_DRAW, offsets);

如果我想要有四个元素,我需要调用glBufferData并增加大小吗?但旧数据会发生什么,会被复制吗?还是我需要完全删除缓冲区并创建一个新的缓冲区?

有一个扩展程序可以完成这个任务,否则您需要分配新的缓冲区并复制数据并填充新的缓冲区。否则旧数据将会丢失。 - ratchet freak
我能直接从OpenGL复制数据吗,还是必须再次将其从我的RAM发送到VRAM? - Maik Klein
1
@ratchetfreak:那是哪个扩展?我能想到的唯一一件事就是GL_ARB_sparse_buffer。你可以预留一个比你需要的更大的缓冲区,然后在填充缓冲区时提交内存页面,但该扩展所需的最小页面大小为64 KiB,而float仅为4字节;) - Andon M. Coleman
1个回答

7
您绝对不应该使用新的大小调用glBufferData (...)。这会导致旧缓冲区被废弃,并提供具有更大存储空间的新缓冲区(其内容与先前分配的内存无关)。
只要任何需要旧数据的OpenGL命令仍在管道中排队等待,旧数据将继续存在。在这些命令完成后,OpenGL允许回收内存 - 您不必担心泄漏,但是不会自动进行原地增长。
GL 3.1引入了复制缓冲区的概念,这将帮助您更加高效地完成此操作。
请考虑以下伪代码:
// Bind the old buffer to `GL_COPY_READ_BUFFER`
glBindBuffer (GL_COPY_READ_BUFFER, old_buffer);

// Allocate data for a new buffer
glGenBuffers (1, &new_buffer);
glBindBuffer (GL_COPY_WRITE_BUFFER, new_buffer);
glBufferData (GL_COPY_WRITE_BUFFER, ...);

// Copy `old_buffer_size`-bytes of data from `GL_COPY_READ_BUFFER`
//   to `GL_COPY_WRITE_BUFFER` beginning at 0.
glCopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);

在实际应用中,您可以将缓冲区数据从任何绑定位置复制到任何其他绑定位置。新的GL_COPY_..._BUFFER绑定点非常方便,但并不是必需的,因为它们不会干扰任何其他绑定。


在我复制数据之后,是否可以将new_buffer的句柄更改为old_buffer的句柄?否则,我将不得不创建一个新的vao。 - Maik Klein
1
@MaikKlein:好吧,你可以在将旧缓冲区复制到新缓冲区之后在old_buffer上调用“glBufferData(...)”,然后再将数据复制回去。这样,您将有效地使用“new_buffer”作为备份,同时调整原始缓冲区的大小而不会使存储在VAO中的顶点指针失效。如果您知道某些缓冲区的大小将增长,请通过过度分配缓冲区来避免小的增量增长(少量浪费的内存通常比与进行多次复制相关的驱动程序开销更可取)。 - Andon M. Coleman
1
如果你预先生成了旧缓冲区和新缓冲区,你只需使旧缓冲区变为孤儿,并使用swap(old_buffer, new_buffer);交换它们。 - ratchet freak
这段代码在翻译时给我一个段错误(在Python的PyOpenGL中)。我该怎么办? - N3RDIUM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接