Specular reflection not OK

Hello everybody,

For a long time I have asked myself questions about this. Take for instance the code below. It will draw a sphere with a certain lighting. This light is directional light and coming from the negative Y-Axis : GLfloat position[] = {0.0f,-1.0f,0.0f,0.0f};

Yet, and here is the problem: the specular lighting does not seem in order. It is shown as being fixed on a certain spot, and does NOT change when you move the camera around. This is nowhere near what you would expect as reflection.

Can anybody tell me where the problem is located and how to solve this?

void CNewRightView:    [img]http://www.opengl.org/discussion_boards/ubb/biggrin.gif[/img]rawSphereWithGlut()
{

 GLfloat ambient[]   = {0.6f, 0.6f,0.7f,1.0f};
 GLfloat diffuse[]   = {0.7f, 0.7f,0.7f,1.0f};
 GLfloat position[]  = {0.0f,-1.0f,0.0f,0.0f};
 GLfloat spec[]     = {1.0f, 1.0f,1.0f,1.0f};
 GLfloat specma[]   = {0.3f, 0.3f,0.3f,1.0f};

 glShadeModel(GL_SMOOTH);  // Smooth rendering
 glFrontFace(GL_CCW);    // Counter clock-wise polygons face out

 glEnable(GL_DEPTH_TEST);  // Hidden surface removal
 glEnable(GL_LIGHTING);    // Enable lighting

 glLightfv(GL_LIGHT1,GL_POSITION,position);  // Setup and enable light 0
 glLightfv(GL_LIGHT1,GL_AMBIENT,ambient);
 glLightfv(GL_LIGHT1,GL_DIFFUSE,diffuse);
 glLightfv(GL_LIGHT1,GL_SPECULAR,spec);
 glEnable(GL_LIGHT1);

 glEnable(GL_COLOR_MATERIAL);          // Set Material properties to follow glColor values
 glMaterialfv(GL_FRONT,GL_SPECULAR,specma);
 glMateriali(GL_FRONT,GL_SHININESS,128);

 glColor3d(0.5,0.5,0.5);

 glutSolidSphere(0.05,50,50);

 glDisable(GL_POLYGON_OFFSET_FILL);
 glDisable(GL_COLOR_MATERIAL);
 glDisable(GL_DEPTH_TEST);
 glDisable(GL_LIGHTING);
 glDisable(GL_LIGHT1);
}

[This message has been edited by Simon666 (edited 03-12-2003).]

That code doesn’t show where you “move the camera around.”

If you are doing so in the GL_PROJECTION matrix, you shouldn’t be. That should only be used for setting up the shape of the viewing volume. (e.g. gluPerspective, glOrtho, etc.)

When you set the GL_POSITION of a light, it takes the MODELVIEW matrix into account, so it also makes a difference where you call that at.

Hello,

First of all, thanks for replying. The camera is set in the CCamera class. I use glRotated and glTranslated to view the scene from the desired angle.

If you just “move” the camera you shouldn’t notice any difference.
If you “rotate” the camera, there should be a little difference, at least as long as the MODELVIEW matrix is the current matrix.

Originally posted by vincoof:
If you just “move” the camera you shouldn’t notice any difference.
If you “rotate” the camera, there should be a little difference, at least as long as the MODELVIEW matrix is the current matrix.

Could you tell me what this means, and what I would need to change? I currently don’t understand what you mean?

Translation only does not change the specular highlight (except in local viewer mode or with point light). If the light is directional, and if the viewer is considered at an infinite distance (it is the default state of OpenGL) then calling glTranslate has no effect on the specular contribution.

But if you call glRotate with a non-nul angle, then the specular highlight might move and seems to “float” around the object.

Originally posted by vincoof:
[b]Translation only does not change the specular highlight (except in local viewer mode or with point light). If the light is directional, and if the viewer is considered at an infinite distance (it is the default state of OpenGL) then calling glTranslate has no effect on the specular contribution.

But if you call glRotate with a non-nul angle, then the specular highlight might move and seems to “float” around the object.[/b]

OK, I call glRotate with an angle different from zero in my CCamera class, but how would I solve this problem then?

It does not really solve the problem. It could explain why you thought there was a problem when in fact there wasn’t. It’s natural to think that the specular highlight floats, but the simple translation does not give the feeling of floating, so it’s a common mistake to think that the specular is wrong when in fact it’s ok. But if you call glRotate then obviously there is a problem.

Could you post screenshots showing the problem ?

Originally posted by vincoof:
Could you post screenshots showing the problem ?[/b]

Here is a picture showing the problem. I use positional light coming from the negative Y direction. Yet nomatter under what angle I look at the scene, the reflected spot on the sphere stays at the same place, which can be found by drawing a line from the center in the direction (0,-1/sqrt(2),1(sqrt(2))), or so it seems. Note that the diffuse reflection is OK and shows clearly that the directional light is coming from the negative Y-axis.

GLfloat position[] = {0.0f,-1.0f,0.0f,0.0f};
glLightfv(GL_LIGHT0,GL_POSITION,position);

[This message has been edited by Simon666 (edited 03-11-2003).]

I’m sorry but the image looks correct. Perhaps you could setup online an executable of this sample program ?

Thanks for the program. Now I really see what you mean.
The most possible explanation is that you work with projection matrix instead of modelview matrix.
Do you call glMatrixMode(GL_MODELVIEW) in your code ?

Also, have you tried to call glGetError ?

Do you call glMatrixMode(GL_MODELVIEW) in your code ?

Yes, on several places. If I understand it correctly, it is necessary for perspective view?

Also, have you tried to call glGetError ?

I’ve never even heard of this, so no. What is it used for and how does one use it?

Generally, when you setup your projection matrix you may call something like that (typically when the window is resized) :
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum or gluPerspective
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glGetError is used to get errors from the GL
it is a function that returns an int (an enumerant) which corresponds to first error ever encountered since the last call to glGetError.
If glGetError returns GL_NO_ERROR, it means that no problem was detected by the GL (it does not ensure that 100% of the problems are checked, but a majority of them). If not GL_NO_ERROR it can be something like GL_INVALID_ENUM or GL_INVALID_VALUE … if so, you’d better look at the place where the error occurs.

[This message has been edited by vincoof (edited 03-11-2003).]

I will try it once. If you look at my code, you can see that for perspective it goes pretty much like this:

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

if (SpecialView==true)
{
// Stuff for top, bottom, left, right, front and back view
}
else
{
if ((AutoRotate==1)&&(abs(RelevantChange)==2))
{
Normal_Azim+=AutoRotateAmount;
}

// Ensure azimuth, elevation and twist are between -180 and 180 degrees

gluPerspective( Focus , Ratio , Maximum2( Distance/100, Distance - 10 ), Distance + 10 );
glTranslated( 0, 0, -Distance );

glRotated( Normal_Twist ,0,0,1);
glRotated(-90+Normal_Elev ,1,0,0);
glRotated(-90-Normal_Azim ,0,0,1);
}

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());

glMatrixMode( GL_MODELVIEW );

glPushMatrix();
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

if (SpecialView==true)
{
// Stuff for top, bottom, left, right, front and back view
}
else
{
glRotated(90+Normal_Azim ,0,0,1);
glRotated(90-Normal_Elev ,1,0,0);
glRotated(-Normal_Twist ,0,0,1);

glTranslated( 0, 0, Distance );
}

glPopMatrix();
}

The camera is set by several rotations, characterised by a viewing direction specified by an azimuth, elevation and twist. This observer is looking in this direction at a certain Target, characterized by x,y and z coordinates and by a certain distance of the observer from the target.

This is how I set my camera, this happens in the OnDraw function of my view. The rendering of the scene is done between these functions:

// Basic scheme of OnDraw (simplified)

C**View::OnDraw(CDC pDC)
{
pDoc->Camera.Set();

// Render scene

pDoc->Camera.Reset();
}

[This message has been edited by Simon666 (edited 03-11-2003).]

call your camera settings inside the modelview state.
You’re doing :

glMatrixMode(GL_PROJECTION);
frustum stuff
rotate and translate according to camera position and orientation
glMatrixMode(GL_MODELVIEW);

but you should do :
glMatrixMode(GL_PROJECTION);
frustum stuff
glMatrixMode(GL_MODELVIEW);
rotate and translate according to camera position and orientation

and perhaps you should call glLoadIdentity just after glMatrixMode(GL_MODELVIEW)

Well, I’ve simplified my function to set the camera and this is how they look now:

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

gluPerspective( Focus , Ratio , Maximum2( Distance/100, Distance - 10 ), Distance + 10 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

glTranslated( 0, 0, -Distance );

glRotated( Normal_Twist ,0,0,1);
glRotated(-90+Normal_Elev ,1,0,0);
glRotated(-90-Normal_Azim ,0,0,1);

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

glRotated(90+Normal_Azim ,0,0,1);
glRotated(90-Normal_Elev ,1,0,0);
glRotated(-Normal_Twist ,0,0,1);

glTranslated( 0, 0, Distance );
}

Yet the result is still the same. Do I need to set the light position somewhere in between these lines?

Results are the same ? That is really hard to believe …

Could you please post the new executable ?

ah, but this is prefectly correct !
If that’s not the behaviour you wanted, then I don’t know know what you want

Originally posted by vincoof:
ah, but this is prefectly correct !
If that’s not the behaviour you wanted, then I don’t know know what you want

No it isn’t. The behaviour has still not changed since the previous time I posted the exe, unless you see something else than I do (You never know-I have a crappy graphics card at work). The behaviour is also physically incorrect.

[This message has been edited by Simon666 (edited 03-12-2003).]

It looks right to me too. Unless you don’t want the light to move with the scene. If that is the case, you should set the glLight params after the transformations you do for each sphere.

[This message has been edited by Deiussum (edited 03-12-2003).]