1

我正在尝试借助 drawBuffers 编写简单的 webgl 多通道程序。我创建了 2 个 drawBuffer 纹理并在 fragmentShaderPass1 中为它们分配颜色。Texture1 应该是绿色的,Texture2 应该是棕色的。然后我将这些纹理作为制服传递给 fragmentShaderPass2,它使用 Texture1 的颜色来渲染矩形。问题是矩形总是黑色而不是绿色!我在这里做错了什么?

    // STAGE 1
    let fragmentShaderPass1 = `
        #extension GL_EXT_draw_buffers : require
        precision highp float;
        precision highp int;
        precision highp sampler2D;

        void main( void )
        {
            gl_FragData[0] = vec4(.2, .8, .0, 1);  // green
            gl_FragData[1] = vec4(.6, .5, .4, .3);  // brown
        }
    `;
    let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);

    let firstStageFrameBuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);

    gl.useProgram(pass1_prog);

    for (let i = 0; i < 2; i++) 
    {
        let tex = gl.createTexture();
        textures.push(tex);

        gl.bindTexture(gl.TEXTURE_2D, tex);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

        // attach texture to framebuffer
        gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
    }

    gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
    gl.viewport(0, 0, _this.canvas.width, _this.canvas.height); 

    ext.drawBuffersWEBGL([
        ext.COLOR_ATTACHMENT0_WEBGL,
        ext.COLOR_ATTACHMENT1_WEBGL
    ]);

    gl.drawArrays(gl.POINTS, 0, 1); 



    // STAGE 2
    let fragmentShaderPass2 = `
        precision highp float;
        precision highp int;
        precision highp sampler2D;

        uniform sampler2D inColor0;
        uniform sampler2D inColor1;

        void main( void )
        {
            gl_FragColor = texture2D(inColor0, vec2(0.5));
        }
    `;
    let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);

    gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    gl.useProgram(pass2_prog);
    gl.viewport(0, 0, canvas.width, canvas.height); 
    gl.clearColor(1.0, 1.0, 1.0, 1.0);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, textures[0]);
    gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);

    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, textures[1]); 
    gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);

    gl.drawArrays(gl.POINTS, 0, 1);
4

1 回答 1

3

The code you posted above does not make your textures renderable and gets this error in the JavaScript console

RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture filtering (maybe)?

They are not renderable because they have no mips but are set to use mips (the default). They are also probably not power of 2 dimensions though you didn't show the size of the canvas but just guessing it's not a power of 2.

Making them renderable

  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

makes them render

const canvas = document.querySelector('canvas');
const _this = {canvas};
const textures = [];
const gl = _this.canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_draw_buffers');
if (!ext) { alert('need WEBGL_draw_buffers'); }
const globals = {
  vertexShader: `
    void main() {
      gl_Position = vec4(0, 0, 0, 1);
      gl_PointSize = 100.0;
    }
  `,
}
// STAGE 1
let fragmentShaderPass1 = `
  #extension GL_EXT_draw_buffers : require
  precision highp float;
  precision highp int;
  precision highp sampler2D;

  void main( void )
  {
      gl_FragData[0] = vec4(.2, .8, .0, 1);  // green
      gl_FragData[1] = vec4(.6, .5, .4, 1);  // brown
  }
`;
let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);

let firstStageFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);

gl.useProgram(pass1_prog);

for (let i = 0; i < 2; i++) {
  let tex = gl.createTexture();
  textures.push(tex);

  gl.bindTexture(gl.TEXTURE_2D, tex);

  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

  // attach texture to framebuffer
  gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
}

gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);

ext.drawBuffersWEBGL([
  ext.COLOR_ATTACHMENT0_WEBGL,
  ext.COLOR_ATTACHMENT1_WEBGL
]);

gl.drawArrays(gl.POINTS, 0, 1);



// STAGE 2
let fragmentShaderPass2 = `
        precision highp float;
        precision highp int;
        precision highp sampler2D;

        uniform sampler2D inColor0;
        uniform sampler2D inColor1;

        void main( void )
        {
            gl_FragColor = texture2D(inColor0, vec2(0.5));
        }
    `;
let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

gl.useProgram(pass2_prog);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);

gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);

gl.drawArrays(gl.POINTS, 0, 1);


// ---
function createProgram(gl, vSrc, fSrc) {
  return twgl.createProgram(gl, [vSrc, fSrc]);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>

Note I changed the "brown" color from vec4(.6, .5, .4, .3) to vec4(.6, .5, .4, 1). vec4(.6, .5, .4, .3) is an invalid color for the canvas unless you do more math on output or set the canvas to not except premultiplied alpha color. Your output shader didn't do any extra math and you didn't show your code for setting up the canvas. The default is the browser expects you to put premultiplied color values in the canvas. vec4(.6, .5, .4, .3) is not premultiplied alpha because if it was r, g, and b could not be > a.

于 2020-01-13T02:58:36.627 回答