Toon shader survey
2019-12-13
Everybody loves a nice toon shader. They give this timeless magic look that doesn't rely on realism nor fancy lightning.
For the past weeks I've going trough many iterations in my search for the uber shader, here I bring you my findings. From implementation details to aesthetic choices, there is a vast array of decisions you'll have to take. Here's a (non-exhaustive) list of them.
All references and implementations are done in Unity, but are easily transferable to other engines. This is not a tutorial on how to implement a toon shader, more of a collection of toon shader tutorials and references.
Ramp texture vs Step
The essence of toon shaders is how they apply the light. By grouping the light into bands they provide that characteristic look. There are two main ways of doing this.
Either use N · L
to sample a ramp texture, or
use the step
function to band the light.
Both of these are roughly equivalent, with the ramp texture giving more control at a slightly higher cost, while the step is slightly cheaper, but can only do proportional bands.
Unlit vs Lit
Whether you have none or a ton, lights are crucial for the look of your game. Unity standard assets has an unlit toon shader, it simply uses a cubemap to light the object. It is pretty good, as it looks like there is a static light while there may be none.
Ronja has a tutorial with support for multiple lights, it is a bit more complex, but you could get even more fancy if you wish to support things like vertex lights or Spherical Harmonics.
Specular
Metallic objects have another source of light, specular, that's when the light reflects "straight" to you eyes. I had never thought of doing specular lighting in a toon shader until I saw Roystan's tutorial.
Turns out it can look pretty good on metallic objects.
Fresnel
Rim light looks really nice. If it fits the aesthetic, try using it. I followed Roystan tutorial for that.
Colored Shadow
Sometimes you don't want your shadows to be pitch black. Ronja
shows how to use the Emission property of surface shaders to have a shadow color.
If your shader is not a surface shader (for example if you are doing the unlit
version), you could always do something like multiplying the shadow color by
the inverse of N · L
.
You could also set the shadow color using the environmental light.
Outline
We have arrived to the extras, rendering an outline is such a common effect on toon shaders that it comes with the Unity standard assets. It simply adds a pass where only the backface triangles are rendered, while also displacing them along the normals.
Edge Detection
This one is a bit different from outline, I read it from Harry Alisavakis, the result being similar to the last one, but it uses the camera dept hand normals texture.
This one is a bit finnicky, it took me some time to adapt this from a screen image effect, and I'm not 100% happy with the result. Roystan also has an edge detection post process tutorial, but I haven't tried that one.
Vertex Color
I admit it. When I'm doing models prototype them with vertex colors. I should probably use textures, but for quick drafts inside unity, this method is so much faster. So I tend to add support for using the vertex color as part of the final color.
This is optional, like everything else, put this behind a shader_feature
,
just be aware, the method for getting the vertex color is different in vertex
and surface shaders.
Putting it all together
Using these two (lit & unlit) "uber" shaders I did this.
There are no textures here, just a point light, and the shaders (Can you spot where the unlit material is used?). I also have a bit of fog and light flickering.
If you wish to grab the shaders, I put them in a gist. I also encourage you to experiment and improve on them.
That all for today, thanks for reading this tutorial. And if you want more, follow me at @alvarber.