30

I am developing a graphics application in C++ with the OpenGL API and GLUT.

To add lighting, I made the following changes in my modelview matrix:

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

// Create light components.
GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f };
GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat position[] = { 0.0f, 0.0f, 0.0f, 1.0f };

// Assign created components to GL_LIGHT0.
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv(GL_LIGHT0, GL_POSITION, position);

The lighting largely works I believe, but the colors of my objects all go away. All I see is a black/white silhouette of my overall figure.

I was wondering why this is?

genpfault
  • 51,148
  • 11
  • 85
  • 139
dangerChihuahua007
  • 20,299
  • 35
  • 117
  • 206

2 Answers2

34

When lighting is enabled, a vertex' color is not determined from the color set by glColor or glColorPointer, but by the currently set material colors combined with the lights' colors using the lighting computations.

So in order to change an object's color, you need to change the material setting (which by default is a diffuse grey material) before rendering, using the glMaterial functions. There is essentially a corresponding material color for each of the different light colors (GL_DIFFUSE, ...) along with some additional properties to approximate light emitting materials (GL_EMISSION) and controlling the material's roughness (GL_SHININESS). Read some introductory material on OpenGL's lighting features to understand their workings.

What you can do to quickly adapt your code from plain coloring to lighting (or to enable per-vertex material properties) is to use color material. By calling glEnable(GL_COLOR_MATERIAL) and setting an appropriate mapping with glColorMaterial you can configure OpenGL to change a specific material color, whenever you change the current vertex color (using either glColor or glColorPointer).

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
22

Try glEnable(GL_COLOR_MATERIAL).

See Common OpenGL Pitfall #14:

  1. Careful Enabling Color Material

OpenGL's color material feature provides a less expensive way to change material parameters. With color material enabled, material colors track the current color. This means that instead of using the relatively expensive glMaterialfv routine, you can use the glColor3f routine.

Here is an example using the color material feature to change the diffuse color for each vertex of a triangle:

glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glBegin(GL_TRIANGLES);
    glColor3f(0.2, 0.5, 0.8);
    glVertex3f(1.0, 0.0, 0.0);
    glColor3f(0.3, 0.5, 0.6);
    glVertex3f(0.0, 0.0, 0.0);
    glColor3f(0.4, 0.2, 0.2);
    glVertex3f(1.0, 1.0, 0.0);
glEnd();

Consider the more expensive code sequence needed if glMaterialfv is used explicitly:

GLfloat d1[] = { 0.2, 0.5, 0.8, 1.0 };
GLfloat d2[] = { 0.3, 0.5, 0.6, 1.0 };
GLfloat d3[] = { 0.4, 0.2, 0.2, 1.0 };

glBegin(GL_TRIANGLES);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d1);
    glVertex3f(1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d2);
    glVertex3f(0.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d3);
    glVertex3f(1.0, 1.0, 0.0);
glEnd();

If you are rendering objects that require frequent simple material changes, try to use the color material mode. However, there is a common pitfall encountered when enabling the color material mode. When color material is enabled, OpenGL immediately changes the material colors controlled by the color material state. Consider the following piece of code to initialize a newly create OpenGL rendering context:

GLfloat a[] = { 0.1, 0.1, 0.1, 1.0 };
glColor4f(1.0, 1.0, 1.0, 1.0);

glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glEnable(GL_COLOR_MATERIAL); /* WARNING: Ambient and diffuse material latch immediately to the current color. */
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glColor3f(0.3, 0.5, 0.6);

What state will the front ambient and diffuse material colors be after executing the above code fragment? While the programmer may have intended the ambient material state to be (0.1, 0.1, 0.1, 1.0) and the diffuse material state to be (0.3, 0.5, 0.6, 1.0), that is not quite what happens.

The resulting diffuse material state is what the programmer intended, but the resulting ambient material state is rather unexpectedly (1.0, 1.0, 1.0, 1.0). How did that happen? Well, remember that the color material mode immediately begins tracking the current color when enabled. The initial value for the color material settings is GL_FRONT_AND_BACK and GL_AMBIENT_AND_DIFFUSE (probably not what you expected!).

Since enabling the color material mode immediately begins tracking the current color, both the ambient and diffuse material states are updated to be (1.0, 1.0, 1.0, 1.0). Note that the effect of the initial glMaterialfv is lost. Next, the color material state is updated to just change the front diffuse material. Lastly, the glColor3f invocation changes the diffuse material to (0.3, 0.5, 0.6, 1.0). The ambient material state ends up being (1.0, 1.0, 1.0, 1.0).

The problem in the code fragment above is that the color material mode is enabled before calling glColorMaterial. The color material mode is very effective for efficient simple material changes, but to avoid the above pitfall, always be careful to set glColorMaterial before you enable GL_COLOR_MATERIAL.

nrofis
  • 8,975
  • 14
  • 58
  • 113
genpfault
  • 51,148
  • 11
  • 85
  • 139