Ambient Term

In which you approximate the indirect light that reaches surfaces that do not otherwise see lights.

Find a chair and look underneath its seat. What color do you see? It's probably not pitch black. Suppose you rendered it using the lighting model that you've seen so far. The bottom of the seat would be pitch black if it didn't face a light source.

The light source in this renderer is positioned inside the torus, and the outside faces, whose normals point away from the light, are pitch black:

Even though the bottom of your chair doesn't face a light source, it still receives the light that bounces indirectly off of other surfaces in your environment. That's why it's not pitch black.

Tracing light as it bounces around a scene is hard. Many renderers make no attempt at illuminating surfaces with anything but direct rays of light. To give the illusion that light reaches surfaces indirectly, you add a minimum amount of albedo. This minimum amount is called the ambient term.

An ambient factor is sent as a uniform to this fragment shader, which applies it to the albedo to compute the ambient term:

uniform float ambientFactor;
// ...

void main() {
  // ...
  vec3 ambient = ambientFactor * albedo * diffuseColor;
  vec3 diffuse = (1.0 - ambientFactor) * litness * albedo * diffuseColor;
  vec3 rgb = ambient + diffuse;
  fragmentColor = vec4(rgb, 1.0);

In the renderer above, try changing the ambient factor to a different value in [0, 1]. As you approach 1, the scene loses contrast. This effect is called desaturation and is used to set a dour mood in games and movies.

The diffuse term is weighted by the complement of the ambient factor. This complementary weighting keeps the color intensites from exceeding 1.

Observe that the ambient term is not influenced by the normal or light direction. It is a crude hack.