Toon shader survey

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.

Similar results with ramp texture and step bands.

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.

The sharpness of the bands in the unlit case will depend on your cubemap.

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.

The main light here is colored to distinguish the specular light.

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.

Emission method.

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.

Unfortunately you can’t have the outline as a shader feature, you must create another shader.

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.

You can see how it renders not only outlines but inner lines as well.

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.

I call it quad-art.

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.