在this question about growing buffers中,有人回答以下代码。
// 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);
这是我对上述内容的理解,以便将A复制到B:
Bind A
Generate B
Bind B
Write null contents to B at larger size
Copy A to B
我的问题是A是着色器的原始顶点缓冲区,而B也是(因为目标是更改大小)。在我的代码(C#opentk)中,着色器告诉我使用GL.GetActiveAttrib
与命名着色器变量重合的缓冲区的ID,我找不到如何使其使用与提供的缓冲区不同的缓冲区的方法。
所以我要么必须重新分配着色器才能在以后使用B,要么进行双重复制:
Bind A
Generate B
Bind B
Write null contents to B at larger size
Copy A to B
Reassign shader to use B
Write null contents to A at larger size (size of B)
Copy B to A
是否有可能使它使用特定的缓冲区或避免重复复制?
答案 0 :(得分:0)
使用glBufferData
设置缓冲区的大小后,该大小将变为不变。这就是为什么需要复制到另一个更大的缓冲区B
的原因。
好消息是您可以将缓冲区与其他目标重新绑定。这是您可以在缓冲区管理器中执行的操作(似乎您错误地将其称为“着色器”。着色器是GPU中的程序)。不需要第二份副本。
如果要保留以前的绑定, GL_COPY_READ_BUFFER
和GL_COPY_WRITE_BUFFER
目标很有用。这不是您的情况,因此副本更简单:
//The buffer must be bound before copying it
glBindBuffer(GL_ARRAY_BUFFER, oldBuf); //or GL_ELEMENT_ARRAY_BUFFER or whatever it was
//New buffer
glGenBuffers (1, &newBuf);
//GL_COPY_WRITE_BUFFER is needed because GL_ARRAY_BUFFER is in use by oldBuf
glBindBuffer (GL_COPY_WRITE_BUFFER, newBuf);
glBufferData (GL_COPY_WRITE_BUFFER, newSize, ...);
glCopyBufferSubData (GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);
现在完成复制,可以安全删除缓冲区oldBuf
。
还有两件事要做:
a) Tell the buffer-manager to use 'newBuf' insted of 'oldBuf'
b) Before using this new buffer, re-bind it to the target you need
glBindBuffer(GL_ARRAY_BUFFER, newBuf);
嗯,还有另一件事要做。当绑定VAO时,glVertexAttribPointer
建立了关联“属性-要读取的缓冲区”,它使用了oldBuf
缓冲区。但是现在您想要另一个缓冲区。因此,您必须再次绑定该VAO,绑定新缓冲区并使用glVertexAttribPointer。
更好的解决方案可能是具有较大的缓冲区,并且仅使用其中的一部分。假设您有一个用于一百万个顶点的VBO。 1M x 3浮点数x 4字节= 12M字节。这不是任何不是太老的GPU都无法处理的大小。
如果数据大小发生变化,但不超过1M个顶点,那么最简单的方法是使用glBufferSubData
并上传新数据,即使只是添加数据也是如此。没有新的缓冲区,没有副本,没有VAO状态更改。