我注意到我的程序中有一个奇怪的错误,当我在调用glVertexArrayVertexBuffer
. 在我的帧循环中,我通常为一个绘制调用使用一个 VAO,但有时我想将相同的 VAO 用于具有不同着色器的多个绘制调用。但这在我的实现中不起作用:
while(RUN){
updateBuffers();//updates VAO
drawThis();//binds and unbinds VAO
drawThat();//binds and unbinds VAO -> OpenGL Invalid Operation error at draw call
}
而这有效:
while(RUN){
updateBuffers();//updates VAO
drawThis();//binds and unbinds VAO
updateBuffers();//updates VAO
drawThat();//binds and unbinds VAO -> works
}
这也不起作用:
updateBuffers();
while(RUN){
drawThis();//OpenGL Invalid Operation error in second frame
}
但这会起作用
updateBuffers();
glBindVertexArray(VAO);
while(RUN){
drawThis();//only makes the draw call
}
glBindVertexArray(0);
...但这不是一个选项,因为我还想在我的帧循环中使用其他 VAO(并且我想保持灵活的顺序)。
那么这些函数在内部做什么呢?
这些draw
函数只需绑定一个 VAO 和一个着色器,进行一次绘制调用(通常glDrawElementsInstanced
),然后解除绑定着色器和 VAO。
该函数通常通过使用,和标志映射整个缓冲区的指针updateBuffers
写入缓冲区对象(用 初始化)。为了确保不会覆盖 GPU 仍在使用的任何数据,我总是写入缓冲区的不同分区。因此,在每次更新之前,我将写入偏移量增加上一次更新的大小(如果更新超过存储大小,则将其设置为 0)。glNamedBufferStorage
GL_MAP_WRITE_BIT
GL_MAP_PERSISTENT_BIT
GL_MAP_COHERENT_BIT
而且因为更新的数据应该对着色器可见,所以我也必须更新着色器绑定到的绑定点。我通过在每次更新时调用glBindBufferRange
统一缓冲区(由统一块使用)和glVertexArrayVertexBuffer
顶点缓冲区(用于顶点属性)来做到这一点,以使每个缓冲区的绑定偏移量从更新数据的位置开始。
这始终适用于统一缓冲区绑定(使用 更新偏移量glBindBufferRange
)但是当我更新 VAO 的顶点缓冲区的绑定(使用glVertexArrayVertexBuffer
)然后在glVertexArrayVertexBuffer
再次调用之前多次绑定和取消绑定该 VAO,我得到一个Invalid Operation
错误。
为什么会glVertexArrayVertexBuffer
导致 VAO 出现这样的行为?更新绑定到顶点缓冲区的 VAO 的偏移量的正确方法是什么?