Webgl-添加DEPTH_STENCIL渲染缓冲区可防止渲染到立方体贴图帧缓冲区

时间:2018-07-29 23:40:45

标签: javascript opengl-es webgl opengl-es-2.0

我们正在Webgl 1中工作,并尝试使用模具渲染到立方体贴图。单独渲染到立方体贴图效果很好。当我们添加DEPTH_STENCIL渲染缓冲区时,它将停止写入立方体贴图,并且不会发出错误。

  • 使用普通的TEXTURE_2D而不是TEXTURE_CUBE_MAP不会发生这种情况。
  • 深度/模板/剪刀测试已禁用。
  • 打到framebufferRenderbuffer的电话中断了它。
  • 将渲染缓冲区切换为只是模板或只是深度都具有相同的效果。
  • 将渲染缓冲区切换为颜色缓冲区会使它再次工作。

这是一种最低限度的娱乐活动。如您所见,我们将获得控制台输出,其中前三个调用的值正确,而最后一个调用的值为零。

为什么会发生这种情况,而使渲染缓冲区与多维数据集映射一起使用,我们还缺少什么呢?

const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl");

console.log(TEST(false, false));
console.log(TEST(false, true));
console.log(TEST(true, false));
console.log(TEST(true, true));

function TEST(useCubemap, useBuffer) {
  const size = 512;
  const textureType = useCubemap ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;

  // SETUP THE PROGRAM
  {
    const program = gl.createProgram();
    const vertShader = gl.createShader(gl.VERTEX_SHADER);
    const fragShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(vertShader, `
            attribute vec2 a_position;
            
            void main() {           
                gl_Position = vec4(a_position, 0.2, 1.0);
            }
        `);
    gl.compileShader(vertShader);
    gl.attachShader(program, vertShader);

    gl.shaderSource(fragShader, `
            void main() {
                gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4);
            }
        `);
    gl.compileShader(fragShader);
    gl.attachShader(program, fragShader);

    gl.linkProgram(program);
    gl.useProgram(program);
  }

  // SETUP THE QUAD
  {
    const posBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
    gl.enableVertexAttribArray(0);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, +1, -1, -1, +1, +1, +1, -1]), gl.STATIC_DRAW);
  }

  // SETUP THE FRAMEBUFFER
  {
    const fb = gl.createFramebuffer();
    const targetTexture = gl.createTexture();

    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

    gl.bindTexture(textureType, targetTexture);
    gl.texParameteri(textureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(textureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(textureType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(textureType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    // SWITCH TEXTURE TYPE
    if (textureType === gl.TEXTURE_2D) {
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0);
    } else {
      for (let i = 0; i < 6; i++) gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, targetTexture, 0);
    }
  }

  // SETUP THE RENDER BUFFER
  {
    const rb = gl.createRenderbuffer();

    gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size);

    // TAKING THIS OUT MAKES IT WORK
    if (useBuffer) gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb);
  }


  // DISABLE THE OBVIOUS CULPRITS
  gl.disable(gl.DEPTH_TEST);
  gl.disable(gl.STENCIL_TEST);
  gl.disable(gl.SCISSOR_TEST);

  // DO A RENDERYFUCK
  gl.viewport(0, 0, size, size);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

  // GET THE OUTFUCK
  const pixels = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  return pixels;
}

1 个答案:

答案 0 :(得分:0)

对我有用。在您发布的代码中,所有4个调用的值都相同。您正在使用什么OS / GPU /驱动程序?如果您使用的是Chrome,是否可以粘贴about:gpu的内容?

这听起来像是驱动程序中的错误。这可能是WebGL规范中的一个错误。

OpenGL ES规范不需要任何帧缓冲区附件的组合才能工作(零,zilch,nada)。 WebGL规范需要3种组合才能起作用。来自the spec, section 6.8

  

以下所有帧缓冲对象附件的组合,当所有附件都是完整的帧缓冲附件,非零且具有相同的宽度和高度时,必须导致帧缓冲完整:

     
      
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理
  •   
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理+ DEPTH_ATTACHMENT = DEPTH_COMPONENT16渲染缓冲区
  •   
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理+ DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL渲染缓冲区
  •   

但是请查看WebGL一致性测试only TEXTURE_2D is tested

因此,首先,这表明您的驱动程序/ GPU不支持与多维数据集映射结合使用。通过调用gl.checkFramebufferStatus进行测试。如果未返回gl.FRAMEBUFFER_COMPLETE,则您的设置不支持渲染到具有深度模具附件的立方体贴图。

const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl");

TEST("TEXTURE_2D", "DEPTH_COMPONENT16");
TEST("TEXTURE_2D", "DEPTH_STENCIL");
TEST("TEXTURE_CUBE_MAP", "DEPTH_COMPONENT16");
TEST("TEXTURE_CUBE_MAP", "DEPTH_STENCIL");

function TEST(target, depthBufferFormat) {
  const size = 16;
  const textureType = gl[target];

  // SETUP THE FRAMEBUFFER
  {
    const fb = gl.createFramebuffer();
    const targetTexture = gl.createTexture();

    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

    gl.bindTexture(textureType, targetTexture);
    gl.texParameteri(textureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(textureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(textureType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(textureType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    // SWITCH TEXTURE TYPE
    if (textureType === gl.TEXTURE_2D) {
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0);
    } else {
      for (let i = 0; i < 6; i++) gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, targetTexture, 0);
    }
  }

  // SETUP THE RENDER BUFFER
  {
    const rb = gl.createRenderbuffer();
    const format = gl[depthBufferFormat];

    gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
    gl.renderbufferStorage(gl.RENDERBUFFER, format, size, size);

    // TAKING THIS OUT MAKES IT WORK
    const attachmentPoint = depthBufferFormat === "DEPTH_COMPONENT16"
      ? gl.DEPTH_ATTACHMENT
      : gl.DEPTH_STENCIL_ATTACHMENT;
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachmentPoint, gl.RENDERBUFFER, rb);
  }

  const success =  gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
  console.log(target, depthBufferFormat, success ? "PASS" : "**FAIL**");
}

您需要模具还是仅深度缓冲器? this sample run是否适合您?它使用的是DEPTH_COMPONENT16附件。