Specular light doesn't work as supposed to

We draw a scene and then, using the keyboard, we re-position the source of the light. This far everything is great. Now, as long as we use diffuse light all is just fine but as soon as we change to specular light, the scene behaves unpredictably. At first we suspected the normals to be crazy but it does work as expected with diffuse light, so, we assume it can’t be that. Most likely, it’s something basic but as far as we have seen the examples and help given in the Red Book, it’s suppsoed to work (and it does work as well but not for all the faces).

The diffuse light works for all our faces (we have only three this far) while the specular light works for the first two but not the third. The first two are in the xy-plane, while the third one is in the xz-plane. And (once again), yes, we did set the normal right (correct behavior of the difufse light proves it).

This is how we set up the object.


private void doDrawStupidThingThatWorksNotWithLight () {
double size = 75.0;
float[]
   amb = new float[]{0.0f, 1.0f, 0.0f, 1.0f},
   dif = new float[]{0.0f, 1.0f, 0.0f, 1.0f},
   spe = new float[]{0.0f, 1.0f, 0.0f, 1.0f},
   shi = new float[]{50.0f};
   this.gl.glMaterialfv (GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, amb);
   this.gl.glMaterialfv (GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, dif);
   this.gl.glMaterialfv (GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, spe);
   this.gl.glMaterialfv (GL.GL_FRONT, GL.GL_SHININESS, shi);
   this.gl.glBegin (GL.GL_QUADS);
      this.gl.glNormal3d (0, 1, 0);
      this.gl.glVertex3d (0, 0, 0);
      this.gl.glVertex3d (0, 0, size);
      this.gl.glVertex3d (-size, 0, size);
      this.gl.glVertex3d (-size, 0, 0);
   this.gl.glEnd ();}

And this is how we set up the lighting.


private void doShedLight () {
float[]
   amb = new float[]{0.2f, 0.2f, 0.2f, 1.0f},
   dif = new float[]{0.0f, 0.0f, 0.0f, 1.0f},
   spe = new float[]{1.0f, 1.0f, 1.0f, 1.0f},
   pos = new float[]{this.angX, this.angY, this.angZ, 0.0f},
   spo = new float[]{0.0f, 0.0f, 0.0f, 1.0f};

   this.gl.glLightfv (GL.GL_LIGHT0, GL.GL_AMBIENT, amb);
   this.gl.glLightfv (GL.GL_LIGHT0, GL.GL_DIFFUSE, dif);
   this.gl.glLightfv (GL.GL_LIGHT0, GL.GL_SPECULAR, spe);
   this.gl.glLightfv (GL.GL_LIGHT0, GL.GL_POSITION, pos);
   this.gl.glLightfv (GL.GL_LIGHT0, GL.GL_SPOT_DIRECTION, spo); }

So, any hints?

Without seeing some sample images of what’s going wrong, most answers will be mostly guesswork, but here we go anyway…

You might be falling foul of Gouraud (the kind that OpenGL does for you) shading’s weakness at rendering specular highlights. You can read about it at the supplied link, but the gist of the problem is that intensities are calculated at each vertex using the normal vector, and then interpolated across the polygon. If the specular highlight lies somewhere on the interior of the polygon’s area, the interploated intensities will not display it.
This problem does not occur with Phong shading. In this case, the normal vector is interpolated over the face of the polygon, and the intensity calculation performed for each rendered fragment. The obvious downside is the increased computation required.
I believe Phong shading can be performed using Fragment Shaders, or you could just subdivide large faces into a patchwork of smaller faces with appropriate normal values.

Thanks for the reply. I’d love to present you with a working code that examplifies the issue but i’ve been using news too long to make a mistake to post an entire source code on a public display (there are better ways to make people hate you ;D ). Nevertheless, if you (or anybody else) mail me at tmp1@viltersten.com, i’d be happy to mail back.

Now, having that said - i read the link you provided but the only thing that Wikipedia tells me is that the issue can occur when using a number of surfaces. I have stripped the problem to only one single polygon and still get this crazy behavior. Also, i find the idea of a highly professional software as OpenGL going down for something as simple as coloring a single something highly suspect. Not saying it’s impossible - just a little bit unexpected

Hoping for many letters requesting the crazy behavior - thanks for any additional info.

Your problem seems to be low geometry tessellation. For such a big “wall” (size = 75.0), only four per-vertex specular values are calculated and then interpolated across the quad. You either need to subdivide your geometry or use per-pixel lighting.

Also, try enabling SEPARATE_SPECULAR_COLOR.

Sorry, as i suspected neither downsizing or enabling that stuff did help. I’m seriously considering the option of paying someone to take a look at the code. Given the prices and my budget it’s still only a consideration but i sure get frustrated so you never know… :wink:

If you send a compilable/runnable bit of code I would be happy to take a look. (Free of charge ;))

I would love to. However, i have issues posting more than a few lines on a public website. I can (and will if i have to) but i’d prefer to mail it directly to you. Send me a line and i’ll reply to you right away. tmp1@viltersten.com

As the payment - what about i’ll buy you a pizza next time i’m in Belgium? :slight_smile:

The first problem is with the light position. If you set the w coordinate to 0, the light is in fact a light at an infinite location and the position is specifying the direction of this light source. You can use this to get a single ambient light source like the sun. Since it is at an infinite distance, the light angle for each vertex is equal and so all vertices with the same normal are light the same way. If you change

pos = new float[]{this.angX, this.angY, this.angZ, 0,0f},

to

pos = new float[]{this.angX, this.angY, this.angZ, 1.0f},

things should be working the way you expect

Also

private void setPerspective() {
  this.gl.glMatrixMode (GL.GL_PROJECTION);
  this.gl.glLoadIdentity ();
  this.glu.gluPerspective (120, 1, 1, 500);
  this.glu.gluLookAt (15, 75, 100, 0, 0, 0, 0, 0, 1);
  this.gl.glMatrixMode (GL.GL_MODELVIEW);
}

should be

private void setPerspective() {
  this.gl.glMatrixMode (GL.GL_PROJECTION);
  this.gl.glLoadIdentity ();
  this.glu.gluPerspective (120, 1, 1, 500);
  this.gl.glMatrixMode (GL.GL_MODELVIEW);
  this.glu.gluLookAt (15, 75, 100, 0, 0, 0, 0, 0, 1);
}