Cel shading (also known as toon shading) is a form of non-photorealistic rendering (NPR) used in films and video games to create a cartoon-like visual style. Some of the best-known games that make use of this technique include The Legend of Zelda, Prince of Persia, and Borderlands:
Generally speaking, there is no single "correct" way to implement this technique, and every project adopts its own approach. That said, most toon shading implementations consist of three main components:
In this article, we'll focus only on the last two. Model preparation is not a programming task—it falls under the responsibility of artists, technical artists, and art directors. As in the other computer graphics articles on this site, we'll use Unity Engine so that we don't have to spend time on problems that have already been solved countless times, such as loading textures or accessing the scene depth buffer.
Let's start from the beginning. Consider the most basic lighting model used in computer graphics: Lambertian shading. As is well known, the illumination of a point is calculated using a very simple principle: the larger the angle between the surface normal and the direction from the point to the light source, the less illuminated that point on the surface is.
Below is a fragment shader that computes lighting according to the Lambertian model, along with the resulting image. In the following sections, we will modify this shader step by step to achieve the desired toon shading effect.
fixed4 frag(fragment_data i) :COLOR
{
float3 L = normalize(_WorldSpaceLightPos0 - i.pos_world);
float3 N = normalize(i.normal);
float lambert = max(dot(L, N) + _Ambient, 0.0);
float3 color = tex2D(_DiffTex, i.uv);
return float4(color * lambert, 1.0);
}