home / blog / graphics
Published: 24 January 2026 9 min read graphics
Stylised lighting: beyond cel shading

Stylised lighting: beyond cel shading

Banded shadows are the first step everyone knows. The real character lives in the rim light and in how you pick the shadow colour.

Banding is not enough

When people say toon shader, the first thing they think of is rounding light intensity into a few steps. On its own that gives a cheap look; your scene reads as low quality rather than as a cartoon.

What makes the difference is which colours those steps land on. Push the shadow towards the complement of the light instead of towards black, and the scene suddenly looks art-directed.

Rim light saves the silhouette

In stylised scenes objects tend to disappear into the background because there is so little shading detail. Rim light is therefore not decoration, it is a functional tool.

If you scale rim strength by camera distance, distant objects stop over-glowing. A small multiplier makes a big difference.

Measure the cost

The assumption that stylised shaders are cheap is wrong. Multi-layer rim, outlines and custom shadow maths can end up more expensive than PBR.

I measure every shader variant in RenderDoc and write the GPU cost into the documentation. When the art team can see the budget, they make better decisions.

ToonLit.hlsl
half3 ToonShade(half3 albedo, half3 N, half3 L, half3 lightColor) { half ndl = dot(N, L) * 0.5h + 0.5h; half band = floor(ndl * _Steps) / _Steps; half rim = pow(1.0h - saturate(dot(N, _ViewDir)), _RimPower); return albedo * lightColor * band + _RimColor * rim; }
hlslToonLit.hlsl

Consistency is everything

Every material in the scene must share the same lighting model. A single PBR object breaks the coherence of a stylised scene.

That is why I write a shared lighting function and have every shader call it. Change the model once and the whole scene changes with it.

← All posts