I want to render a model using flat shading with per triangle normals and VBOs. However, VBOs do not support per triangle values. My model is dynamic, so this rules out using display lists.
I’m thinking of doing this. For each triangle, create an extra vertex which has the same position as the triangle’s first vertex. The normal corresponding to this vertex will store the face normal for the triangle, and other normals will have dummy values. If I’m not mistaken, for flat shading, only the normal of the first vertex is read. Then, I’ll render using GL_QUADS. Will this method work? Visually, there should be no difference between a straightforward immediate mode method for flat shading right?
Also, I’ll be glad to hear any alternatives.
You can see this: http://www.opengl.org/sdk/docs/man3/xhtml/glProvokingVertex.xml
I think it’s what you search !
If you still want vertex sharing for your triangles and don’t want to implemented complex manipulation of your source geometry, I recommend calculating the face normals on the fly in the fragment shader as shown here:
Here’s an example of an ideal use for the geometry shader. I read skynet’s comment in his link above that with his graphics card, though, he can calculate the face normals per pixel faster than calculating them once per triangle in the geometry shader. That’s mind boggling (unless your triangles are all really tiny). It makes me wonder if the GF8800GTS graphics card implements the geometry shader in the driver on the CPU with software emulation rather than with hardware in the GPU. That’s one horribly bad implementation of a geometry shader in the GF8800GTS (not skynet’s fault, that’s nVidia’s fault).
Back to the original post, another way to accomplish the goal is to use a texture map that contains the face normal’s X, Y, Z, coordinates in the texel’s RGB components. One texel per triangle. You’d have to rotate each normal, though, same as the model. No need to normalize anything, at least. Should be able to do it all in the vertex shader.
Logically, the cleanest approach is to use the geometry shader, but if skynet’s issue exists with your hardware and driver, then doing it in the fragment shader would be best.
That’s one horribly bad implementation of a geometry shader in the GF8800GTS (not skynet’s fault, that’s nVidia’s fault).
To be fair though, nobody ever claimed GS’s were particularly fast.
Thanks for all the suggestions. Unfortunately I haven’t learnt shader programming yet, so I can only rely on plain OpenGL.