Problem with GL_FLAT shading

Hi, I have a question about shading. If I compute the face normal of a polygon, and do

glBegin(GL_POLYGON);
glNormal3f(normalx, normaly, normalz);
glVertex3f(x1, y1, z1);
.
.
glVertex3f(xn, yn, zn);
glEnd();  

it doesn’t shade the polygon correctly. Flat shading should not just apply the computed normal to the first vertex to figure out a color for the whole polygon… it should apply it to the geometric average of the vertices of the polygon. Is there a way to do this in openGL? I thought of defining the first vertex as the average of the other vertices but this makes the polygon not proper or something.

Hi !

Yes it should, that’s what flat shading is, what you want is to use GL_SMOOTH shading instead, then you can specify one normal for each vertex.

Mikael

Hi,
thanks for your reply. I know about smooth shading, but I still want flat shading to do the proper thing. flat shading is supposed to compute the color at the center of a polygon, and not at a vertex…

Don’t assume what should or should not happen. Read the spec.

OpenGL specification, section 2.13.7 Flatshading :
A primitive may be flatshaded, meaning that all vertices of the primitive are assigned the same color index or the same primary and secondary colors. These colors are the colors of the vertex that spawned the primitive. For a point, these are the colors associated with the point. For a line segment, they are the colors of the second (final) vertex of the segment. For a polygon, they come from a selected vertex depending on how the polygon was generated. Table 2.9 summarizes the possibilities.

---------------------------------------
|Primitive type of polygon i  | Vertex|
---------------------------------------
|single polygon (i  1)       | 1     |
|triangle strip               | i + 2 |
|triangle fan                 | i + 2 |
|independent triangle         | 3i    |
|quad strip                   | 2i + 2|
|independent quad             | 4i    |
---------------------------------------
Table 2.9: Polygon flatshading color selection.
The colors used for flatshading the ith polygon generated by the indicated Begin/End
type are derived from the current color (if lighting is disabled) in effect when the 
indicated vertex is specified. If lighting is enabled, the colors are produced by 
lighting the indicated vertex. Vertices are numbered 1 through n, where n is the 
number of vertices between the Begin/End pair.

I know what should happen in a regular flat shading algorithm. In ones that we implement ourselves, usually the face normal is found and applied to the geometric center of the polygon, not to one of the vertices. Once the color is found at the geometric center, this color is used for the whole polygon. Applying it to the first vertex gives an incorrect color. I was just wondering how to apply the color to the center of the polygon. it should be something like (vertex 1 + vertex 2 + … + vertex n) / n. In the chart from the specification, for a single polygon it applies the color to vertex 1, and this is incorrect.

As Kehziah posted from the OpenGL spec, OpenGL doesn’t average the normals and use that for flat shading. It picks one of the normals and just uses that. If you want to simulate it using an averaged normal, just assign that averaged normal as the normal for the appropriate vertex of each of your polygons.

I already found the face normal. What should be averaged is the vertices, to find the center of the polygon and find the correct color at the center of the polygon (which is the average of the vertices’ xyz locations).

If you already found the face normal, then just use that for the appropriate vertex (or even all of them) and let OpenGL calculate the color for you…

You are right that you wont get the “correct” flatshading for the triangle if you dont calculate the shading at the center point (if you use an pointlight for example you will get an “incorrect” result even if you pass the correct facenormal to every vertex).

On the other hand, one could argue that flatshading is just a very fast approximation of the true shading, so since its kind of “wrong” anyway it all boils down to a question about the margin of error.

OpenGL uses a pipeline concept to transform and light vertices, meaning that verticies are transformed one after another with no feedback, same goes for the lighting. So if you enable flatshading the rasterizer will pick the color from the first vertex defining the triangle to fill the entire triangle because all information about lights is not available anymore at this stage.

Finding the center point and using that for lighting because its “more correct” or should I say “less incorrect” would simply break the entire pipeline concept OpenGL is based on.

Actually this reminds me of the eternal float vs. double comparision. Both arent exact and never will be, since they are both approximations. Eventhough doubles have a smaller error while sporting a greater range, they are still “wrong”.

If you re-read the bit pasted from the spec above, you’ll note that it is actually the vertex that spawned the item that OpenGL uses to calculate the overall color. That is, the last vertex, not the first, that would define the color for a flat shaded a triangle, line, quad, polygon, etc…

…unless its a “single polygon” enclosed in its own glBegin()/glEnd() block. But right its not always the first vertex, nor is it always the last.

And what difference does that actually make?

well, you’ll end up with a different color depending on which vertex OpenGL decides to use for the flat shaded color.

even if a polygon is nested in its own Begin/End block OpenGL still uses the last vertex sent down to it because this is the vertex that spawned the polygon, right?

I think the correct way to do it has already been mentioned. Use the normal you calculated at the “center” of the polygon and use that normal for each vertex and let OpenGL handle the rest.

Originally posted by lgrosshennig:
[b]…unless its a “single polygon” enclosed in its own glBegin()/glEnd() block. But right its not always the first vertex, nor is it always the last.

And what difference does that actually make?[/b]
It doesn’t make that much difference. It’s just been said in this thread a couple of places already that it was the first vertex that was used, and I was clarifying that it isn’t always, as should be evident if you actually read the bit that was pasted from the OpenGL spec… Although, I suppose you could argue that the original question uses GL_POLYGON and that one does use the first…

Anyway, as I already stated, if you want to use flat shading and don’t want to have to be bothered with reading the spec to figure out which vertex actually is used to calculate the color of the face, just use the same normal for all of the vertices of that face. The only place where you AREN’T going to be able to do this is if you are using strips.

I guess there is no way to implement flat shading using the center of the polygon then? I am well aware of smooth shading but I NEED to have flat shading the way I described it. oh well

Originally posted by cesarsalad:
I guess there is no way to implement flat shading using the center of the polygon then? I am well aware of smooth shading but I NEED to have flat shading the way I described it. oh well
Maybe I’m not quite sure what you are getting at… You have a face normal, which basically means that everywhere on that polygon will have the exact same normal, including your “center of the polygon.” I’m assuming you have lighting turned on since you are using normals, so OpenGL will calculate the color based on the material properties, the normals, and the light properties…

Do you want some other normal calculated for the center of the polygon? If so, calculate it how you want and use that as your face normal.

There is no way to specify one normal per polygon in opengl unless you draw only one polygon at a time. This would be extremely slow for most applications. Another alternative is to use duplicate vertices and duplicate normals for each polygon. This way you can make all 3 normals of the polygon equal to the surface normal of the polygon, without affecting other polygons which share the vertices.

Originally posted by Deiussum:
It doesn’t make that much difference.

I know, the point I was trying to make was, that it doesnt really matter which vertex is elected for the calculation because its just a approximation anyway.

Regards,
LG

Originally posted by Aeluned:
[b]well, you’ll end up with a different color depending on which vertex OpenGL decides to use for the flat shaded color.
even if a polygon is nested in its own Begin/End block OpenGL still uses the last vertex sent down to it because this is the vertex that spawned the polygon, right?

I think the correct way to do it has already been mentioned. Use the normal you calculated at the “center” of the polygon and use that normal for each vertex and let OpenGL handle the rest.[/b]
That is incorrect. If you read the part of the spec that is been posted (or the entire spec) you see that it is the first vertex that is elected for the lighting calculation in case of an single polygon.

AFAIK any implemention is free to re-order verticies as long as the succession order is preserved (so 1-2-3 can become 3-1-2) but thats just a sidenote.

In addition using the center normal for each vertex still gives you “incorrect” values because the light->“elected vertex” vector may differ by some margin from the light->“center vertex” vector.

As I said before, one or another approach may be less “incorrect” than the others, you will never get it “right” though.

Flatshading is a crude approximation, deal with it.

Originally posted by cesarsalad:
I guess there is no way to implement flat shading using the center of the polygon then? I am well aware of smooth shading but I NEED to have flat shading the way I described it. oh well
Unless you subdivide your polygon into a triangle fan and make sure the "center point " is the "i + 2"th vertex in every triangle, I am afraid not.

Perhaps someone else has a better idea.

Regards,
LG

Originally posted by ioquan:
There is no way to specify one normal per polygon in opengl unless you draw only one polygon at a time. This would be extremely slow for most applications. Another alternative is to use duplicate vertices and duplicate normals for each polygon. This way you can make all 3 normals of the polygon equal to the surface normal of the polygon, without affecting other polygons which share the vertices.
Incorrect see above.