使用 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);
我有两个对象(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)".
不过,您提出的解决方案对我来说并不理想。在每次绘制调用之前在间接缓冲区上调用 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);