在WebGL2中使用drawBuffers时会遇到麻烦

Sky*_*yun 4 opengl-es webgl webgl2

我想将延迟渲染器和前向渲染器组合在一起.为了共享相同的深度缓冲区,我使用一个带有4个颜色附件的帧缓冲区对象,用于G缓冲区渲染的COLOR_ATTACHMENT0-2,用于延迟着色和前向渲染的COLOR_ATTACHMENT3,这里是pesudo代码:

//**Gbufffer part**
Bind G-Buffer FBO
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
draw the G buffer

//**Lighting part**
Bind Lighting buffer FBO

//**Shading part**
Bind G-Buffer FBO
gl.drawBuffers([gl.COLOR_ATTACHMENT3]);

//**Forward rendring part**
//Still use the G-Buffer FBO and COLOR_ATTACHMENT3
draw forward material
Run Code Online (Sandbox Code Playgroud)

使用这个时,我在firefox中遇到了一个错误:

错误:WebGL:drawBuffers:buffers[i]必须为NONE或COLOR_ATTACHMENTi.

在Chrome浏览器中,我得到了这个:

FrameBufferObject.ts:151的WebGL:INVALID_OPERATION:drawBuffers:COLOR_ATTACHMENTi_EXT或NONE

我的代码出了什么问题?这真让我迷惑...... THX.

gma*_*man 6

如果我没记错的话,你必须使用第一个缓冲区的颜色附件0,第二个颜色附件1,第三个颜色附件2等.

换句话说,这没关系

gl.drawBuffers([
  gl.COLOR_ATTACHMENT0,  // color attachment 0 to draw buffer 0
  gl.COLOR_ATTACHMENT1,  // color attachment 1 to draw buffer 1
  gl.COLOR_ATTACHMENT2,  // color attachment 2 to draw buffer 2
]);
Run Code Online (Sandbox Code Playgroud)

这也没关系

gl.drawBuffers([
  gl.COLOR_ATTACHMENT0,  // color attachment 0 to draw buffer 0
  gl.NONE,               // NONE to draw buffer 1
  gl.COLOR_ATTACHMENT2,  // color attachment 2 to draw buffer 2
]);
Run Code Online (Sandbox Code Playgroud)

这不是!!

gl.drawBuffers([
  gl.COLOR_ATTACHMENT0,  // color attachment 0 to draw buffer 0
  gl.COLOR_ATTACHMENT2,  // color attachment 2 to draw buffer 1 ERROR!
  gl.COLOR_ATTACHMENT1,  // color attachment 1 to draw buffer 2 ERROR!
]);
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下.

gl.drawBuffers([
   gl.COLOR_ATTACHMENT3,  // color attachment 3 to draw buffer 0 ERROR!
]);
Run Code Online (Sandbox Code Playgroud)

必须始终匹配0到0,1到1,2到2等.

如果你真的在做什么,你应该制作3个帧缓冲对象.一个带有前3个缓冲区,一个带有第4个缓冲区,另一个带有所有4个缓冲区.然后你会做类似的事情

gl.bindFramebuffer(gl.FRAMEBUFFER, threeAttachmentFB);
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);

.. draw stuff ..

gl.bindFramebuffer(gl.FRAMEBUFFER, oneAttachmentFB);
gl.drawBuffers([gl.COLOR_ATTACHMENT0]);

.. draw stuff ..

gl.bindFramebuffer(gl.FRAMEBUFFER, fourAttachmentFB);
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1,
                gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3]);

.. draw stuff ..
Run Code Online (Sandbox Code Playgroud)

在版本中,不保证各种组合工作.目前还不清楚WebGL2的限制是什么,但在WebGL1中只保证这些组合有效

  • 一种颜色附件(有或没有深度或深度)

    COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
    
    Run Code Online (Sandbox Code Playgroud)
  • 两种颜色的附件(有或没有深度或深度)

    COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
    
    Run Code Online (Sandbox Code Playgroud)
  • 三种颜色附件(带或不带深度或深度或深度)

    COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE
    
    Run Code Online (Sandbox Code Playgroud)
  • 四种颜色附件(带或不带深度或深度)

    COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE
    COLOR_ATTACHMENT3_WEBGL = RGBA/UNSIGNED_BYTE
    
    Run Code Online (Sandbox Code Playgroud)

根据GPU /驱动程序/浏览器/操作系统,所有其他组合可能有效,也可能无效


Pau*_*Jan 1

如果您的实际代码与您在此处发布的代码略有不同,我不会感到惊讶。

查看WebGLContext::DrawBuffers的Firefox 源代码https://dxr.mozilla.org/mozilla-central/source/dom/canvas/WebGLContextFramebufferOperations.cpp :

for (size_t i = 0; i < buffers.Length(); i++) {
    // "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
    //  bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
    //  BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
    // MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.

    // WEBGL_draw_buffers:
    // "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
    //  equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
    // This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
    // be larger than MaxColorAttachments.
    if (buffers[i] != LOCAL_GL_NONE &&
        buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
    {
        ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
                              funcName);
        return;
    }
}
Run Code Online (Sandbox Code Playgroud)

您的代码未通过该检查。也许你把顺序搞混了?

[编辑]正如 gman 指出的,您对绘制缓冲区的第二次调用gl.drawBuffers([gl.COLOR_ATTACHMENT3]);不符合此验证[/编辑]