Framebuffer Effects

One of the most straightforward things we can do with a framebuffer object is apply a post-process effect to a scene. This is much like applying a photographic filter to the entire scene. It entails two steps:

  1. Render the scene normally (using shaders, textures, etc) but to an off-screen framebuffer.
  2. Copy the framebuffer's color buffer to the screen but with a fragment shader manipulating the image in an interesting way.

The first step has been covered. The second proceeds as follows.

A post-process effect is rendered as a rectangle that exactly fits the screen, textured with the framebuffer color buffer. This produces a one-to-one mapping from the input rendering to the output image, while introducing an extra opportunity for fragment shading.

Screen-Filling Rectangle

To produce a piece of geometry that exactly fits the screen, we need not know the size or shape of the screen. Recall that the gl_Position varying in the vertex shader receives a position in clip coordinates, the position after the $M$, $V$, and $P$ matrices have been applied. In this coordinate system, the visible portion of the scene is known to extend from $-1$ to $+1$ along the $x$, $y$, and $z$ axes.

Thus, to produce a full-screen rectangle, define geometry that covers this volume, and do not apply any of the $M$, $V$, or $P$ transforms. Here is that geometry.

positions = [
    [ +1.0, +1.0, 0.0 ],
    [ -1.0, +1.0, 0.0 ],
    [ -1.0, -1.0, 0.0 ],
    [ +1.0, -1.0, 0.0 ],
texCoords = [
    [ 1.0, 1.0 ],
    [ 0.0, 1.0 ],
    [ 0.0, 0.0 ],
    [ 1.0, 0.0 ],
triangles = [
    [ 0, 1, 2 ],
    [ 0, 2, 3 ],

And here is an appropriate vertex shader. This shader receives no uniforms and does nothing but copy its attributes into varyings.

precision mediump float
attribute vec4 vertexPosition
attribute vec2 vertexTexCoord
varying vec2 fragmentTexCoord

function main()

This vertex shader works with a variety of fragment shaders, and the fragment shader is where the post-process effect is implemented.