使用 glMultiDrawArraysIndirect 和间接缓冲区时出错

Error using glMultiDrawArraysIndirect and indirect buffer

我有两个对象(A 和 B)要使用 glMultiDrawArraysIndirect() 渲染。每个对象都有一个 setupBuffers() 方法来创建和绑定一个 vao,然后创建和绑定间接缓冲区、实例化 ID 缓冲区、顶点缓冲区和纹理坐标缓冲区。 (使用 JOGL)

问题来了:如果我先调用对象A的setupBuffers()再调用B的setupBuffers(),那么只会绘制B;如果我在调用 A 中的 setupBuffers() 之前调用对象 B 的 setupBuffers(),则只会绘制 A。 (没有发现异常。)存储的数据应该都是正确的,因为我已经测试了它们。

对象 A:

protected void setupBuffers()
{
    gl.glGenVertexArrays(1, vaoBuff);
    gl.glBindVertexArray(vaoBuff.get(0));

    gl.glGenBuffers(4, vboBuff);

    //bind indirect buffer object
    gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
    gl.glBufferData(GL4.GL_DRAW_INDIRECT_BUFFER, instanceCount * 4 * Integer.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);

    //bind draw instance ID in the shader with a buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(1));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount * Integer.SIZE / 8, drawIndexBuff, GL4.GL_STATIC_DRAW);
    gl.glVertexAttribIPointer(d_idLoc, 1, GL4.GL_UNSIGNED_INT, 0, 0);
    gl.glVertexAttribDivisor(d_idLoc, 1);
    gl.glEnableVertexAttribArray(d_idLoc);

    //bind vertex data buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(2));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * vertBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);
    gl.glVertexAttribPointer(verPosLoc, 3, GL4.GL_FLOAT, false, 0, 0);
    gl.glEnableVertexAttribArray(verPosLoc);

    //bind texture coordinate data buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(3));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * texBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);
    gl.glVertexAttribPointer(tc_inLoc, 2, GL4.GL_FLOAT, false, 0, 0);
    gl.glEnableVertexAttribArray(tc_inLoc);
}

绘制方法:

gl.glBindVertexArray(vaoBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_TRIANGLE_STRIP, 0, instanceCount, 0);

对象 B:

(方法'setupBuffers()'和A中的很相似)

绘制方法:

gl.glBindVertexArray(vaoBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0);

有什么想法吗?

添加: 现在我找到了导致该问题的行:

gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));

这个用于绑定间接缓冲区的方法在对象A和B中都被调用了一次,导致了那个问题,但我不知道为什么。这是为什么?使用 OpenGL 是否一样(我使用的是 JOGL)?或者这是 JOGL 的错误?

终于修好了。 GL_DRAW_INDIRECT_BUFFER 绑定点不是顶点数组对象状态的一部分。它是全局上下文状态。因此,在从该缓冲区执行间接操作之前,我必须将其设置为我想从中提取的缓冲区(将上面的代码更改为):

gl.glBindVertexArray(vaoBuff.get(0)); 
gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0); 

然后它工作得很好。

您自己的回答中描述问题根本原因的部分很有道理。 GL_DRAW_INDIRECT_BUFFER 绑定确实不是 VAO 状态的一部分。规范证实了这一点。相应的状态 (DRAW_INDIRECT_BUFFER_BINDING) 列在标题为 "Vertex Array Data (not in Vertex Array objects)".

的 table 23.5 中

不过,您提出的解决方案对我来说并不理想。在每次绘制调用之前在间接缓冲区上调用 glBufferData() 将首先破坏将数据存储在缓冲区中的目的。这个想法是您可以重复使用数据,同时它保留在 GPU 可以有效访问的内存中。

您需要做的就是在每次绘制调用之前再次绑定 缓冲区。绘图的调用顺序如下所示:

gl.glBindVertexArray(vaoBuff.get(0)); 
gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0);