Where smooth shading comes from

Normal averaging lab

A polygon mesh has one true normal per face. Smooth shading is not a different mesh — it is the same mesh handed different normals. Drag the averaging slider to blend each face normal into the average of the faces meeting at that vertex, and watch the facets disappear without a single triangle being added.

Mesh
Drag to rotate
face normal (one per triangle) vertex normal (averaged) split by crease angle
Averaging flat
face normal 0.00 averaged

At 0 every corner of a triangle carries that triangle's own normal, so interpolation has nothing to interpolate and the face renders flat. At 1 the corners share the averaged normal of every face meeting there, so the shading runs continuously across the edge.

One shared vertex, close up live

Two faces meet at a vertex. The averaged normal is the normalised sum of the face normals — it belongs to neither face, which is exactly why the shading stops agreeing with the geometry and starts looking curved.

Triangles
Positions
Distinct normals
Creased edges
Geometry
10
80°

Faces meeting at a sharper angle than the crease threshold are not averaged together. That is what keeps a cube's edges crisp while a sphere of the same code goes smooth.

Lighting
-38°
42°
36
Overlays
What this means in code
Flat and smooth shading differ only in what you pass to glNormal3f. Emit one normal before a whole face and every vertex of that face shares it, giving flat shading. Emit a different, averaged normal before each glVertex3f and OpenGL interpolates the resulting vertex colours across the triangle, giving smooth shading. The vertex positions are identical in both cases — which is why raising the segment count above eventually makes flat shading converge on smooth anyway, at a far higher triangle cost.