# Combine flat and smooth shading with a single model geometry

I need to be able to switch between smooth and flat shading interactively. Is there a way to do this efficiently with a single geometry?

For example, smooth shading does not require duplicate vertices, whereas flat shading does. If I load an arbitrary model, would I need to rebuild the geometry such that each triangle has it's own set of 3 vertices, or is there a better way to accomplish this?

• I recommend you to rephrase the question along the more practical lines of "how to combine flat and smooth shading with single model geometry" – Kromster Nov 12 '14 at 6:11

## 4 Answers

You need two different models, because flat-shaded and smooth-shaded models normals are different.

One of the ways is to generate 2 separate models and replace them with one another on demand.

Another way is to make a single model prepared for flat shaded render (all vertices unique) and replace only normals when switching to flat/smooth shading. For smooth-shaded normals that would mean unnecessary vertices duplication, but you will save memory on overall by keeping vertices/indices single.

Further unification is to store both normals per each vertex (x,y,z,nx1,ny1,nz1,nx2,ny2,nz2) and use required ones using a switch in the shader.

P.S. Smooth-shaded models might still need duplicate vertices along the sharp edges if there are smooth groups and/or smoothing degree threshold and/or discontinuous UVs.

• Hm! I wonder whether we could emulate this with a single flat shaded model, and a normal map that encodes the smooth normals. Swapping between that normal map and a plain blue one would toggle smooth & flat shading with no geometry change, no? – DMGregory Mar 2 '19 at 13:44
• @DMGregory, well, edges and creases won't be so sharp then, right? – Kromster Mar 3 '19 at 5:11
• That's why we start with the flat-shaded geometry, which has the maximum sharpness natively. We can then selectively "opt out" of sharp creases by rendering smooth interpolated blends into the normal map. – DMGregory Mar 3 '19 at 13:16
• @DMGregory I guess you are right. However, generating and adding normals texture and UV coords for it would likely be a bit of an inconvenience. – Kromster Mar 3 '19 at 18:54

One way of doing this is to when you are loading the model and creating the vertex layout. you could calculate a second set of normals. which would be the flat normals. Do so by taking the connecting triangles. and then put it into all the vertices. if there is more than one connecting pollygon, you could insert some indexing to make it easier to handle this. after that you can just switch shader paths.

This is an old question. However, in the interest of others seeking help with a similar problem, I believe I have a plausible solution:

You could have a model prepared for smooth shading (without the duplicate vertices) and present an option of emulating flat shading through your pixel shader. It is possible to calculate the normal at a given pixel by comparing it's position to that of others in its vicinity.

Precisely, a unit vector perpendicular to the surface containing the pixel is the normalized cross product of the partial derivatives of the position with respect to the screen-space x and y coordinates.

In HLSL, the derivatives are represented by the ddx() and ddy() functions:

normal = normalize(cross(ddy(position), ddx(position)));


The GLSL parallels to those should be dFdx() and dFdy().

You can also use "flat" interpolation and adjust your normals so that the first vertex normal of each triangle is appropriate for that particular face. That will likely require rotating your triangles so that each triangle can get a decent normal, and possibly splitting some verts if the only verts available are taken by faces with normals that are too far off.