Framebuffer Attachments In WebGL Producing Unexpected Results

155 views Asked by At

I have a problem with framebuffer attachments. Basically, my framebuffers always worked fine, but for my last project I needed to initialize them with some color values. So I created an attachment with a texture containing the color values I wanted. This leads to some really unexplainable (to me) behaviour, you can see in the code below that I create a framebuffer with an attachment, then have one shader which renders a very simple shape to the framebuffer and another shader which reads out the values with some noise added to the readout position.

The weird thing is that

  • The readouts seem to be weirdly all over the place, if you delete the framebuffer attachment in the source (just comment out the lines so that an empty object remains in the array) you will see how it is meant to look like (notice the noisy edges, so writing to and reading from framebuffer works as expected).

    Instead it looks like this:

  • Also changing the values of the attachment texture changes the result, which is weird as I never read from the framebuffer before writing to it. It seems as if the readouts return the initial color value most of the time (in this case gray).

  • If you remove the noise term or attach a constant noise term (independent of position), the readouts seem to work just fine.

(function main() {
  const dim = [512, 512];
  twgl.setDefaults({ attribPrefix: "a_" });
  const gl = twgl.getContext(document.querySelector("canvas"));
  gl.canvas.width = dim[0];
  gl.canvas.height = dim[1];
  const bfi = twgl.primitives.createXYQuadBufferInfo(gl);
  const pgi = {
    cross: twgl.createProgramInfo(gl, ["vs", "fs_cross"]),
    noise: twgl.createProgramInfo(gl, ["vs", "fs_noise"])
  };
  const fbi = twgl.createFramebufferInfo(
    gl,
    [
      {
        attachment: twgl.createTexture(gl, {
          src: Array(dim[0] * dim[1])
            .fill([128, 128, 0, 0])
            .flat()
        })
      }
    ],
    ...dim
  );
  (function frame() {
    twgl.bindFramebufferInfo(gl, fbi);
    gl.useProgram(pgi.cross.program);
    twgl.setUniforms(pgi.cross, {
      u_resolution: dim
    });
    twgl.setBuffersAndAttributes(gl, pgi.cross, bfi);
    twgl.drawBufferInfo(gl, bfi);
    twgl.bindFramebufferInfo(gl, null);
    gl.useProgram(pgi.noise.program);
    twgl.setUniforms(pgi.noise, {
      u_framebuffer: fbi.attachments[0],
      u_pi: Math.PI,
      u_resolution: dim,
      u_seed: Array(24).fill().map(Math.random)
    });
    twgl.setBuffersAndAttributes(gl, pgi.noise, bfi);
    twgl.drawBufferInfo(gl, bfi);
    window.requestAnimationFrame(frame);
  })();
})();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vs" type="x-shader/x-vertex">
  attribute vec4 a_position;
  attribute vec2 a_texcoord;

  varying vec2 v_texcoord;

  void main() {
    v_texcoord = a_texcoord;
    gl_Position = a_position;
  }
</script>
<script id="fs_cross" type="x-shader/x-fragment">
  precision highp float;

  varying vec2 v_texcoord;
  
  uniform vec2 u_resolution;

  void main() {
    if(sign(v_texcoord.x - 0.5) * sign(v_texcoord.y - 0.5) < 0.0) {
        gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
      } else {
         gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
      }
  }
</script>
<script id="fs_noise" type="x-shader/x-fragment">
  precision highp float;

  varying vec2 v_texcoord;

  uniform sampler2D u_framebuffer;
  uniform float u_pi;
  uniform vec2 u_resolution;
  uniform vec2 u_seed[12];
  
  vec2 normal(vec2 uv) {
    float scl = sqrt(-2.0 * log(uv.x));
    float ang = 2.0 * u_pi * uv.y;
    return vec2(scl * cos(ang), scl * sin(ang));
  }
  
  vec2 noisySample(sampler2D tex, vec2 coord) {
    vec2 sum = vec2(0.0, 0.0);
    vec2 uni = vec2(0.0, 0.0);
    for(int i = 0; i < 6; i++) {
      uni = fract(uni + vec2(
        dot(gl_FragCoord.xy + sin(gl_FragCoord.xy), u_seed[i]),
        dot(gl_FragCoord.xy + sin(gl_FragCoord.xy), u_seed[i + 6])
      ));
      vec2 nc = coord + normal(uni) / u_resolution;
      sum += texture2D(u_framebuffer, nc).rg;
    }
    return sum / 6.0;
  }
  
  void main() {
    vec2 tmp = noisySample(u_framebuffer, v_texcoord);
    gl_FragColor = vec4(tmp, 0.5, 1.0);
  }
</script>
<canvas></canvas>

0

There are 0 answers