1

我注意到我的程序中有一个奇怪的错误,当我在调用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)。glNamedBufferStorageGL_MAP_WRITE_BITGL_MAP_PERSISTENT_BITGL_MAP_COHERENT_BIT

而且因为更新的数据应该对着色器可见,所以我也必须更新着色器绑定到的绑定点。我通过在每次更新时调用glBindBufferRange统一缓冲区(由统一块使用)和glVertexArrayVertexBuffer顶点缓冲区(用于顶点属性)来做到这一点,以使每个缓冲区的绑定偏移量从更新数据的位置开始。

这始终适用于统一缓冲区绑定(使用 更新偏移量glBindBufferRange)但是当我更新 VAO 的顶点缓冲区的绑定(使用glVertexArrayVertexBuffer)然后在glVertexArrayVertexBuffer再次调用之前多次绑定和取消绑定该 VAO,我得到一个Invalid Operation错误。

为什么会glVertexArrayVertexBuffer导致 VAO 出现这样的行为?更新绑定到顶点缓冲区的 VAO 的偏移量的正确方法是什么?

4

0 回答 0