# Section 4.5. Positional and Directional Lights

### 4.5. Positional and Directional Lights

Positional light sources shine light in all directions. Use a positional light source to simulate local light sources, such as a streetlight or an exposed light bulb. Specify the position as a homogenous xyzw coordinate. x, y , and z specify the light position in object coordinates, and the w value must be 1.0.

The following code makes GL_LIGHT1 a positional light at (10, 4, 4) in object coordinates:

const GLfloat pos[4] = { 10.f, 4.f, -4.f, 1.f };
glLightfv( GL_LIGHT1, GL_POSITION, pos );

Directional light sources are always at an infinite distance from your geometry and shine light in a single direction. Use a directional light to simulate nonlocal light sources with effectively parallel light rays, such as the Sun. To specify a directional light, again use a homogenous coordinate, but store a vector pointing toward the light in the x, y , and z values (the light shines in the opposite direction), and set the w coordinate to 0.0.

The following code makes GL_LIGHT1 a directional light at positive x, with light shining along the negative x axis (in object coordinates):

const GLfloat pos[4] = { 1.f, 0.f, 0.f, 0.f };
glLightfv( GL_LIGHT1, GL_POSITION, pos );

To summarize the above:

• For positional lights, GL_POSITION is an xyz location with a w value of 1.0.

• For directional lights, GL_POSITION is an xyz vector pointing toward the light with a w value of 0.0. The light direction is ( xyz ).

For both positional and directional lights, GL_POSITION is an object-coordinate value. When you call glLightfv () to specify the position, OpenGL multiplies the GL_POSITION value by the current model-view matrix to transform it into eye coordinates, where OpenGL performs lighting calculations. Usually, an application needs to manage only two light-positioning scenarios:

• Headlights The light position stays fixed relative to the camera, regardless of the camera position. Applications commonly create this effect by specifying the light position in eye coordinates. Because the camera is at the origin in eye coordinates, specifying the light position relative to the camera position is simple. The following code places GL_LIGHT1 directly above the camera:

glMatrixModel( GL_MODELVIEW );
glPushMatrix();
const GLfloat pos[] = { 0., 1., 0., 1. };
glLightfv( GL_LIGHT1, GL_POSITION, pos );
glPopMatrix();

• Scene lights Architectural applications commonly place positional light sources in the scene to simulate a light fixture or table lamp. To create this effect, the model-view matrix must contain the current view transformation, as well as the light modeling transformation (if any), when you specify the light position. You'll need to specify the light position again if the camera changes position or if the light moves (to simulate repositioning a desk lamp, for example).

In either case, always specify the light position before specifying any geometry that the light illuminates.

### 4.6. Debugging Lights

Several things could cause lighting not to work properly, and there are numerous ways to identify the source of the problem.

#### 4.6.1. Debugging a Blank Window

If OpenGL appears to have rendered nothing, try the following:

• Disable lighting by replacing your call to enable lighting with glDisable ( GL_LIGHTING ) . If OpenGL still renders nothing, the problem is elsewherepossibly an incorrect view transformation or a near/far clipping plane problem. Resolve these issues first before re-enabling lighting.

• If the final rendered color of your geometry happens to be the same color as your clear color, your window will appear blank even though OpenGL rendered the geometry. To make "invisible" geometry appear, try setting a different clear color by calling glClearColor () just before you call glClear () . If enabling lighting makes your geometry appear black, check to ensure that your application has enabled at least one light source, and set its diffuse and specular colors appropriately.

#### 4.6.2. Normals

When first learning to use OpenGL, many programmers fail to supply correct normals. This type of error causes odd shading artifacts on lit surfaces. As a good rule of thumb, supply a unit-length normal for every vertex.

If the application is specifying unit-length normals, yet odd lighting artifacts persist, it's possible that scale transformations in the model-view matrix are distorting the normals. If necessary, enable GL_RESCALE_NORMAL or GL_NORMALIZE to resolve this issue.

#### 4.6.3. Incorrect Face Culling

If your application enables GL_CULL_FACE but has the vertex winding order reversed , you might be looking at back faces instead of front faces. In addition to causing other visual artifacts, this situation might make the light appear to be on the wrong side of your geometry. Replace your call to enable face culling with a call to glDisable ( GL_CULL_FACE ) . If disabling face culling resolves your lighting issue, see "glFrontFace" in OpenGL Reference Manual for information on how to configure face culling properly.

#### 4.6.4. Debugging Position and Direction

If your lights appear in the wrong position or shine from the wrong direction, check to make sure that you're specifying the GL_POSITION each frame with the correct model-view transformation. Specifying the GL_POSITION each frame is required for some light types, and if your light is a headlight or some other type of light that doesn't require a refresh of the GL_POSITION each frame, this is still good debugging technique. You can always optimize specifying the GL_POSITION later, after you've identified and addressed any issues related to light position.

Be sure to specify the GL_POSITION before rendering geometry illuminated by that light.

If you use positional lights, first try a directional light instead. This will help verify that you've specified the vertex normals correctly.

#### 4.6.5. Debugging Light Colors

If you're using colored lights and not getting the results you expect, initially use white lights to verify that you've specified the correct material colors. Remember, for example, that a pure-red object lit by a pure-blue light will appear black, because red objects reflect only red light and absorb blue light.

#### 4.6.6. Per-Vertex Lighting Artifacts

The fact that OpenGL calculates lighting at each vertex could create lighting artifacts on low-resolution geometry, as shown in Figure 4-3.

##### Figure 4-3. The sphere on the left has insufficient resolution for OpenGL to render the specular highlight accurately. This is not an issue for the sphere on the right, due to its higher resolution. Light and material parameters are identical for both spheres.

Low-resolution geometry lighting artifacts are especially apparent in specular highlights. Inadequate resolution, however, could also cause visible artifacts in diffuse lighting. These artifacts will appear in the presence of either directional or positional lights, but positional lights often cause them to be more acute. Low-resolution geometry that rotates or moves relative to a light source will often have an unstable specular highlight that appears to crawl or swim over the surface, or to fade in and out.

Geometry must have sufficient vertices for per-vertex lighting and Gouraud shading to produce acceptable results. Increasing geometric resolution could adversely affect performance, however, so try to find a good balance between lighting effects and number of vertices.

You might also try specifying a smaller GL_SHININESS specular exponent to create a larger specular highlight that affects more vertices.

If neither of these methods produces acceptable results, consider other OpenGL features, such as cube maps or per-fragment lighting in a fragment shader. Chapter 6, "Texture Mapping," describes using cube maps to improve specular highlights. You can implement per-fragment lighting in OpenGL version 2.0 by using fragment shaders, but this is beyond the scope of this book. See OpenGL Shading Language for more information.

#### 4.6.7. Missing Specular Highlights

Specular highlights might not appear for several reasons.

Check to ensure that the incident light and viewing angles are correct. The specular highlight won't appear unless the viewing angle coincides with the reflection of the incident light. Incorrect surface normals could cause OpenGL to calculate the reflection vector incorrectly, so check that your application is sending correct unit-length normals.

Check your setting for the specular material color and specular light color. Remember that only GL_LIGHT0 defaults to a full-intensity specular color; other lights default to zero intensity.

Check your GL_SHININESS value. Large values may create specular highlights too small to appear on low-resolution geometry. Temporarily set a much lower value, such as 1.0. If the specular highlight appears, you'll need to increase the resolution of your geometry, as discussed earlier in this chapter, or set GL_SHININESS to a smaller value.

If you're using texture mapping with GL_MODULATE texture environment mode, you'll need to use secondary color or multitexturing to add a specular highlight. See Chapter 6, "Texture Mapping," for more information.

#### 4.6.8. Line and Point Colors

OpenGL is a state machine. When your application enables lighting, OpenGL lights all subsequent primitives, including lines and points. Although lit lines and points can create some interesting effects, often this isn't the desired result. Most applications need to disable lighting before submitting line and point primitives. This causes OpenGL to render the primitives with the current primary color, rather than modify the primary color with lighting results.