Let there be Light… Vertex Light

All those transformation are of little use on their own, after all, without light there is nothing to be seen. Light and its interaction with objects is a very complex matter, over time some very clever people came up with approximate lighting models that produce a visual result that is good enough to fool us into thinking that the result produced is kind of correct (note that mathematically correct lighting does not equal realistic lighting).

The basic lighting model as implemented by DirectX uses the following formula:

Global Illumination = Ambient Light + Diffuse Light + Specular Light + Emissive Light

As you can see there are 4 elements that make up the final illumination of a vertex, all 4 will be discussed individually below.

Ambient Light

Ambient Light is constant lighting. It is constant in all directions and it colours all pixels of an object the same. It is fast to calculate but leaves objects looking flat and unrealistic. It’s basically a minimum base light amount that influences every object. Usually there is only one single ambient light in a scene, but it is possible to create additional ones (although there is little use to define them separately since all global ambient lights can be merged into a single one). The formula used to determine the influence of the global light on an object is as follows:

Ambient Lighting = Ca*[Ga + sum(Lai)]

Ca is the materials ambient colour. Each object has a material assigned to it, this material will influence how the light interacts with the object (e.g. metal, plastic, cloth… all respond differently to a light source). Ga is the global lights colour. The sum(Lai) is there to support additional global lights, their colours are added together but this is rarely used. The usual Ambient Lighting formula is reduced to a multiplication of the materials ambient colour with the scenes ambient light colour (Ca * Ga). This formula matches the basic light behaviour seen in the real world. If we have a pure red ball and we shine a bright white light at it we’ll see red light emitted by the ball. In our formula we would get:

Ambient Lighting =
(R,G,B) =
Object Colour * Light Colour =
(1.0, 0.0, 0.0) * (1.0, 1.0, 1.0) =
(1.0, 0.0, 0.0) =
Red

Note that the multiplication is done per colour component, so the red channel is multiplied with red channel, blue with blue and green with green.

On the other hand if you shine a blue light on a red ball you will see nothing (a red colour means that all other light is absorbed by the material, so blue light is absorbed by the ball and no light is emitted). This matches the behaviour of the formula:

Ambient Lighting =
(R,G,B) =
(1.0, 0.0, 0.0) * (0.0, 0.0, 1.0) =
(0.0, 0.0, 0.0) =
Black

The problem with this lighting model is that the whole object responds in the exact same way, meaning that if the result is red it will be red for the whole object with no gradients or variation at all. Obviously this is not very realistic which is why the model has to be extended with other factors.

At the end of the lighting section you will find a java applet that allows you to experiment with different elements of the Global Illumination formula. Try enabling only the Ambient Lighting factor of the formula and notice the flat unrealistic result. Quite often the Ambient Lighting factor is only used for initial scene building to make sure that all objects in the scene are visible; at a later time the ambient light is disabled or set to a very low, hardly visible, value.

Diffuse Light

Diffuse Lighting depends on both the light direction and the object surface normal. It varies across the surface of an object as a result of the changing light direction and the changing surface normal vector. It takes longer to calculate diffuse lighting because it changes for each object vertex; however the benefit of using it is that it shades objects and gives them a strong three-dimensional (3-D) illusion.

We immediately notice the introduction of a new element: the surface normal. Surface normals are supplied per vertex. So we do not just use the vertex position (as described in the section about transformations) but for 3d graphics you also need a normal. The normal is a vector that is perpendicular to the surface of the object. The normal is provided by 3d modelling packages and stored per vertex (this can also be supplied per pixel but this will be discussed in a potentially upcoming article about pixel shaders). Diffuse lighting is described by the following equation.

Diffuse Lighting = sum[Cd*Ld*(N.Ldir)]

You can ignore the sum, this is just there to indicate that this model can be used to sum over multiple light sources. The C and L factors are pretty similar to the C and G factors of the ambient light. C is the objects diffuse colour and L is the lights diffuse colour, they are multiplied to get correct basic lighting behaviour as illustrated in the ambient lighting section (red object, blue light equals no light – red objects, white light equals red object – etc…). The new element in this formula is N “dot” Ldir. This “dot” is a dot product which is defined as follows:

N.L = N * L * cos (alpha)
With "alpha" the angle between the N and L vectors.

The dot product has a behaviour which is typical for a light: if you shine a light directly on a surface you’ll see a very bright spot of light, if you shine your light almost parallel with the surface you’ll hardly have any light reflecting from the surface. This is exactly the behaviour of the dot product of N, the normal of the surface, and L the light direction. If you shine directly on the surface the angle between N and L is close to zero which results in cosine value close to 1, since the cosine(0)=1.0. On the other hand if your light direction is parallel to the surface the angle between the surface normal and the light direction will be close to 90 degrees, which means the result of the dot product between N and L will be close to zero, since the cosine(90)=0.0.

Again you can use the java applet at the end of this section to play with the Diffuse Lighting factors and the surface normals/light direction.

This model can be extended to include an attenuation factor meaning that the light influence will be decreased related to the distance between the light source and the vertex position. This can be modelled by an extra multiplication of the Diffuse Lighting Term with an attenuation factor. For a spot light yet another term has to be added which creates the typical spot light shape, more details about this term can be found in the literature