代码之家  ›  专栏  ›  技术社区  ›  Oscar

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

  •  1
  • Oscar  · 技术社区  · 10 年前

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

    问题是:如果我在调用B中的setupBuffers()之前调用对象A的setupBuffer(),那么只会绘制B;如果我在调用A中的setupBuffers()之前调用对象B的setupBuffer(),那么将只绘制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的bug?

    2 回复  |  直到 10 年前
        1
  •  3
  •   Reto Koradi    10 年前

    你自己的答案中描述问题根源的部分很有意义。这个 GL_DRAW_INDIRECT_BUFFER 绑定确实不是VAO状态的一部分。这由规范确认。相应的状态( DRAW_INDIRECT_BUFFER_BINDING )列在标题为“顶点阵列数据(不在顶点阵列对象中)”的表23.5中。

    不过,我觉得你提出的解决方案并不理想。使命感 glBufferData() 在每个draw调用之前对间接缓冲区的访问将首先破坏将数据存储在缓冲区中的目的。其想法是,您可以重复使用数据,而数据保留在GPU可以高效访问的内存中。

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

    gl.glBindVertexArray(vaoBuff.get(0)); 
    gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
    gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0);
    
        2
  •  2
  •   Oscar    10 年前

    终于修好了。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); 
    

    然后它工作得很好。