7

I'm trying to figure out how to properly implement flat shading for meshes containing non-planar polygons (using OpenGL/GLSL). The aim is to obtain something similar to the result Blender gives (all polygons below are non-planar):

enter image description here

To provide a bit of context — the non-planar polygons (e.g. quads, pentagons, ...) are either present in the mesh I load or appear as a result of applying a subdivision scheme (such as Catmull-Clark) to the mesh.

In case of a triangle mesh, I'm aware of the following approaches to implement flat shading —

  1. Compute the cross product of dFdx and dFdy in the fragment shader
  2. Use the geometry shader to compute the triangle normal by taking the cross product of two sides of the triangle
  3. When using glDrawElements, use the flat interpolation qualifier (which basically uses the normal associated with the provoking vertex for all fragments)
  4. When using glDrawArrays, most vertices (usually all of them) are copied to the GPU multiple times. Therefore, a different normal can be used each time

For a mesh containing non-planar polygons the first three options don't yield the result I'm after. In my implementation (using the Qt framework) I use GL_TRIANGLE_FAN:

enter image description here

The fourth option could work, but isn't very elegant — I'd like to use either glDrawElements or glDrawMultiElements. One other option would be to use glDrawElements while looping over the faces one by one (instead of invoking it once using glPrimitiveRestartIndex). In that case, one could upload a uniform normal for each face. However, this does not seem very efficient. Any other ideas?

Ailurus
  • 171
  • 3

1 Answers1

7

Without knowing the internals of Blender, I would say it uses shared normals for the quads, splitting the normals only on edges between the quads, not between the triangles. So your idea of uploading a normal per quad is probably close to the result you are looking for.

If you load the mesh as quads, you are set. If you are using an old version of OpenGL where quads still exist, you may even be able to use solution 3).

If you load the mesh as triangles, you will have to figure out which triangles originated in quads. You can likely do this simply by enforcing split normals beyond a fixed angle between adjacent triangles.

I am not sure there is a simple dynamic solution, where you just render any mesh. You may be able to use the geometry shader to look at the adjacent vertices, but the easiest version is to smooth the normals once before upload.

Mikkel Gjoel
  • 471
  • 2
  • 4