PDA

View Full Version : Material colors problem



snow_master
05-08-2002, 10:27 PM
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….)- http://www.opengl.org/discussion_boards/ubb/smile.gif
thanks in advance.

Morglum
05-09-2002, 12:13 AM
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

snow_master
05-09-2002, 12:34 AM
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.

Morglum
05-09-2002, 01:15 AM
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 ?

snow_master
05-09-2002, 03:22 AM
>>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....

Deiussum
05-09-2002, 04:14 AM
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).]

Morglum
05-09-2002, 05:20 AM
I give up. The code you've shown seems to be perfectly correct.

nexusone
05-09-2002, 06:06 AM
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???

http://www.opengl.org/discussion_boards/ubb/smile.gif



Originally posted by snow_master:
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 :

snow_master
05-09-2002, 08:19 AM
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....

nexusone
05-09-2002, 08:37 AM
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....

Deiussum
05-09-2002, 09:08 AM
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.

secnuop
05-09-2002, 02:22 PM
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... http://www.opengl.org/discussion_boards/ubb/smile.gif

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

Deiussum
05-10-2002, 04:47 AM
Originally posted by secnuop:
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

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.

secnuop
05-10-2002, 12:25 PM
Originally posted by Deiussum:
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.



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).]

snow_master
05-12-2002, 02:47 PM
>>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.

Deiussum
05-13-2002, 09:39 AM
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.

davepermen
05-13-2002, 09:46 AM
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

snow_master
05-14-2002, 02:41 AM
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.

mrbill
05-14-2002, 04:42 AM
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_DIFFUS E) calls when glEnable(GL_COLOR_MATERIAL) and glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_D IFFUSE) 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_DIFFUS E) 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

Deiussum
05-14-2002, 04:43 AM
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.

snow_master
05-14-2002, 05:26 AM
mrbil:
Thanks for your detailed explanation.
though, I still get the same results....
if I use glMaterial, and specifically call glDisable(GL_COLOR_MATERIAL), even I never enabled it, I get the entire strip in the color of the last vertex.
if I use glEnable(GL_COLOR_MATERIAL) , and call glColorMaterial with the switches I want to go up, and then call glColor* inside glBegin - glEnd, I get the same results, the entire strip is in the last vertex color.
THE ONLY way I see the strip in different colors is if I turn off the lights (glDisable(GL_LIGHTING)) and then call glColor* between glBegin and glEnd.
Deiussum:
it is a problem for me to upload the code, but I will be happy to mail it to anyone that think he can help.

Old GLman
05-14-2002, 07:36 AM
Hi, I'll take a look, but first I need to be able to read the code http://www.opengl.org/discussion_boards/ubb/biggrin.gif



// 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&amp; 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_DIFF USE , 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;

snow_master
05-14-2002, 07:43 AM
OK, PROBLEM SOLVED.
I thought about it and came to the obvious conclusion this is not a code problem !!!
but I did tested it on two different computers....so I went and checked on the other computer to see what the hardware spec is, and they have ALMOST nothing in common except...you guessed it the same stupid ATI card....so I went to a third computer with a ge-force 3 card and...everything works fine....
my bad I should have checked it in the first place...sorry...
thanks any how to all of you that tried to help.