Chapter 10 Lighting
We see objects only by virtue of
the light they reflect into our eyes. Additionally, the way in which the light
is reflected from objects gives us important information about their
three-dimensional shape. One of the first things painters learn is the power of
light and shade to make pictures look realistic. Similarly, in the quest for
realism in computer graphics, we must consider the effects of illumination on
the objects we model.
Ultimately, we draw pictures by displaying
collections of pixels with the appropriate colours and intensities. We need
methods for determining exactly what these values should be.
When
rendering a scene, however, we must consider many factors, including:
- The geometrical arrangement of the light, the object and the viewer.
Experience tells us that at certain angles, we see reflected glare from the
light source and this is not the same colour as the object. So the reflectance
spectrum is geometry dependent. Also, surfaces directly facing a light source
will appear brighter than surfaces inclined at angles.
- The geometry of the illuminant - is it a point or an area, how far away is
it from each object.
- The physical nature of the surface is it shiny, matte, coloured,
patterned, transparent, smooth or bumpy?
- The effect of other surfaces in the scene.
- The medium through which the light passes is it smoky, foggy,
underwater or raining for example.
During the process of rendering we
must consider the following distinctions:
- The illumination of objects by light sources (of whatever origin)
- The reflection of light from objects
- The shading of objects (for display on a graphics screen)
Concerning the first point, we have to model the geometry of the light
source, both its physical dimensions as well as its intensity distribution,
together with its spectral distribution, i.e. what colour it is. For the second
point, we need to consider how incident light is modified by a particular
surface, especially the colour of the light. We do this by defining a light
reflection model and there are many ways to do this. The third point is
necessary since in most cases we only compute the light leaving a few specific
points on a surface and use various interpolation techniques to find the light
leaving the surface at other locations.
There are two ways of computing
illumination effects: local illumination models and global illumination
models.
Local models consider each object in a scene in isolation,
without reference to other objects in the scene. Scenes rendered in this way
therefore look artificial and contain no shadows or reflection effects. Because
they are simple, and the time to render one object does not depend on the
overall scene complexity, local models are fast. Also, this simplicity allows
local models to be implemented in hardware on graphics workstations which gives
further speed benefits. Local models are a suitable choice when the purpose of
rendering is to give basic information about the 3D shape of an object. An
example would be the display of a molecule made of thousands of coloured
spheres. All that is needed is an indication of shape, and it is important that
rendering is fast so that the molecule may be rotated and examined in real
time.
In contrast, global models consider the relationships between
objects in a scene and can produce more realistic images incorporating shadows,
reflection, and refraction. Global models are used when a realistic portrayal of
some aspect of physical reality is desired, and when this realism is more
important than the speed of rendering. In general, the more realistic the
lighting model, the greater the computational cost.
10.1 Local illumination models
10.1.1 Light sources
There are two basic kinds of
illumination source: emitters and reflectors.
Anything that gives off
light, such as the sun, a light bulb, or a fluorescent tube is an emitter.
Characteristics of emitters include the overall intensity of the light and its
spectrum, which determines the colour of the light. We can further classify
light emitters into two types. When the light source is sufficiently far away
from the surface, we can consider it to be an infinite point source, and all the
light rays effectively strike a surface at the same angle. But, when the light
source is near to the surface rays will arrive at different points on the
surface at different angles, as illustrated in Figure 10.1.
Figure 10.1:
Light source
characteristics.
We may also wish to take the geometry of the light source
into account. In particular, we can classify emitter geometry into two types:
point sources and area sources. With area light sources, a single point on an
object can be illuminated from several different angles from the same light
source, as shown in Figure 10.1.
As
any physical light source must take up a certain amount of space, all light
sources are area sources! However, considering some small area sources to be
point sources gives a significant reduction in complexity and is an acceptable
compromise in many instances.
Turn a spotlight on in one corner of a
room, and parts of the room not directly lit by the spotlight will still be
illuminated by light reflected off walls, ceiling, carpets, people, and so on.
So light reflectors are all the other objects in a scene that are not emitters.
Although clearly an emitter can also reflect light, the amount reflected is so
small in comparison with the emitted light that the reflected portion is
frequently ignored. The colour of a light reflector depends on the spectrum of
the incident light and the reflectance spectrum of the reflective
object.
In addition to these direct reflections, there will be indirect
ones - reflections of reflections, and so on. These multiple reflections in a
scene produce an overall illumination called ambient light, which is discussed
further below.
10.1.2 Types of reflection
We need to develop a model to
enable us to calculate how much light is reflected from different objects in a
scene. There are two ways in which reflection occurs:
- Diffuse reflection - light is scattered uniformly from the surface of the
object (Figure 10.2a),
and the surface looks dull. The surface is effectively absorbing the
illumination and re-radiating it only at preferred wavelengths. For example, a
green object looks green when illuminated with white light because it absorbs
all wavelengths except green, which it reflects.
- Specular reflection - a high proportion of the incident light is reflected
over a fairly narrow range of angles, and the object looks shiny (Figure 10.2b).
To a first approximation at least, the colour of the surface does not affect
the colour of the specularly reflected light.
In practice, many
materials exhibit both of these effects to different degrees, and the total
reflection is of the kind shown in Figure 10.2c.
[Diffuse]

[Specular]

[Diffuse and
Specular]
Figure 10.2:
Diffuse, specular
and combined reflections.
10.1.3 Light source geometry
Consider a single light source,
modelled as a point infinitely distant from the object being lit. Clearly, the
amount of light reflected from a surface will depend on its orientation to the
source of light. We describe this quantitatively with two vectors, shown in
Figure 10.3.
Figure 10.3:
Describing a
surface and its orientation.
- The normal vector N - this is a vector normal (at right angles to)
the surface. For example, for a surface lying in the xz-plane, its normal
vector will be parallel to the y-axis.
- The light vector L - this points towards the light source.
Since only the directions of these vectors are required to orient the
surface with respect to the light source, it is convenient (and conventional) to
use unit vectors, so we will assume that N and L have been
normalized. The angle q between N and L
is called the angle of incidence.
10.1.4 Ambient illumination
Multiple reflections of light in
a scene together produce a uniform illumination called ambient light. Actually,
this is an over-simplification. For many purposes, we can assume a constant
level of ambient light in a scene. In reality, however, ambient light effects
are much more subtle.
The intensity I of diffuse reflection at a
point on an object illuminated only by ambient light of intensity
Ia is:
where ka is called the diffuse reflection coefficient and is
a constant in the range 0 to 1. Its value varies from surface to surface
according to the surface properties of the material in question. A highly
reflective surface will have ka
approaching 1, and a surface that absorbs most of the light falling onto it will
have ka near 0.
We could
use Equation 10.1
to compute the illumination of an object, but each point on the object would be
assigned the same intensity. This is not realistic, as we know that in practice
the shading of objects is not constant. If this were the case we would not be
able to perceive the 'three-dimensionality' of the object. We achieve a more
realistic effect by considering localized light sources (such as points sources)
and the orientation of surfaces with respect to light sources.
10.1.5 Diffuse reflection
The amount of light reflected by
the surface depends on the amount received from the source of illumination,
which in turn depends on the intensity of the illumination, and the orientation
of the surface with respect to it. If N and L are in the same
direction, (where q =0° ) reflection will be at a maximum. If they are
at right angles (where q =90° ), reflection will be at a minimum. The
precise relationship is expressed by Lambert's Cosine Law, which states that the
effective intensity Ie incident on
a surface when illuminated by a light of intensity Ip incident at q is:
Ie=Ipcos
(q )
Expressing the diffuse reflectivity of
the surface by kd , the amount of
light I diffusely reflected by a surface illuminated by a light of
intensity Ip incident at q is:
Since
N and L are normalized, their dot product gives the angle between
them:
cos (q )=N· L
so we can rewrite Equation 10.2
entirely in terms of vectors as:I
We
can now combine the effects of ambient illumination and a point light source to
give the illumination model:
I=ambient term+diffuse
term
or,
Notice
that in Equation 10.4
the intensity of light reflected from a surface is independent of the distance
of the point source from the object. This means if two objects have parallel
surfaces, and seen from the viewpoint the surfaces overlap, they will be shaded
the same and will merge into one. Also, note that neither the colour of the
illuminating light nor that of the surface is taken into account in this
model.
10.1.6 The position of the light source
This can be modelled
by observing that the intensity of light falls off in inverse proportion to the
square of the distance the light has travelled. If light from a source of
intensity Ip travels a distance
d , its effective intensity is Ip/4p d2 . We can incorporate this into Equation 10.4
to give:
(Note
the ambient term kaIa is
not dependent on distance, since by definition the source is everywhere).
However this model does not give realistic results in practice. In typical
modelling applications, we will either have a point light source at infinity, so
that d is infinite, or we have a light source at a finite position.
Either way, we will typically have values of d that differ little between
objects, and this, in conjunction with the finite values available to assign to
pixels, may mean that the effect of the d2
term in the model may be too great. Experiments have shown that a better model
is to use a linear approximation for fall-off of intensity with distance, using:
where
d is the actual distance from the light source to the object, and
d0 is a constant determined
experimentally. (There are lot of 'constants determined experimentally' in
computer graphics.)
10.1.7 Specular reflection
An object modelled using only
diffuse reflection appears dull and matte. However many real surfaces are shiny.
At certain viewing angles, a shiny surface reflects a high proportion of the
incident light - this is called specular reflection. When this happens you see a
bright spot on the object the same colour as the illuminating
light.
First we consider a perfect reflector such as a highly-polished
mirror. In Figure 10.4,
the unit vector R represents the direction of specular reflection.
V is the direction from which the surface is being viewed. For a perfect
reflector, the angle of incidence equals the angle of reflection, so the
specular reflection can only be observed when V and R coincide, such that f =0°
.
Figure 10.4:
The four reference
vectors.
Real materials, however, behave less exactly. Light arriving
at an angle of incidence of q is reflected in a range
of angles centered on q , where the intensity is at a
maximum. The intensity of the specular reflection falls off rapidly as the angle
f between the direction of maximum ideal reflection R,
and the viewing direction V, increases. We need to somehow incorporate this
effect into our illumination model.
10.1.7.1 The Phong model
Phong developed an empirically
based model where the intensity of specular reflection is proportional to cos
nf . Figure 10.5
graphs cos nf for
-p /2£ f £ p /2 .
We use n to represent the surface properties, and is typically in the
range 1 to 200. For a perfect reflector, n=¥ ;
for a very poor specular reflector, like foam, n=1 .
Figure 10.5:
The behaviour of
cos
nf
.
For real materials, the amount of light specularly reflected
also depends on the angle of incidence q . In general,
the intensity of the specular reflection increases as the angle of incidence
increases. Exactly how the two are related depends on individual surface
properties, and we represent this with the specular reflection function
W(q ) which has a value in the range 0 to 1. The
precise behaviour of W(q ) will vary from
surface to surface.Many materials show little variation, and W(q ) is often replaced by a constant value ks selected experimentally. This constant,
ks , is called the specular
reflection coefficient.
We can now incorporate specular reflection into
our illumination model of Equation 10.5,
by adding the specular reflection component to the diffuse and ambient
reflections:
I=ambient term+diffuse term+specular
term
or,
| I=kaIa+ |
|
[ |
kd(N· L)+kscos nf |
] |
(10.6) |
Since R
and V are normalized, and we can rewrite Equation 2-6 entirely in terms of
vectors:
| I=kaIa+ |
|
[ |
kd(N· L)+ks(R· V)n |
] |
(10.7) |
10.1.8 Multiple light sources
Extending Equation 10.7
to include more than one source of illumination is straightforward. Each source
will cause diffuse and specular reflection at the surface, so we need to sum
these effects. If there are m different point sources, our model becomes:
| I=ambient term |
+ |
|
diffuse term |
i+ |
|
specular termi |
This summation,
however, can cause problems with overflow in the value of I, although the
problem can also occur with a single light source. For display purposes we
require the range of I to be limited, usually 0 to 1 in normalized form. There
are a number of ways to deal with overflow. First we could avoid the situation
arising in the first place by adjusting the reflection parameters or the
relative light sources strengths. If we decide this is not such a good idea then
adjusting the computed value of I is necessary. In this case we can
either
- adjust the value locally by, for example, clamping the value to the
required range, or
- adjust the value globally by considering the full range of intensities
calculated for the image and scaling everything at the same time so that no
values are out of range.
The second method is generally preferred
which avoids limit errors leading to Mach banding in the image.
10.1.9 Colour
So far we have mainly assumed a monochromatic
light source, and have ignored the fact that objects are coloured. We express
colour using a colour model, which gives us a way of assigning numerical values
to colours. A common simple model is the Red-Green-Blue (RGB) model, where a
colour is represented by a mixture of the three primary colours red, green and
blue corresponding to the colours of the monitor phosphors.
To consider
the effect of coloured illumination and coloured objects, we must apply our
illumination model to each component of the colour model we are using. For
example, if we are using the RGB colour model, we would treat each of the red,
green and blue components of the colour separately.
We can take the
surface (diffuse) colour of objects into consideration by expressing the diffuse
reflection coefficient as a colour dependent parameter ( kdR , kdG
, kdB ). We also have colour
components for the illumination; the red component of Ip is IpR
, and so on. So, for the red component our model becomes:
| IR=kaRIaR+ |
|
[ |
kdR(N· L)+ks(R· V)n |
] |
and similarly for green and
blue. We are assuming that the specular highlight will be the same colour as the
light source, hence ks is not
colour dependent. Once we have the three intensities IR , IG
and IB , and each component is
within the display range, we can use these to directly drive the RGB monitor to
display the required colour. Out of range values are treated, in ways similar to
those mentioned before, by clamping or global scaling. We could also locally
scale the colour by dividing each component by the value of the largest
component, a method which preserves the hue and saturation of the colour but
modifies its lightness.
Although using the RGB colour model often
provides reasonable results, it is a gross over-simplification of the
interactions between light and objects. For proper results, it is necessary to
apply the illumination model with many more than three samples across the
spectrum. Instead of restricting ourselves to a three component colour model, a
more general form of the illumination model may be written:
| I |
|
=k |
|
I |
|
+ |
|
é ë |
k |
|
(N·
L)+ks(R· V)n |
ù û |
where any terms
which are wavelength-dependent are indicated with the subscript l . But how do we use these spectral samples to specify an
RGB triplet, which we must have to be able to display the colour on a graphics
screen? The straightforward way of doing this is to convert the samples to the
CIE XYZ colour space and then to the monitor RGB space, which requires knowledge
of the chromaticities of the monitor phosphors.
Although this spectral
sampling technique is physically more correct, we must remember that the
reflection models discussed thus far are mainly based on empirical observation:
they are constructed such that the results look reasonable.
So in general
it would seem inappropriate to use such a method. However, when we come to
discuss global models of light reflection we will see that these models are more
physically based and would benefit from a more considered use of spectral
sampling. Unfortunately, while this is true, it is still the custom of the
majority of practitioners in the field to use the RGB colour model in their
rendering systems.
10.1.10 Summary
We have derived a simple local illumination
model that takes into account the following:
- Direct diffuse reflections from point sources.
- Direct specular reflections from point sources.
Not taken into
account are:
- Area light sources
- Indirect reflections:
- Specular to specular
- Specular to diffuse
- Diffuse to specular
- Diffuse to diffuse
Instead, indirect diffuse reflections
are modelled as ambient light. Our model can cope with polygonal geometries,
interpolating the surface normals to simulate the appearance of a curved
surface. Wavelength dependencies are modelled by taking three wavelength
samples, one each in the red, green and blue areas of the spectrum, and mapping
the intensities directly to the drive signals for a colour monitor.
10.2 Lighting in OpenGL
When you look at a physical surface,
your eye's perception of the colour depends on the distribution of photon
energies that arrive and trigger your cone cells. Those photons come from a
light source or combination of sources, some of which are absorbed and some of
which are reflected by the surface. In addition, different surfaces may have
very different properties some are shiny, and preferentially reflect light in
certain directions, while others scatter incoming light equally in all
directions. Most surfaces are somewhere in between.
OpenGL approximates
light and lighting as if light can be broken into red, green, and blue
components. Thus, the colour of light sources is characterized by the amount of
red, green, and blue light they emit, and the material of surfaces is
characterized by the percentage of the incoming red, green, and blue components
that are reflected in various directions. The OpenGL lighting equations are just
an approximation, but one that works fairly well and can be computed relatively
quickly.
In the OpenGL lighting model, the light in a scene comes from
several light sources that can individually be turned on and off. Some light
comes from a particular direction or position, and some light is generally
scattered about the scene. For example, when you turn on a light bulb in a room,
most of the light comes from the bulb, but some light comes after bouncing off
one, two, three, or more walls. This bounced light (called ambient) is assumed
to be so scattered that there is no way to tell its original direction, but it
disappears if a particular light source is turned off. Finally, there might be a
general ambient light in the scene that comes from no particular source, as if
it had been scattered so many times that its original source is impossible to
determine.
In the OpenGL model, the light sources have an effect only
when there are surfaces that absorb and reflect light. Each surface is assumed
to be composed of a material with various properties. A material might emit its
own light (like headlights on an automobile), it might scatter some incoming
light in all directions, and it might reflect some portion of the incoming light
in a preferential direction like a mirror or shiny surface. The OpenGL lighting
model considers the lighting to be divided into four independent components:
emitted, ambient, diffuse, and specular. All four components are computed
independently, and then added together.
10.2.1 Emitted, Ambient, Diffuse, and Specular Light
Emitted light is the simplest it originates from an object and is
unaffected by any light sources.
The ambient component is the light from
that source that's been scattered so much by the environment that its direction
is impossible to determine it seems to come from all directions. Backlighting in
a room has a large ambient component, since most of the light that reaches your
eye has bounced off many surfaces first. When ambient light strikes a surface,
it's scattered equally in all directions.
Diffuse light comes from one
direction, so it's brighter if it comes squarely down on a surface than if it
barely glances off the surface. Once it hits a surface, however, it's scattered
equally in all directions, so it appears equally bright, no matter where the eye
is located. Any light coming from a particular position or direction probably
has a diffuse component.
Finally, specular light comes from a particular
direction, and it tends to bounce off the surface in a preferred direction. A
well-collimated laser beam bouncing off a high-quality mirror produces almost
100 percent specular reflection. Shiny metal or plastic has a high specular
component, and chalk or carpet has almost none. You can think of specularity as
shininess.
Although a light source delivers a single distribution of
frequencies, the ambient, diffuse, and specular components might be different.
For example, if you have a white light in a room with red walls, the scattered
light tends to be red, although the light directly striking objects is white.
OpenGL allows you to set the red, green, and blue values for each component of
light independently.
10.2.2 Material Colours
The OpenGL lighting model makes the
approximation that a material's colour depends on the percentages of the
incoming red, green, and blue light it reflects. For example, a perfectly red
ball reflects all the incoming red light and absorbs all the green and blue
light that strikes it. If you view such a ball in white light (composed of equal
amounts of red, green, and blue light), all the red is reflected, and you see a
red ball. If the ball is viewed in pure red light, it also appears to be red.
If, however, the red ball is viewed in pure green light, it appears black (all
the green is absorbed, and there's no incoming red, so no light is reflected).
Like lights, materials have different ambient, diffuse, and specular colours,
which determine the ambient, diffuse, and specular reflectances of the material.
A material's ambient reflectance is combined with the ambient component
of each incoming light source, the diffuse reflectance with the light's diffuse
component, and similarly for the specular reflectance and component. Ambient and
diffuse reflectances define the colour of the material and are typically similar
if not identical. Specular reflectance is usually white or gray, so that
specular highlights end up being the colour of the light source's specular
intensity. If you think of a white light shining on a shiny red plastic sphere,
most of the sphere appears red, but the shiny highlight is white.
10.2.3 RGB Values for Lights and Materials
The colour
components specified for lights mean something different than for materials. For
a light, the numbers correspond to a percentage of full intensity for each
colour. If the R, G, and B values for a light's colour are all 1.0, the light is
the brightest possible white. If the values are 0.5, the colour is still white,
but only at half intensity, so it appears gray. If R=G=1 and B=0 (full red and
green with no blue), the light appears yellow.
For materials, the
numbers correspond to the reflected proportions of those colours. So if R=1,
G=0.5, and B=0 for a material, that material reflects all the incoming red
light, half the incoming green, and none of the incoming blue light. In other
words, if an OpenGL light has components (Lr,Lg,Lb) ,
and a material has corresponding components (Mr,Mg,Mb) ,
then, ignoring all other reflectivity effects, the light that arrives at the eye
is given by (Lr× Mr,Lg×
Rg,Mb× Mb)
.
Similarly, if you have two lights, which send (R1,G1,B1) and
(R2,G2,B2) to the eye,
OpenGL adds the components, giving (R1+R2,G1+G2,B1+B2) . If any of the
sums are greater than 1 (corresponding to a colour brighter than the equipment
can display), the component is clamped to 1.
10.2.4 Using Lighting in OpenGL
These are the steps required
to add lighting to your scene:
- Define normal vectors for each vertex of all the objects. These normals
determine the orientation of the object relative to the light sources.
- Create, select, and position one or more light sources.
- Create and select a lighting model, which defines the level of global
ambient light and the effective location of the viewpoint (for the purposes of
lighting calculations).
- Define material properties for the objects in the scene.
10.2.4.1 Creating Light Sources
Light sources have a number
of properties, such as colour, position, and direction. The command used to
specify all properties of lights is glLight; it takes three arguments:
to identify the light whose property is being specified, the property, and the
desired value for that property. Defaults values for lights in OpenGL are given
in Table 10.1.
| Parameter Name |
Default Value |
Meaning |
| GL_AMBIENT |
(0.0, 0.0, 0.0, 1.0) |
ambient RGBA intensity of light |
| GL_DIFFUSE |
(1.0, 1.0, 1.0, 1.0) or |
diffuse RGBA intensity of light |
| |
(0.0, 0.0, 0.0, 1.0) |
|
| GL_SPECULAR |
(1.0, 1.0, 1.0, 1.0) |
specular RGBA intensity of light |
| GL_POSITION |
(0.0, 0.0, 1.0, 0.0) |
(x, y, z, w) position of light |
| GL_SPOT_DIRECTION |
(0.0, 0.0, -1.0) |
(x, y, z) direction of spotlight |
| GL_SPOT_EXPONENT |
0.0 |
spotlight exponent |
| GL_SPOT_CUTOFF |
180.0 |
spotlight cutoff angle |
| GL_CONSTANT_ATTENUATION |
1.0 |
constant attenuation factor |
| GL_LINEAR_ATTENUATION |
0.0 |
linear attenuation factor |
| GL_QUADRATIC_ATTENUATION |
0.0 |
quadratic attenuation
factor |
Table 10.1:
Default Values for
OpenGL lights.
Remember to turn on each light with
glEnable.
The colours across the face of a smooth-shaded polygon
are determined by the colours calculated for the vertices. Because of this, you
probably want to avoid using large polygons with local lights if you locate the
light near the middle of the polygon, the vertices might be too far away to
receive much light, so the whole polygon will look darker than you intended. To
avoid this problem, break up the large polygon into smaller ones.
For
real-world lights, the intensity of light decreases as distance from the light
increases. Since a directional light is infinitely far away, it doesn't make
sense to attenuate its intensity over distance, so attenuation is disabled for a
directional light. However, you might want to attenuate the light from a
positional light. OpenGL attenuates a light source by multiplying the
contribution of that source by an attenuation factor.
You can have a
positional light source act as a spotlight that is, by restricting the shape of
the light it emits to a cone. To create a spotlight, you need to determine the
spread of the cone of light you desire. (Remember that since spotlights are
positional lights, you also have to locate them where you want them. Again, note
that nothing prevents you from creating a directional spotlight, but it probably
won't give you the result you want.) To specify the angle between the axis of
the cone and a ray along the edge of the cone, use the GL_SPOT_CUTOFF parameter. You also need to specify a
spotlight's direction, which determines the axis of the cone of light. A
spotlight's direction is transformed by the modelview matrix just as though it
were a normal vector, and the result is stored in eye coordinates.
You
can have at least eight lights in your scene (possibly more, depending on your
OpenGL implementation). Since OpenGL needs to perform calculations to determine
how much light each vertex receives from each light source, increasing the
number of lights adversely affects performance. The constants used to refer to
the eight lights are GL_LIGHT0, GL_LIGHT1, GL_LIGHT2,
GL_LIGHT3, and so on.
OpenGL treats the
position and direction of a light source just as it treats the position of a
geometric primitive. In other words, a light source is subject to the same
matrix transformations as a primitive. More specifically, when glLight
is called to specify the position or the direction of a light source, the
position or direction is transformed by the current modelview matrix and stored
in eye coordinates. This means you can manipulate a light source's position or
direction by changing the contents of the modelview matrix stack.
10.2.4.2 Selecting a Lighting Model
OpenGL's notion of a
lighting model has three components:
- The global ambient light intensity.
- Whether the viewpoint position is local to the scene or whether it should
be considered to be an infinite distance away.
- Whether lighting calculations should be performed differently for both the
front and back faces of objects.
There can be ambient light that's not
from any particular source. To specify the RGBA intensity of such global ambient
light, use the GL_LIGHT_MODEL_AMBIENT parameter
as shown in Code Example 17.
Code Example
*
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
The location of the viewpoint affects the calculations for highlights
produced by specular reflectance. More specifically, the intensity of the
highlight at a particular vertex depends on the normal at that vertex, the
direction from the vertex to the light source, and the direction from the vertex
to the viewpoint. With an infinite viewpoint, the direction between it and any
vertex in the scene remains constant. A local viewpoint tends to yield more
realistic results, but since the direction has to be calculated for each vertex,
overall performance is decreased with a local viewpoint. By default, an infinite
viewpoint is assumed. A local viewpoint can be enabled with
glLightModeli(LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE).
Lighting
calculations are performed for all polygons, whether they're front-facing or
back-facing. Since you usually set up lighting conditions with the front-facing
polygons in mind, however, the back-facing ones typically aren't correctly
illuminated. If only the front faces are ever seen it doesn't matter what the
back-facing polygons look like. If the inside surface would be visible, however,
you might want to have the inside surface be fully lit according to the lighting
conditions you've defined; you might also want to supply a different material
description for the back faces. When you turn on two-sided lighting, as follows:
glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE).
OpenGL reverses
the surface normals for back-facing polygons; typically, this means that the
surface normals of visible back- and front-facing polygons face the viewer,
rather than pointing away. As a result, all polygons are illuminated correctly.
With OpenGL, you need to explicitly enable (or disable) lighting. If
lighting isn't enabled, the current colour is simply mapped onto the current
vertex, and no calculations concerning normals, light sources, the lighting
model, and material properties are performed. Enable lighting with:
glEnable(GL_LIGHTING).
10.2.4.3 Defining Material Properties
Most of the material
properties are conceptually similar to ones you've already used to create light
sources. The mechanism for setting them is similar, except that the command used
is called glMaterial. The default material values are shown in Table 10.2.
| Parameter Name |
Default Value |
Meaning |
| GL_AMBIENT |
(0.2, 0.2, 0.2, 1.0) |
ambient colour of material |
| GL_DIFFUSE |
(0.8, 0.8, 0.8, 1.0) |
diffuse colour of material |
| GL_AMBIENT_AND_DIFFUSE |
|
ambient and diffuse colour of material |
| GL_SPECULAR |
(0.0, 0.0, 0.0, 1.0) |
specular colour of material |
| GL_SHININESS |
0.0 |
specular exponent |
| GL_EMISSION |
(0.0, 0.0, 0.0, 1.0) |
emissive colour of
material |
Table 10.2:
Default Values
for OpenGL materials.
The material properties can be applied separately to the
different faces of the polygon using GL_FRONT,
GL_BACK, or GL_FRONT_AND_BACK.
The GL_DIFFUSE and GL_AMBIENT parameters affect the colour of the diffuse
and ambient light reflected by an object. Diffuse reflectance plays the most
important role in determining what you perceive the colour of an object to be.
It's affected by the colour of the incident diffuse light and the angle of the
incident light relative to the normal direction. (It's most intense where the
incident light falls perpendicular to the surface.) The position of the
viewpoint doesn't affect diffuse reflectance at all.
Ambient reflectance
affects the overall colour of the object. Because diffuse reflectance is
brightest where an object is directly illuminated, ambient reflectance is most
noticeable where an object receives no direct illumination. An object's total
ambient reflectance is affected by the global ambient light and ambient light
from individual light sources. Like diffuse reflectance, ambient reflectance
isn't affected by the position of the viewpoint. For real-world objects, diffuse
and ambient reflectance are normally the same colour.
Specular reflection
from an object produces highlights. Unlike ambient and diffuse reflection, the
amount of specular reflection seen by a viewer does depend on the location of
the viewpoint it's brightest along the direct angle of reflection.
By
specifying an RGBA colour for GL_EMISSION, you
can make an object appear to be giving off light of that colour. Since most
real-world objects (except lights) don't emit light, you'll probably use this
feature mostly to simulate lamps and other light sources in a scene.A
A
technique for minimizing performance costs associated with changing material
properties is to use glColorMaterial. This causes the material property
(or properties) specified by mode of the specified material face (or faces)
specified by face to track the value of the current colour at all times. A
change to the current colour (using glColor) immediately updates the
specified material properties. The face parameter can be GL_FRONT, GL_BACK, or
GL_FRONT_AND_BACK (the default). The mode
parameter can be GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE (the default), GL_SPECULAR, or GL_EMISSION.
10.2.5 Lighting Example
Code Example 18
shows an example of the manipulation of the lighting parameters in OpenGL. Two
lights are created in fixed positions: one fixed in the center of the planes
with green ambient colour, and a red diffuse component. The diffuse component is
rapidly attenuated by the quadratic attenuation factor provided. The second
light is a blue spotlight, with red specular component positioned away from the
origin.
Note that the planes which rotate through these lights are built
of many smaller polygons. This is necessary, since lighting calculations only
occur at vertices.
An example of the output produced is shown in Figure
10.6.
Figure 10.6:
Behaviour of
lighting example.
Code Example
*
/* lights.cc */
...
void drawPlanes (int detail)
{
double delta = (2.0 / (double) detail);
double y;
double x;
for (y = -1.0; y < 1.0; y += delta)
{
for (x = -1.0; x < 1.0; x += delta)
{
glBegin (GL_QUADS);
glNormal3f (0.0, 0.0, 1.0);
glVertex3f (x, y, 0.0);
glVertex3f (x + delta, y, 0.0);
glVertex3f (x + delta, y + delta, 0.0);
glVertex3f (x, y + delta, 0.0);
glNormal3f (0.0, 1.0, 0.0);
glVertex3f (x, 0.0, y);
glVertex3f (x + delta, 0.0, y);
glVertex3f (x + delta, 0.0, y + delta);
glVertex3f (x, 0.0, y + delta);
glNormal3f (1.0, 0.0, 0.0);
glVertex3f (0.0, x, y);
glVertex3f (0.0, x + delta, y);
glVertex3f (0.0, x + delta, y + delta);
glVertex3f (0.0, x, y + delta);
glEnd ();
}
}
}
void paintGL ()
{
...
GLfloat spot_ambient[] = { 0.0, 0.0, 0.3, 1.0 }; /* rather greenish */
GLfloat spot_specular [] = { 0.9, 0.0, 0.0, 1.0 }; /* rather reddish */
GLfloat spot_position [] = { -0.5, 0.3, 0.5, 1.0 };
GLfloat spot_direction [] = { 0.0, 0.2, -1.0 };
GLfloat nolight [] = { 0.0, 0.0, 0.0, 1.0 }; /* rather blackish */
GLfloat globe_ambient[] = { 0.2, 0.4, 0.0, 1.0 }; /* rather greenish */
GLfloat globe_diffuse[] = { 0.4, 0.2, 0.0, 1.0 }; /* rather redish */
GLfloat globe_position [] = { 0.0, 0.0, 0.0, 1.0 };
/* place a spotlight */
glLightfv (GL_LIGHT0, GL_AMBIENT, spot_ambient);
glLightfv (GL_LIGHT0, GL_DIFFUSE, nolight);
glLightfv (GL_LIGHT0, GL_SPECULAR, spot_specular);
glLightfv (GL_LIGHT0, GL_POSITION, spot_position);
glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);
glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 3.0);
glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);
glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0);
glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0);
glLightfv (GL_LIGHT1, GL_AMBIENT, globe_ambient);
glLightfv (GL_LIGHT1, GL_DIFFUSE, globe_diffuse);
glLightfv (GL_LIGHT1, GL_SPECULAR, nolight);
glLightfv (GL_LIGHT1, GL_POSITION, globe_position);
glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 360.0);
glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0);
glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.0);
glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0);
glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 1.5);
glEnable (GL_LIGHT0);
glEnable (GL_LIGHT1);
GLfloat material_ambient[] = { 0.5, 0.5, 0.5, 0.1 };
GLfloat material_diffuse [] = { 0.5, 0.5, 0.5, 0.1 };
GLfloat material_specular [] = { 0.9, 0.9, 0.9, 0.1 };
GLfloat material_emission [] = { 0.0, 0.0, 0.0, 0.1 };
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 4.0);
...
drawPlanes (28);
...
}
void initializeGL ()
{
glShadeModel (GL_SMOOTH);
glEnable (GL_DEPTH_TEST);
glEnable (GL_NORMALIZE);
glEnable (GL_LIGHTING);
glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
GLfloat global_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
glLightModelfv (GL_LIGHT_MODEL_AMBIENT, global_ambient);
glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
}
...
10.2.6 The Mathematics of OpenGL Lighting
If lighting is
not enabled, the colour of a vertex is simply the current colour; if it is
enabled, the lighting computations described here are carried out in eye
coordinates. In the following equations, mathematical operations are performed
separately on the R , G , and B components. Thus, for
example, when three terms are shown as added together, the R values, the
G values, and the B values for each term are separately added to
form the final RGB colour (R1+R2,G1+G2,B1+B2) . When three
terms are multiplied, the calculation is (R1R2R3,G1G2G3,B1B2B3) .
The colour produced by lighting a vertex is
computed as follows:
| vertex colour |
= |
material emmision at that
vertex+ |
| |
|
global ambient light× material
ambient property+ |
| |
|
attenuated ambient, diffuse and
specular contributions |
| |
|
from all light
sources |
After lighting calculations are
performed, the colour values are clamped (in RGBA mode) to the range [0,1]. Note
that OpenGL's lighting calculations don't take into account the possibility of
one object blocking light from another, so shadows aren't automatically
created.
10.2.6.1 Material Emission
The material emission term is
the simplest. It's the RGB value assigned to the GL_EMISSION parameter.
10.2.6.2 Scaled Global Ambient Light
The second term is
computed by multiplying the global ambient light (as defined by the GL_LIGHT_MODEL_AMBIENT parameter) by the material's
ambient property (GL_AMBIENT's values as
assigned with glMaterial):
| ambient |
|
× ambientmaterial |
Each of the
R, G, and B values for these two parameters are multiplied separately to compute
the final RGB value.
10.2.6.3 Contributions from Light Sources
Each light source
may contribute to a vertex's colour, and these contributions are added together.
The equation for computing each light source's contribution is as follows:
| contribution |
= |
attenuation factor× |
| |
|
spotlight effect× |
| |
|
(ambient term+diffuse
term+specular term) |
10.2.6.3.1 Attenuation Factor
The attenuation is given by:
where
d is the distance between the light's position and the vertex,
kc = GL_CONSTANT_ATTENUATION, kl = GL_LINEAR_ATTENUATION and kq = GL_QUADRATIC_ATTENUATION.
10.2.6.3.2 Spotlight Effect
The spotlight effect evaluates
to one of three possible values, depending on whether the light is actually a
spotlight and whether the vertex lies inside or outside the cone of illumination
produced by the spotlight:
- 1 if the light isn't a spotlight (GL_SPOT_CUTOFF is 180.0).
- 0 if the light is a spotlight but the vertex lies outside the cone of
illumination produced by the spotlight.
- (max{-L·
D,0})GL_SPOT_EXPONENT where: L is
the unit vector that points from the vertex to the spotlight (GL_POSITION), and D is the spotlight's direction
(GL_SPOT_DIRECTION), assuming the light is a
spotlight and the vertex lies inside the cone of illumination produced by the
spotlight. The dot product of the two vectors L and D varies as
the cosine of the angle between them; hence, objects directly in line get
maximum illumination, and objects off the axis have their illumination drop as
the cosine of the angle. To determine whether a particular vertex lies within
the cone of illumination, OpenGL evaluates max{-L· D,0} . If this value is less
than the cosine of the spotlight's cutoff angle (GL_SPOT_CUTOFF), then the vertex lies outside the cone;
otherwise, it's inside the cone.
10.2.6.3.3 Ambient Term
The ambient term is simply the
ambient colour of the light scaled by the ambient material property:
ambientlight×
ambientmaterial
10.2.6.3.4 Diffuse Term
The diffuse term needs to take into
account whether light falls directly on the vertex, the diffuse colour of the
light, and the diffuse material property:
(max{L· N,0})× diffuselight× diffusematerial
where: L is the unit vector that
points from the vertex to the light position (GL_POSITION) and N is the unit normal vector at
the vertex.
10.2.6.3.5 Specular Term
The specular term also depends on
whether light falls directly on the vertex. If L· N is less than or equal to zero, there is no
specular component at the vertex. (If it's less than zero, the light is on the
wrong side of the surface). If there's a specular component, it depends on the
following:
- The unit normal vector at the vertex N .
- The sum of the two unit vectors that point between (1) the vertex and the
light position L and (2) the vertex and the viewpoint V
(assuming that GL_LIGHT_MODEL_LOCAL_VIEWER is
true; if it's not true, the vector (0, 0, 1) is used as the second vector in
the sum). This vector sum is normalized (by dividing each component by the
magnitude of the vector) to yield S .
- The specular exponent (GL_SHININESS).
- The specular colour of the light (light GL_SPECULAR).
- The specular property of the material (material GL_SPECULAR).
Using these definitions, here's
how OpenGL calculates the specular term:
(max{S· N,0})shininess× specularlight× specularmaterial
However, if L· N=0 , the specular term is 0.
10.2.6.4 Putting It All Together
The following represents
the entire lighting calculation in RGBA mode.
| vertex colour |
= |
emmisionmaterial+ |
| |
|
ambientlight× ambientmaterial+ |
| |
|
|
|
æ ç ç è |
|
|
ö ÷ ÷ ø |
|
æ è |
(max{-L· |
D,0}) |
|
ö ø |
|
( |
light term |
) |
| |
where
| light term |
= |
ambientlight× ambientmaterial+ |
| |
|
(max{L· N,0})× diffuselight× diffusematerial+ |
| |
|
(max{S· N,0})shininess× specularlight× specularmaterial |