PDA

View Full Version : Problem with GL_FLAT shading



cesarsalad
10-25-2004, 08:41 PM
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.

mikael_aronsson
10-25-2004, 09:59 PM
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

cesarsalad
10-25-2004, 10:24 PM
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...

kehziah
10-26-2004, 04:26 AM
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.

cesarsalad
10-26-2004, 09:20 AM
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.

Deiussum
10-26-2004, 09:55 AM
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.

cesarsalad
10-26-2004, 11:57 AM
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).

Deiussum
10-26-2004, 12:20 PM
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...

lgrosshennig
10-26-2004, 01:41 PM
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".

Deiussum
10-27-2004, 04:40 AM
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...

lgrosshennig
10-27-2004, 09:42 AM
...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?

Aeluned
10-27-2004, 09:56 AM
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.

Deiussum
10-27-2004, 11:10 AM
Originally posted by lgrosshennig:
...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?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.

cesarsalad
10-27-2004, 05:43 PM
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

Deiussum
10-28-2004, 04:45 AM
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 wellMaybe 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.

ioquan
10-28-2004, 10:24 AM
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.

lgrosshennig
10-29-2004, 12:03 PM
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

lgrosshennig
10-29-2004, 12:24 PM
Originally posted by Aeluned:
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.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.

lgrosshennig
10-29-2004, 12:36 PM
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 wellUnless 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

lgrosshennig
10-29-2004, 01:21 PM
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.

ioquan
11-05-2004, 10:51 AM
no, that is not incorrect. It is the answer to his question, which everyone else failed to give.

GL_FLAT_SHADING is not what he wants, though he though it was. He just wants to shade polygons using the surface normal of the polygon to determine the light color instead of using the 3 vertex normals.

The way to accomplish this in OpenGL is to use duplicate vertices and normals so that each polygon has its own set of normals, and then to make all 3 normals for the polygon equal to the surface normal of the polygon.

Aeluned
11-05-2004, 12:09 PM
right. which is what i said about 9 posts ago, in reference to what someone else said a bunch of posts ago.

use the surface normal for all 3 vertices...what's the problem here?

lgrosshennig
11-05-2004, 03:07 PM
*sigh*

Because for certain lighting calculations the position of the "to be lit" vertex and its associated normal is important, especially for bigger polygons.

Spot direction, spot cut off and quadratic attenuation if any of that rings a bell.

If you follow cesarsalad post's this is exactly what he is complaining about, assigning the surface normal to all verticies only works for simple directional lighting and hence is the given advice incorrect.

Besides, if you look at the code example he gave in his very first post, he already specifies the normal _before_ the verticies, so that normal will be used for all the following verticies.

I am not sure what exactly he is doing but if he says he needs the lighting the way he descriped, I believe he has his reasons.

Cheers!

MikeC
11-05-2004, 04:23 PM
Originally posted by lgrosshennig:
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.I agree; this is the only way to get the result the OP wants.

Though for a mesh of any size I suspect that GL_TRIANGLES would be better than GL_TRIANGLE_FAN; you'd be sending more data to GL, but you'd have the same number of verts (assuming indexing), the pattern would be pretty vertex-cache-friendly and you'd get far more efficient batching.

Edit: plus GL_TRIANGLE_FAN couldn't work, because the centre vertex is only issued once. I guess you were speaking loosely. Which makes this post somewhat redundant. Oh well.

lgrosshennig
11-05-2004, 05:35 PM
Originally posted by MikeC:
I agree; this is the only way to get the result the OP wants.

Though for a mesh of any size I suspect that GL_TRIANGLES would be better than GL_TRIANGLE_FAN; you'd be sending more data to GL, but you'd have the same number of verts (assuming indexing), the pattern would be pretty vertex-cache-friendly and you'd get far more efficient batching.

Edit: plus GL_TRIANGLE_FAN couldn't work, because the centre vertex is only issued once. I guess you were speaking loosely. Which makes this post somewhat redundant. Oh well.[/QB]Agreed :) . I was thinking of an triangle fan first because it was the first plausible thing that came to mind but you are right, you need independent triangles (which share verticies using indexing) and locate the "center point" at 3i.

It dosent change the idea behind it though, just the implementation.

Thanks for pointing it out.

dorbie
11-07-2004, 03:08 PM
Flat shading in OpenGL is not exclusively about normals it is also about the interpolation of per vertex values.

With flat shading the last color value or lighting result calculated before (or with) the last vertex is the color used across the whole triangle.

If you want a 'faceted' appearance with correct lighting per vertex then you should specify the same normal for each triangle vertex and keep smooth shading on. The only problem with this is you won't be able to use meshed primitives for the facets, but GL_TRIANGLES would probably be the method of choice.

lgrosshennig
11-08-2004, 03:37 PM
Originally posted by dorbie:
Flat shading in OpenGL is not exclusively about normals it is also about the interpolation of per vertex values.Excuse me? In flat shading there is no color interpolation going on (unless you count an increment of ZERO for all color channels as an increment). Depending on the primitive, one of the specified verticies will be lit and colored and that color will be substituted for the entire polygon. This is not what the OP wants though, he wants the "center" of a polygon to be lit and colored.


Originally posted by dorbie:
With flat shading the last color value or lighting result calculated before (or with) the last vertex is the color used across the whole triangle.
Or the first one in case of an single polygon, if you check the piece of spec thats being posted.


Originally posted by dorbie:
If you want a 'faceted' appearance with correct lighting per vertex then you should specify the same normal for each triangle vertex and keep smooth shading on.
Ok, its obvious now that you havent even read the thread or know what the OP desires.


Originally posted by dorbie:
The only problem with this is you won't be able to use meshed primitives for the facets, but GL_TRIANGLES would probably be the method of choice.Congrats to come to the only logical conclusion left over.

Cheers!