Framebuffers and Shadows

Framebuffers, Rendered Textures and Shadow Mapping

A framebuffer object redirects drawing from the canvas into textures that the next pass can sample: mirrors, post-processing (Post-Processing and Particles), deferred lighting (Deferred Rendering) and shadow maps. The seventeenth part of webgl-helper.js builds one:

webgl-helper.js, seventeenth part: an offscreen framebuffer with color and depth texturesJavaScript
// Section 3.13: an offscreen framebuffer: an optional RGBA8 color texture and a 24-bit depth
// texture set to compare for sampler2DShadow; throws unless the framebuffer is complete
GLH.framebuffer = function (gl, width, height, { color = true } = {}) {
  const fbo = gl.createFramebuffer(), T = gl.TEXTURE_2D, F = gl.FRAMEBUFFER;
  const texture = (format, attachment) => {
    const t = gl.createTexture();
    gl.bindTexture(T, t);
    gl.texStorage2D(T, 1, format, width, height);            // one level, fixed format
    gl.texParameteri(T, gl.TEXTURE_MIN_FILTER, gl.LINEAR);   // no mipmaps
    gl.texParameteri(T, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(T, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.framebufferTexture2D(F, attachment, T, t, 0);
    return t;
  };
  gl.bindFramebuffer(F, fbo);
  const colorTexture = color ? texture(gl.RGBA8, gl.COLOR_ATTACHMENT0) : null;
  if (!color) gl.drawBuffers([gl.NONE]);                     // depth only
  const depth = texture(gl.DEPTH_COMPONENT24, gl.DEPTH_ATTACHMENT);
  gl.texParameteri(T, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  const status = gl.checkFramebufferStatus(F);
  gl.bindFramebuffer(F, null);
  if (status !== gl.FRAMEBUFFER_COMPLETE) throw new Error(`Incomplete framebuffer: ${status}`);
  return { fbo, color: colorTexture, depth, width, height };
};

Subsections