Smooth vs. flat shading

스무스 vs 플랫 셰이딩

Given the same geometry, choosing whether the shading blends normals smoothly per vertex, or keeps them flat per face.

Also known as: Vertex normal smoothingFace-normal shading
···
html
<div class="sub-caps"><span>flat shading</span><span>smooth shading</span></div>
css
.sub-caps{position:absolute;left:0;right:0;bottom:6%;display:flex;justify-content:space-around;font-size:clamp(8px,2.4vmin,12px);color:#dfe3ffcc;text-align:center;padding:0 3%}
js
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b0b14);
const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
camera.position.set(0, 0.5, 6.2);

const flat = new THREE.Mesh(
  new THREE.IcosahedronGeometry(1.05, 1),
  new THREE.MeshStandardMaterial({ color: 0xffb648, flatShading: true, roughness: 0.5 })
);
flat.position.x = -1.7;
const smoothGeo = new THREE.IcosahedronGeometry(1.05, 1);
smoothGeo.computeVertexNormals();
const smooth = new THREE.Mesh(smoothGeo, new THREE.MeshStandardMaterial({ color: 0x8ecbff, flatShading: false, roughness: 0.5 }));
smooth.position.x = 1.7;
scene.add(flat, smooth);
const key = new THREE.DirectionalLight(0xffffff, 1.8); key.position.set(3, 4, 5); scene.add(key);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));

function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const r = t * 0.00025;
  flat.rotation.set(r * 0.5, r, 0);
  smooth.rotation.copy(flat.rotation);
  camera.lookAt(0, 0, 0);
  renderer.render(scene, camera);
});

Every face carries its own normal — the direction it points. Flat shading uses that value as-is, painting one whole face a single brightness, which is why the result shows sharp, visible polygon edges. Smooth shading averages the normals of every face sharing a vertex at that vertex, then interpolates brightness gradually across face boundaries — so the surface reads as continuously curved even though the polygon count hasn’t changed at all.

The key point: the vertex and face count never change — shading is purely a question of how the same shape gets painted. That’s why a low-poly sphere with smooth shading looks smooth in the middle of a face but still shows its faceted silhouette at the edges, and up close reads as “fake round.”

Blender switches this with Shade Smooth/Shade Flat in the object right-click menu, Maya with Soften/Harden Edge, and C4D with a Phong tag. All three also support applying it per-edge (keeping specific edges sharp), so a rounded body can carry crisp detail without needing subdivision at all.

When to use

Use smooth when a low-poly shape needs to read as curved; use flat when a hard-surface or low-poly look is the intent.