Framebuffer

A Framebuffer is a WebGL container object that the application can use for "off screen" rendering. A framebuffer does not itself contain any image data but can optionally contain attachments (one or more color buffers, a depth buffer and a stencil buffer) that store data. Attachments must be in the form of Textures and Renderbuffers.

For additional information, see OpenGL Wiki Framebuffer and Framebuffer Object

Functionality

luma.gl adds

Usage

Creating a framebuffer with default color and depth attachments

const framebuffer = new Framebuffer(gl, {
  width: window.innerWidth,
  height: window.innerHeight,
  color: true,
  depth: true
});

Attaching textures and renderbuffers

framebuffer.attach({
  [GL.DEPTH_ATTACHMENT]: new Renderbuffer(gl, {...}),
  [GL.COLOR_ATTACHMENT0]: new Texture(gl, {...}),
  [GL.COLOR_ATTACHMENT1]: [new TextureCube(gl, {...}), GL.TEXTURE_CUBE_MAP_POSITIVE_X],
  [GL.COLOR_ATTACHMENT2]: [new TextureArray2D(gl, {...}), 0],
  [GL.COLOR_ATTACHMENT3]: [new TextureArray2D(gl, {...}), 1],
  [GL.COLOR_ATTACHMENT4]: [new Texture3D(gl, {..., depth: 8}), 2]
});
framebuffer.checkStatus(); // optional

Resizing a framebuffer to the size of a window. Resizes all attachements with a single framebuffer.resize() call

// Note: this resizes (and possibly clears) all attachments
framebuffer.resize({width: window.innerWidth, height: window.innerHeight});

Clearing a framebuffer

framebuffer.clear();
framebuffer.clear({color: [0, 0, 0, 0], depth: 1, stencil: 0});

Specifying a framebuffer for rendering in each render calls

const offScreenBuffer = new Framebuffer();
program1.draw({
  framebuffer: offScreenBuffer,
  parameters: {}
});
model.draw({
  framebuffer: null, // the default drawing buffer
  parameters: {}
});

Binding a framebuffer for multiple render calls

const framebuffer1 = ...;
const framebuffer2 = ...;
withParameters(gl, {framebuffer: framebuffer1}, () => {
  // Any draw call that doesn't specify a framebuffer will now draw into framebuffer1
  program1.draw({...}); // -> framebuffer1
  program2.draw({...}); // -> framebuffer1
  // Explicit specification of framebuffer overrides (for that call only)
  program2.draw({framebuffer: framebuffer1, ...); // -> framebuffer2
  program2.draw({...}); // -> framebuffer1
});
// framebuffer1 is not longer bound

Reading, copying or blitting data from a Framebuffer attachment.

For reading data into CPU memory check readPixelsToArray

For reading into a Buffer object (GPU memory), doesn't result in CPU and GPU sync, check readPixelsToBuffer

For reading into a Texture object (GPU memory), doesn't result in CPU and GPU sync, check copyToTexture

For blitting between framebuffers (WebGL 2), check blit

Using Multiple Render Targets

Specify which framebuffer attachments the fragment shader will be writing to when assigning to gl_FragData[]

framebuffer.update({
  drawBuffers: [
    GL.COLOR_ATTACHMENT0, // gl_FragData[0]
    GL.COLOR_ATTACHMENT1, // gl_FragData[1]
    GL.COLOR_ATTACHMENT2, // gl_FragData[2]
    GL.COLOR_ATTACHMENT3 // gl_FragData[3]
  ]
});

Writing to multiple framebuffer attachments in GLSL fragment shader

#extension GL_EXT_draw_buffers : require
precision highp float;
void main(void) {
  gl_FragData[0] = vec4(0.25);
  gl_FragData[1] = vec4(0.5);
  gl_FragData[2] = vec4(0.75);
  gl_FragData[3] = vec4(1.0);
}

Clearing a specific draw buffer in a framebuffer (WebGL 2)

framebuffer.clear({
  [GL.COLOR]: [0, 0, 1, 1], // Blue
  [GL.COLOR]: new Float32Array([0, 0, 0, 0]), // Black/transparent
  [GL.DEPTH_BUFFER]: 1, // Infinity
  [GL.STENCIL_BUFFER]: 0 // no stencil
});

framebuffer.clear({
  [GL.DEPTH_STENCIL_BUFFER]: [1, 0] // Infinity, no stencil
});

Methods

constructor(gl : WebGLRenderingContext, props : Object)

Creates a new framebuffer, optionally creating and attaching Texture and Renderbuffer attachments.

new Framebuffer(gl, {
  id,
  width,
  height,
  attachments,
  color,
  depth,
  stencil
})
  • id= - (String) - An optional name (id) of the buffer.
  • width=1 - (number) The width of the framebuffer.
  • height=1 - (number) The height of the framebuffer.
  • attachments={} - (Object, optional) - a map of Textures and/or Renderbuffers, keyed be "attachment points" (see below).
  • color - shortcut to the attachment in GL.COLOR_ATTACHMENT0
  • depth - shortcut to the attachment in GL.DEPTH_ATTACHMENT
  • stencil - shortcut to the attachment in GL.STENCIL_ATTACHMENT

The luma.gl Framebuffer constructor enables the creation of a framebuffer with all the proper attachments in a single step and also the resize method makes it easy to efficiently resize a all the attachments of a Framebuffer with a single method.

When no attachments are provided during Framebuffer object creation, new resources are created and used as default attachments for enabled targets (color and depth). For color, new Texture2D object is created with no mipmaps and following filtering parameters are set.

Texture parameterValue
GL.TEXTURE_MIN_FILTERGL.LINEAR
GL.TEXTURE_MAG_FILTERGL.LINEAR
GL.TEXTURE_WRAP_SGL.CLAMP_TO_EDGE
GL.TEXTURE_WRAP_TGL.CLAMP_TO_EDGE

For depth, new Renderbuffer object is created with GL.DEPTH_COMPONENT16 format.

delete()

Destroys the underlying WebGL object. When destroying Framebuffers it can be important to consider that a Framebuffer can manage other objects that may also need to be destroyed.

initialize(props : Object) : Framebuffer

Initializes the Framebuffer to match the supplied parameters. Unattaches any existing attachments, attaches any supplied attachments. All new attachments will be resized if they are not already at the right size.

Framebuffer.initialize({width, height})

  • width=1 - (number) The width of the framebuffer.
  • height=1 - (number) The height of the framebuffer.
  • attachments={} - (Object, optional) - a map of Textures and/or Renderbuffers, keyed be "attachment points" (see below).
  • color - shortcut to the attachment in GL.COLOR_ATTACHMENT0
  • depth - shortcut to the attachment in GL.DEPTH_ATTACHMENT
  • stencil - shortcut to the attachment in GL.STENCIL_ATTACHMENT

update(options: Object) : Framebuffer

Updates Framebuffers attachments using provided Texture and Renderbuffer objects. Optionally sets read and draw buffers when using WebGL 2 context.

  • attachments - a map of attachments.
  • readBuffer - Buffer to be set as read buffer (WebGL 2)
  • drawBuffers - Buffers to be set as draw buffers (WebGL 2)
  • clearAttachments - When set to true, will first unattach all binding points, default value is false.
  • resizeAttachments - When set to true, all attachments will be re-sized to Framebuffers size, default value is true.

resize({width: Number, height: Number}) : Framebuffer

Framebuffer.resize({width, height})

Resizes all the Framebuffer's current attachments to the new width and height by calling resize on those attachments.

  • width (GLint) - width of Framebuffer in pixels
  • height (GLint) - height of Framebuffer in pixels

Returns itself to enable chaining

  • Each attachment's resize method checks if width or height have actually changed before reinitializing their data store, so calling resize multiple times with the same width and height does not trigger multiple resizes.
  • If a resize happens, resize erases the current content of the attachment in question.

WebGL References see initialize.

attach(attachments : Object, options: Object) : Framebuffer

Used to attach or unattach Textures and Renderbuffers from the Framebuffers various attachment points.

Framebuffer.attach(attachments)

  • attachments - a map of attachments.
  • options
    • clearAttachments - When set to true, will first unattach all binding points, default value is false.
    • resizeAttachments - When set to true, all attachments will be re-sized to Framebuffers size, default value is true.

Returns itself to enable chaining.

The key of an attachment must be a valid attachment point, see below.

The following values can be provided for each attachment

  • null - unattaches any current binding
  • Renderbuffer - attaches the Renderbuffer
  • Texture - attaches the Texture
  • [Texture, layer=0 (Number), mipmapLevel=0 (Number)] - attaches the specific layer from the Texture (WebGL 2)

This function makes calls to the following WebGL APIs:

gl.framebufferRenderbuffer, gl.bindFramebuffer, gl.framebufferTexture2D, gl.bindFramebuffer, gl.framebufferTextureLayer, gl.bindFramebuffer (This is for WebGL 2 only)

checkStatus() : Framebuffer

Check that the framebuffer contains a valid combination of attachments

gl.checkFramebufferStatus, gl.bindFramebuffer

clear(options: Object) : Framebuffer

Clears the contents (pixels) of the framebuffer attachments.

  • options.color (Boolean or Array) - clears all active color buffers (any selected drawBuffers) with either the provided color or the default color.
  • options.depth
  • options.stencil
  • options.drawBuffers=[] - An array of color values, with indices matching the buffers selected by drawBuffers argument.

Notes:

  • The scissor box bounds the cleared region.
  • The pixel ownership test, the scissor test, dithering, and the buffer writemasks affect the operation of clear.
  • Alpha function, blend function, logical operation, stenciling, texture mapping, and depth-buffering are ignored by clear.

invalidate (WebGL 2)

Signals to the GL that it need not preserve the pixels of a specified region of the framebuffer (by default all pixels of the specified framebuffer attachments are invalidated).

Parameters

  • attachments - list of attachments to invalidate

This function makes calls to the following WebGL APIs:

gl.invalidateFramebuffer, gl.invalidateSubFramebuffer, gl.bindFramebuffer

Limits

  • GL.MAX_COLOR_ATTACHMENTS - The maximum number of color attachments supported. Can be 0 in WebGL 1.
  • GL.MAX_DRAW_BUFFERS - The maximum number of draw buffers supported. Can be 0 in WebGL 1, which means that gl_FragData[] is not available in shaders.

It is possible that you can have a certain number of attachments, but you can't draw to all of them at the same time.

Framebuffer Parameters

Framebuffer Attachment Points

Attachment PointDescription
GL.COLOR_ATTACHMENT0Attaches the texture to one of the framebuffer's color buffers
GL.COLOR_ATTACHMENT{1-15}Attaches the texture to one of the framebuffer's color buffers
GL.DEPTH_ATTACHMENTAttaches the texture to the framebuffer's depth buffer
GL.STENCIL_ATTACHMENTAttaches the texture to the framebuffer's stencil buffer
GL.DEPTH_STENCIL_ATTACHMENTCombined depth and stencil buffer
  • The attachment point GL.BACK refersn to the default framebuffer's back buffer.

  • The set of available attachments is larger in WebGL 2, and also the extensions WEBGL_draw_buffers and WEBGL_depth_texture provide additional attachments that match or exceed the WebGL 2 set.

Framebuffer Attachment Values

The following values can be provided for each attachment point

  • null - unattaches any current binding
  • Renderbuffer - attaches the Renderbuffer
  • Texture2D - attaches at mipmapLevel 0 of the supplied Texture2D.
  • [Texture2D, 0, mipmapLevel] - attaches the specified mipmapLevel from the supplied Texture2D (WebGL 2), or cubemap face. The second element in the array must be 0. In WebGL 1, mipmapLevel must be 0.
  • [TextureCube, face (Number), mipmapLevel=0 (Number)] - attaches the specifed cubemap face from the Texture, at the specified mipmap level. In WebGL 1, mipmapLevel must be 0.
  • [Texture2DArray, layer (Number), mipmapLevel=0 (Number)] - attaches the specifed layer from the Texture2DArray, at the specified mipmap level.
  • [Texture3D, layer (Number), mipmapLevel=0 (Number)] - attaches the specifed layer from the Texture3D, at the specified mipmap level.

Remarks

  • In the raw WebGL API, creating a set of properly configured and matching textures and renderbuffers can require a lot of careful coding and boilerplate.
  • This is further complicated by many capabilities (such as support for multiple color buffers and various image formats) depending on WebGL extensions or WebGL versions.