The lighting model

In lines 68-91, I define the lighting model for the cel-shading, and here’s where things get exciting.

First of all, the name of the method should be “LightingCelShaded” because I mentioned in the #pragma above that the lighting model will be called “CelShaded”. The parameters of the method are:

A SurfaceOutputCelShaded struct object.

The light direction.

The view direction.

The light attenuation.

Starting up, in lines 69-70 I calculate the lighting based on the object’s normals and the light direction. I first calculate the classic N•L which I then modify in line 70. I first divide the result of the N•L value by “_LightCutoff” to adjust the area of the lit surface, then multiply the result by the number of shadow bands we want, round the result and divide it by the number of shadow bands. So, if we were to use 4 bands, we’d first multiply the N•L by 4 (so it’s now in the [0,4] spectrum), round it (so the values we get are either 0,1,2,3 or 4) and divide it again by 4 so that the resulting values are either 0, 0.25, 0.5, 0.75 or 1.

In lines 72-74 I calculate the specular highlights of the material. First, in line 72, I get the direction in which the light hitting the object’s surface would be reflected, using the handy “reflect” method. Then I get the dot product of the view direction and the inverted reflection vector and I use the inverted “Smoothness” value of the struct object as a threshold for the resulting dot product. The whole thing is multiplied by the specular color to be used in the final color result.

In line 76, I calculate the rim color. I get the inverted fresnel value by subtracting the dot product of the view direction and the object’s normals from 1, then I use the inverted value of “_RimSize” as a threshold for the step method and multiply the whole thing by “_RimColor” to use it later.

In lines 78-79 I just round the attenuation value (so it’s either 0 or 1) and then make a “shadow” field which is made up by multiplying the rounded attenuation value with the shading value calculated in line 70.

In line 81, I calculate the main color by adding the specular color to the albedo and multiplying the whole thing by “_LightColor0”. This will basically multiply the color of the object with the color of the light that’s affecting the object, whether that’s a directional light or otherwise. There’s no limit on the lights affecting the objects on the shader, just the pixel lights limit of your project.

Finally, in lines 84-88 I assign the final color to the RGB channels of “c”. If the “SHADOWED_RIM” keyword has been enabled, the rim color is added to the main color before the whole thing is multiplied by the shadow value, so there’s no rim lighting on the dark areas of the model. Otherwise, the rim is added after the main color is multiplied by shadow, so it’s added on top.