布局位置 = n可以跳过 WebGL 中 drawBuffers 的索引吗?

问题描述

我正在我的图形引擎中处理 MRT。

一个有趣的点(并打算修复)我生成的片段着色器吐出来了:

layout(location = 0) out vec4 thing1;
layout(location = 2) out vec4 thing2;

应用程序端的 drawBuffers 调用如下:

gl.drawBuffers([gl.COLOR_ATTACHMENT0,gl.NONE,gl.COLOR_ATTACHMENT1]);

但是,我收到一个错误

WebGL: INVALID_OPERATION: drawBuffers: COLOR_ATTACHMENTi_EXT or NONE

很明显,这似乎是不允许的。从我从讨论它的维基百科文章中阅读的文档中:

https://www.khronos.org/opengl/wiki/Fragment_Shader

它指出指定的布局位置是指从 drawBuffers 调用指定的数组索引。所以,理论上我会认为这个着色器配置是有效的。

我的理解中遗漏了什么使这不起作用?

我主要要求理解而不是修复我的程序,当我完成“正确”且没有​​位置索引跳过时,我的生成器将更正索引。

更新:如下所述,您可以跳过着色器中的布局位置。我的问题是 drawBuffers 调用的格式不正确,其中索引中有 COLOR_ATTACHMENT1,其中 ONLY COLOR_ATTACHMENT2 有效。

解决方法

这是错误的

gl.drawBuffers([gl.COLOR_ATTACHMENT0,gl.NONE,gl.COLOR_ATTACHMENT1]);

i-th 个附件必须是 gl.NONEgl.COLOR_ATTACHMENTi

必须是这样

gl.drawBuffers([gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT2]);

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');

  const vs = `#version 300 es
  void main() {
    gl_Position = vec4(0,1);
    gl_PointSize = 100.0;
  }
  `;

  const fs = `#version 300 es
  precision highp float;
  layout(location = 0) out vec4 thing1;
  layout(location = 2) out vec4 thing2;
  void main () {
    thing1 = vec4(1,1);
    thing2 = vec4(0,1,1);
  }
  `;

  const prg = twgl.createProgram(gl,[vs,fs]);

  const fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER,fb);

  createTextureAndAttach(gl,gl.COLOR_ATTACHMENT0);
  createTextureAndAttach(gl,gl.COLOR_ATTACHMENT2);

  gl.drawBuffers([
    gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT2,]);

  const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (status !== gl.FRAMEBUFFER_COMPLETE) {
    console.error("can't render to this framebuffer combo");
    return;
  }

  gl.useProgram(prg);
  gl.viewport(0,1);
  gl.drawArrays(gl.POINTS,1);
  
  checkError();
  
  read(gl.COLOR_ATTACHMENT0);
  read(gl.COLOR_ATTACHMENT2);

  checkError();

  function checkError() {
    const err = gl.getError();
    if (err) {
      console.error(twgl.glEnumToString(gl,err));
    }
  }

  function read(attachmentPoint) {
    gl.readBuffer(attachmentPoint);
    const pixel = new Uint8Array(4);
    gl.readPixels(0,gl.RGBA,gl.UNSIGNED_BYTE,pixel);
    console.log(Array.from(pixel).join(','));
  }

  function createTextureAndAttach(gl,attachmentPoint) {
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,tex);
    gl.texImage2D(gl.TEXTURE_2D,gl.RGBA8,null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER,attachmentPoint,gl.TEXTURE_2D,tex,0);
  }

}

main();
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>

注意:对于 WebGL,引用 OpenGL 文档通常是错误的和/或具有误导性的。您需要为 WebGL2 引用 OpenGL 3.0 ES spec