Previous Contents Next

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:

During the process of rendering we must consider the following distinctions:

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:

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.


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:

I=kaIa     (10.1)
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:
I=kdIpcos (q )     (10.2)

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
I=kdIp(N· L)     (10.3)

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,

I=kaIa+kdIp(N· L)     (10.4)
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:
I=kaIa+
kdIp(N· L)
4p d2

(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:
I=kaIa+
kdIp(N· L)
d+d0
    (10.5)

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+
Ip
d+d0
[ 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+
Ip
d+d0
[ 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 +
m
å
i=1
diffuse  term i+
m
å
i=1
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

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+
IpR
d+d0
[ 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
 
l
=k
 
al
I
 
al
+
I
 
pl
d+d0
é
ë
k
 
dl
(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:

Not taken into account are:

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:

  1. Define normal vectors for each vertex of all the objects. These normals determine the orientation of the object relative to the light sources.

  2. Create, select, and position one or more light sources.
  3. 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).
  4. 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:

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
 
light  model
× 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:
attenuation=
1
kc+kld+kqd2

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:

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:

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+
   
n-1
å
i=0
æ
ç
ç
è
1
kc+kld+kqd2
ö
÷
÷
ø
 



i
æ
è
(max{-L· D,0})
GL_SPOT_EXPONENT
 
ö
ø
 

i
( light  term )
 
 
i

where
light  term = ambientlight× ambientmaterial+
    (max{L· N,0})× diffuselight× diffusematerial+
    (max{S· N,0})shininess× specularlight× specularmaterial


Previous Contents Next