13. OpenGL Lighting Types (Version 2.0)

Introduction

Previously, we talked about setting up some basic lights in OpenGL. Now, we’re going to expand on that by configuring the type of shading, the color of the light, the color of the object, and the type of light we’re using.

It’s important to understand that OpenGL supports several types of lights:
Specular: This type of light is responsible for highlights and shininess on objects. For example, when you light a sphere with both diffuse and specular light, the specular light adds the shiny highlights.
Diffuse: Diffuse light adds the base color of the light to your object. It determines how bright or colorful the light looks on the object’s surface.
Ambient: Ambient light fills the scene with light from all directions. It’s like the background light we see during the day, where the sun acts as a diffuse light but provides ambient illumination from all around.
Emissive: This type of light makes an object appear to emit its own light, like a glow. However, it doesn’t create a soft halo effect—just a steady radiance from the object itself.

These light types, combined with proper material settings, allow us to create complex lighting effects.

Setting Up Lights

For this tutorial, we’ll use two lights:

1. Diffuse Light (`GL_LIGHT0`)
This light provides color and brightness to objects.

2. Ambient Light (`GL_LIGHT1`)
This light illuminates everything equally, without a specific direction.

We start by enabling both lights:

glEnable(GL_LIGHT0); // Enable diffuse light
glEnable(GL_LIGHT1); // Enable ambient light

Next, we define the properties for each light.

Diffuse Light:
The diffuse light color is set to white:

GLfloat dlr = 1.0; // Red component
GLfloat dlg = 1.0; // Green component
GLfloat dlb = 1.0; // Blue component

Ambient Light:
The ambient light is also white, ensuring uniform illumination:

GLfloat alr = 1.0; // Red component
GLfloat alg = 1.0; // Green component
GLfloat alb = 1.0; // Blue component

Light Position:
Here’s where the light comes from:

GLfloat lx = 0.0; // X position
GLfloat ly = 0.0; // Y position
GLfloat lz = 1.0; // Z position
GLfloat lw = 0.0; // W determines type (point or directional)

So, what does this all mean?
– The diffuse light is white, set with `R = 1, G = 1, B = 1`.
– The ambient light is also white, which ensures everything has a minimum brightness.
– The light position is set at `X = 0, Y = 0, Z = 1, W = 0`. Setting `W = 0` makes this a directional light, like sunlight. If you want a point light (like a bulb), set `W = 1`, and the light will radiate outward from the position.

To apply these properties in OpenGL:

GLfloat DiffuseLight[] = {dlr, dlg, dlb}; // Diffuse light color
GLfloat AmbientLight[] = {alr, alg, alb}; // Ambient light color
GLfloat LightPosition[] = {lx, ly, lz, lw}; // Light position

glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);  // Set diffuse light
glLightfv(GL_LIGHT1, GL_AMBIENT, AmbientLight); // Set ambient light
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); // Set light position

We’ve split these into two lights—`GL_LIGHT0` handles the diffuse light, while `GL_LIGHT1` handles the ambient light. Technically, you could combine these into a single light, but splitting them gives you more control.

Shading Model

Let’s briefly discuss shading. OpenGL provides two shading models:
GL_SMOOTH: This is the default and provides smooth transitions between light and dark across the surface. It works well for rounded objects like spheres.
GL_FLAT: Flat shading applies a single color to each polygon face, giving the object a faceted appearance.

For this example, we’re using smooth shading:

glShadeModel(GL_SMOOTH); // Enable smooth shading

Flat shading can be useful for certain visual styles or when you want to emphasize the polygonal nature of a model:

glShadeModel(GL_FLAT); // Enable flat shading

Bringing It All Together

To summarize:
1. `GL_LIGHT0` is our diffuse light, providing directional illumination.
2. `GL_LIGHT1` is our ambient light, ensuring a base level of brightness.
3. Smooth shading ensures light transitions are gradual, giving the scene a polished appearance.

Tutorial Code

Here’s the full code for this tutorial. It demonstrates how to configure and enable lights, adjust light properties dynamically, and apply smooth shading to a rotating cube.

#include <GL/gl.h>
#include <GL/glut.h>

// Angle of rotation
GLfloat angle = 0.0;

// Diffuse light color variables
GLfloat dlr = 1.0, dlg = 1.0, dlb = 1.0;

// Ambient light color variables
GLfloat alr = 1.0, alg = 1.0, alb = 1.0;

// Light position variables
GLfloat lx = 0.0, ly = 0.0, lz = 1.0, lw = 0.0;

// Draw the cube
void cube(void) {
    glRotatef(angle, 1.0, 0.0, 0.0); // Rotate on the X-axis
    glRotatef(angle, 0.0, 1.0, 0.0); // Rotate on the Y-axis
    glRotatef(angle, 0.0, 0.0, 1.0); // Rotate on the Z-axis
    glutSolidCube(2);                // Draw the cube
}

void init(void) {
    glEnable(GL_DEPTH_TEST); // Enable depth testing
    glEnable(GL_LIGHTING);   // Enable lighting
    glEnable(GL_LIGHT0);     // Enable diffuse light
    glEnable(GL_LIGHT1);     // Enable ambient light
    glShadeModel(GL_SMOOTH); // Set smooth shading
}

void display(void) {
    glClearColor(0.0, 0.0, 0.0, 1.0); // Clear screen to black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    GLfloat DiffuseLight[] = {dlr, dlg, dlb};
    GLfloat AmbientLight[] = {alr, alg, alb};
    GLfloat LightPosition[] = {lx, ly, lz, lw};

    glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
    glLightfv(GL_LIGHT1, GL_AMBIENT, AmbientLight);
    glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);

    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // Camera setup
    cube(); // Draw the cube
    glutSwapBuffers();
    angle++; // Increment rotation angle
}

void reshape(int w, int h) {
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y) {
    if (key == 'r') { dlr = 1.0; dlg = 0.0; dlb = 0.0; } // Red light
    if (key == 'g') { dlr = 0.0; dlg = 1.0; dlb = 0.0; } // Green light
    if (key == 'b') { dlr = 0.0; dlg = 0.0; dlb = 1.0; } // Blue light
    if (key == 'w') { ly += 10.0; } // Move light up
    if (key == 's') { ly -= 10.0; } // Move light down
    if (key == 'a') { lx -= 10.0; } // Move light left
    if (key == 'd') { lx += 10.0; } // Move light right
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL Lighting Example");
    init();
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

If you have any questions or encounter issues, feel free to email me at swiftless@gmail.com. Happy coding!

  • March 25, 2010
  • 8