You may need to read the article about textures before this one.

A framebuffer can be thought of as a collection of attachments, which are buffers with purposes. They can be used to render to textures and renderbuffers, which are objects that contain images.

Renderbuffers differ from textures in that they support more formats but can't be sampled. Renderbuffers also support multisampling, which is a process for reducing aliasing, which is an effect that reduces the quality of images that are under-sampled. This means that multisampling is a form of antialiasing. As the name implies, renderbuffers are optimized for use as render targets.

A WebGLFramebuffer can be created with createFramebuffer. For example:

const framebuffer = gl.createFramebuffer();

Like textures and buffers, framebuffers must be bound to a binding point with bindFramebuffer in order to be accessed by functions. Framebuffers have three binding points:

  • DRAW_FRAMEBUFFER, which causes functions that modify attachments to target the attachments of this framebuffer.
  • READ_FRAMEBUFFER, which causes functions that read from attachments to target the attachments of this framebuffer.
  • FRAMEBUFFER, which causes functions that read from or modify attachments to target the attachments of this framebuffer.

There is a default framebuffer that is rasterized to the canvas. When no framebuffer is explicitly attached to any of the framebuffer binding points, the default framebuffer is used.

Attachments can be added using framebufferTexture2D, framebufferRenderbuffer, and framebufferTextureLayer. Every attachment in a framebuffer must have the same dimensions. For example:

gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

In order to use the default framebuffer, simply attach null to the desired binding point.

Rendering to Textures

Rather than writing to the default framebuffer and having that data rasterized to the rendering context, it is possible to write to a custom framebuffer to store that data in textures or renderbuffers.

Note that framebuffers don't have all of the attachments that the default one does by default. For example, in order to use depth testing in a framebuffer, it needs to be given a depth attachment.

The next article is about lighting.