Material colors problem

Hi all,
I have a really stupid problem !! it is so stupid I am a little embraced to ask about it, but it is driving me crazy so I will any how…(-:
my problem is:
I am drawing a triangle strip, and I am switching colors(using glMaterialfv) between triangles, BUT the intire strip is always painted by the material color of the last vertex in the strip !!!
The code is very basic, the init is :

// Perspective
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
double aspect = (rect.Height() == 0) ? rect.Width() :
(double)rect.Width()/(double)rect.Height();
::gluPerspective(45, aspect, 0.1, 1000.0);
setSize(rect.Width(), rect.Height());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Lights properties
float ambientProperties[] = { 0.2f, 0.2f, 0.2f, 1.0f};
float diffuseProperties[] = { 0.5f, 0.5f, 0.5f, 1.0f};
float specularProperties[] = { 0.1f, 0.1f, 0.1f, 1.0f};

//enable lighting.
::glEnable(GL_LIGHTING);
::glEnable(GL_LIGHT0);
::glEnable(GL_LIGHT1);

::glLightfv(GL_LIGHT0, GL_AMBIENT, ambientProperties);
::glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseProperties);
::glLightfv(GL_LIGHT0, GL_SPECULAR, specularProperties);

::glLightfv(GL_LIGHT1, GL_AMBIENT, ambientProperties);
::glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseProperties);
::glLightfv(GL_LIGHT1, GL_SPECULAR, specularProperties);
//set the lighting position
setLightPosition();

::glShadeModel(GL_SMOOTH);
::glEnable(GL_NORMALIZE);
//set the black default clear color
float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
setBcgColor(black);
//enable the Z buffer
::glEnable(GL_DEPTH_TEST);

and the function I fill the display list is:

GLfloat SurfaceColor[4];
//make sure that there is content to draw
if(!isValid())
return false;
//create/replace the list located at listNumber
::glNewList(listNumber,GL_COMPILE);
glColor3f (1.0, 1.0, 1.0);
//check according to the transparency level of the object
//if to enable a blending function
if(getAlphaTransparencyLevel() < 1.0f)
{
::glBlendFunc(GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
::glEnable(GL_BLEND);
::glDepthMask (GL_FALSE);
}
//render the trinagle strip
::glBegin(GL_TRIANGLE_STRIP);
for(int i=0 ; i<getVerticesArraySize() ; i++)
{
CVertex& v = getVertex(i);
//set the vertex normal
::glNormal3f(v.getNormal().getX(), v.getNormal
().getY(), v.getNormal().getZ());
SurfaceColor[0] = v.getColor().getRedValue();
SurfaceColor[1] = v.getColor().getGreenValue();
SurfaceColor[2] = v.getColor().getBlueValue();
SurfaceColor[3] = v.getColor().getAlphaValue();
//set the vertex color (ambient diffuse and
//specular properties
::glMaterialfv(GL_FRONT_AND_BACK,
GL_AMBIENT_AND_DIFFUSE , SurfaceColor);
::glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
SurfaceColor);
//set the vertex geometry.
::glVertex3f(v.getX(), v.getY(), v.getZ());
}
::glEnd();
//if we were drawing a transparent object turn off the
//blending function and turn back on the Z buffer
if(getAlphaTransparencyLevel() < 1.0f)
{
::glDepthMask (GL_TRUE);
::glDisable(GL_BLEND);
}

::glEndList();
return true;

I have tried all the trivial tests like switching off the lights and making sure that the glMaterialfv gets the proper material colors in SurfaceColor, I also tried changing the glMaterialfv calls to
::glColor4fv( SurfaceColor); calls, but for some reason then the strip becomes black and white……
what basic thing am I missing ? (just when I thought I was turning from an opengl beginner to an opengl intermediate….)-
thanks in advance.

Maybe it’s just impossible to change the material properties inside of a strip. Anyway, when you’ll worry about speed, you’ll use a vertex array for this strip, and it’s impossible to charge the materials inside of a vertex array.
But using glColor4f was a good idea ! Because it’s allowed to call it inside of a strip and even inside of a vertex array. Now, why do you get only black and white ?
Here are two ideas :

  1. Before beginning drawing your strip, call :
    glEnable (GL_COLOR_MATERIAL);
    glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  2. Before beginning drawing your strip, call :
    glMaterialf (GL_SHININESS, 100.0);

Hope this helps
Morglum

Morglum,
it is possible to change the material in a strip i have done it before.
regarding your suggestions:

  1. it does make it turn from black and white to color, and i get the same effect (last color only)
    2)what does the exponent factor of the color specular component has got to do with it, it only controls the reflection teta angle spread of the surface.

For 2), that’s simple : if the specular exponent is too low, you don’t see the diffuse color and in many cases, it results in a nearly-black-and white display : black for the ambient color and white for the specular highlight.

Now, I’ve seen that you were compiling a display list. I think here’s the problem : Try removing the calls to glNewList/glEndList. Does it work ?

>>Now, I’ve seen that you were compiling a display list. I think here’s the problem : Try removing the calls to glNewList/glEndList. Does it work ?

I did it without the display list, same results.
it shouldn’t make any difference, the opengl just runs the compiles display list as if the commands where provoked just in amore efficient way…

Are you by any chance using glShadeModel(GL_FLAT)?

Nevermind… just looked at your code a bit closer. (Using code tags would make it more readable, btw.) You’re using GL_SMOOTH. Guess that’s not it then.

[This message has been edited by Deiussum (edited 05-09-2002).]

I give up. The code you’ve shown seems to be perfectly correct.

I had a similar problem with glColorMaterial, in the fact that I only wanted to change the material properties and not the color. But what would happen is that after the first glColorMaterial call, other calls to glColorMaterial did not have any effect. After looking at the spec’s on glColorMaterial, in order for the material properties to change you had to call glColor after the glColorMaterial!!!

I not sure but you may have to have a glColor call after glMaterialfv also to make the new material properties take effect???

Originally posted by snow_master:
[b]Hi all,
I have a really stupid problem !! it is so stupid I am a little embraced to ask about it, but it is driving me crazy so I will any how…(-:
my problem is:
I am drawing a triangle strip, and I am switching colors(using glMaterialfv) between triangles, BUT the intire strip is always painted by the material color of the last vertex in the strip !!!
The code is very basic, the init is :

[/b]

nexusone,
nope, nor before or after or each one of them alone works…the same effect…the last vertex color is the color of the entire strip…

Now with glColorMaterial it is stated to be prefered over using glMaterial. And glColorMaterial can not be used between the glBegin and glEnd.
Now with glMaterial the spec states that you can only change one parameter per vertex between a glBegin/glEnd. You have two changes to material between the glBegin/glEnd. Try putting the material changes before the glbegin.

Here is what the spec on glMaterial states:

 NOTES

  The material parameters can be updated at any	time.  In
  particular, glMaterial can be	called between a call to
  glBegin and the corresponding	call to	glEnd.	If only	a
  single material parameter is to be changed per vertex,
  however, glColorMaterial is preferred	over glMaterial	(see
  glColorMaterial).

Originally posted by snow_master:
nexusone,
nope, nor before or after or each one of them alone works…the same effect…the last vertex color is the color of the entire strip…

I think you’re mis-interpetting the spec. It doesn’t say you can only make 1 change with glMaterial per vertex, it says that if you are only making 1 change per vertex it’s preferrable to use glColorMaterial.

What he’s describing really sounds like something you might expect with flat shading. However his code does show smooth shading. Maybe if you’ve got a full project you would be willing to post somewhere, we can download it to see if we get the same results, or try to play with it to fix things.

One other thing to try might be to put the glShadeModel(GL_SMOOTH) just before the rendering… just in case there someplace else in your code changing to flat that you’re not showing.

Changing the material values between a Begin/End pair is not something that is done very often. This doesn’t mean that it is wrong, and it certainly isn’t illegal, but it is usually discouraged for performance reasons.

What I’m getting at here is that since this isn’t such a common case, are you sure this isn’t a driver problem? Have you tried your app with different driver versions / different cards? I think this is something that’s worth trying before you go too crazy…

You mentioned it, but I have to ask anyways. Are you absolutely sure the material colors are what you expect they are?

(A couple of other notes… Unless you’ve enabled ColorMaterial, calls to glColor have no effect as long as lighting is enabled. It’s kind of weird, but it’s the way OpenGL is. Also, flat vs. smooth shading shouldn’t be a problem, since triangles will still be colored differently, assuming the material calls are going through correctly regardless of whether or not you’re using smooth shading.)

– sec

Originally posted by secnuop:
[b] Also, flat vs. smooth shading shouldn’t be a problem, since triangles will still be colored differently, assuming the material calls are going through correctly regardless of whether or not you’re using smooth shading.)

– sec[/b]

With flat shading model, only the material values for one vertex on a triangle will be used for the entire face. In the case of triangle strips, it is vertex i + 2. So if his material properties at every i + 2 is the same, he’s going to get a strip that is the same color throughout regardless of what material properties he uses for the other vertices.

Originally posted by Deiussum:
[b] With flat shading model, only the material values for one vertex on a triangle will be used for the entire face. In the case of triangle strips, it is vertex i + 2. So if his material properties at every i + 2 is the same, he’s going to get a strip that is the same color throughout regardless of what material properties he uses for the other vertices.

[/b]

True. If every third vertex had the same material color the entire strip would be the same color.

I guess I assumed that each vertex would have a semi-unique material color, in which case each triangle would (most likely) be a different color regardless of which shading mode was being used.

[This message has been edited by secnuop (edited 05-10-2002).]

>>With flat shading model, only the >>material values for one vertex on a >>triangle will be used for the entire >>face. In the case of triangle strips, it >>is vertex I + 2.
first of all the shading model is smooth.
second, for a triangle strip the 3 first vertices are of the first triangle and every I vertex after, along with the i-1, i-2 vertices will form the next triangle, therefore even if every i+2 vertex will have the same color, the i, i+1 will form 2 more triangles with different color, and if every i+2 vertex will have the same color then every third triangle will have the same color to my understanding, any how this is not the case, not the shade model and not the color.

Just for clarification, i + 2 in this case meant the 3rd vertex defining one of the triangles in the strip, not every third vertex in the whole stip. Anyway, doesn’t sound like this is your problem.

Errors
GL_INVALID_ENUM is generated if face or mode is not an accepted value.

GL_INVALID_OPERATION is generated if glColorMaterial is executed between
the execution of glBegin and the corresponding execution of glEnd.

thats gl specs

davepermen:
glColorMaterial is not executed between glBegin and glEnd, but before.
between glBegin and glEnd i call glColor4fv.
but it can’t be the issue since i have done it like that and like glMaterialfv without glColorMaterial and i get the same results.

Originally posted by snow_master:
davepermen:
glColorMaterial is not executed between glBegin and glEnd, but before.

Have you called glEnable(GL_COLOR_MATERIAL) anywhere? That’s probably your problem.

Background:

You need to look very closely at p. 53 of the OpenGL 1.3 SPEC.

You have three controls to worry about in setting material parameters.

1st, you can use glMaterial and set them directly yourself. Some implementor’s might prefer that you do so OUTSIDE of begin/end pairs. But it is absolutely permitted by OpenGL to do so within begin/end pairs. (And on some implementations, there will be a cost associated with calling glMaterial within begin/end pairs.)

In your example, where you WISH to change ambient AND diffuse AND specular colors per vertex, you MUST call glMaterial per vertex. Your example is the exception that proves the rule. (The red book advise of “Use glMaterial… when more than a single material property is being varied rapidly” is EXACTLY what you are doing.)

2nd, you can set glColorMaterial to track current color into SOME of your material paramters. By default, it is as though glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) was called. Basically, this is saying WHICH switches on P. 53 you’d like up or down. (For AMBIENT_AND_DIFFUSE, the top two switches can move up, the bottom two stay down.)

FINALLY, you can glEnable(GL_COLOR_MATERIAL) to cause some of the material paramters to continuously track glColor* calls. This is what actually moves some of the switches on P. 53 UP. To swing all the switches on P. 53 DOWN, you call glDisable(GL_COLOR_MATERIAL). (By default it is disabled.)

For your original example to work the way you expect, you must not have called glEnable(GL_COLOR_MATERIAL) or you should call glDisable(GL_COLOR_MATERIAL).

Questions?

What happens to glColor* calls when glDisable(GL_COLOR_MATERIAL) is called and glEnable(GL_LIGHTING)? It sets the current color, but it is not used in lighting equations.

What happens to glMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE) calls when glEnable(GL_COLOR_MATERIAL) and glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE) is called? It’s not an error, but it won’t do anything, and it is not used in lighting equations. The top two switches are UP on P. 53.

What happens to glMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE) calls when glEnable(GL_COLOR_MATERIAL) and glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE) is called?
It’ll set the AMBIENT material properties. (AMBIENT switch is DOWN, DIFFUSE switch is UP.)

-mr. bill

If you can, maybe you should upload the full project somewhere for us to try. It’d be a lot easier to try and debug, and a lot less speculation.