Cel (toon) shading
Tags: android, devlog, vrgame, opengles2
Published: 2020-08-09 09:01:09

# Starting with Phong Lighting
The beginnings of toon shading is implementing normal phong lighting, for this I followed [this tutorial](https://learnopengl.com/Lighting/Basic-Lighting) to add ambient, diffuse and specular lighting components to the <code>AbstractGameObject</code> shaders. 
Before adding the shading I imported a toroid model to the scene as this was curved and would show off the lighting quite nicely, prior to any lighting this looked like:
![toroid prior to shading](https://dev-to-uploads.s3.amazonaws.com/i/be9md34iro01sei1ir8b.png)

## Ambient
This is a minimum lighting that all pixels of a model will be subject to, initially I have set this to 0.3. 

## Diffuse
This is the lighting that hits a point on the model and is reflected in all directions, adding this gives a more realistic 3D shading effect especially on curved models.
The amount of diffuse lighting (<code>fDiffuse</code>) is calculated to be a value between 0.0 and 1.0 which is multiplied by the light colour.

## Specular
This lighting is the light reflected from the source, off the model and directly at the camera. 
The amount of specular lighting (<code>fSpecular</code>) is calculated to be a value between 0.0 and 1.0 which is multiplied by the light colour and the specular strength which I have set to 0.5 for now.

Applying these 3 lighting components produced a "realistic" looking toroid: 
![Toroid with Phong lighting](https://dev-to-uploads.s3.amazonaws.com/i/xud0re90tfhvcaxerrwi.png)
One issue with this is the fact that the lower half of the toroid is illuminated despite the fact that the upper half is between it and the light source directly above, I may look at this in future if I implement shadow maps.

# Toon shading
Toon shading starts as phong shading, the only difference is that the calculated <code>fDiffuse</code> and <code>fSpecular</code> values are set to one of a finite number of levels.
To do this we calculate which level the value belongs to by multiplying it by the number of levels and flooring that value, once we have the level number we multiply that by the step change per level which is done by dividing by the number of levels, to simplify the process of applying this conversion I created a small function in the fragment shader which took in an intensity value and a number of levels and returned the resulting toon shading level, by adding  the number of levels to the function parameters I can easily have more or less levels for either the <code>fDiffuse</code> or <code>fSpecular</code> values if needed, although for now I have kept them the same.

![toonify function](https://dev-to-uploads.s3.amazonaws.com/i/ib6di56mg3qb676i0tnp.PNG)

One thing to note is I needed to change the fragment shaders float precision from <code>mediump</code> to <code>highp</code> to get the floor function to work. 

Initially, I set the number of levels for both values to 3 and got this effect:
![toon 3](https://dev-to-uploads.s3.amazonaws.com/i/3pdk22iu0l9pz496o8on.png)

Changing the number of levels for both values to 10 give a completely different effect which I think is too far.
![toon 10](https://dev-to-uploads.s3.amazonaws.com/i/vxtlpkhl7lndd3lyts3u.png)

Reducing the number of levels to 5 gives a better effect but not quite what I am going for.
![toon 5](https://dev-to-uploads.s3.amazonaws.com/i/e47qlpzn4p6ju0rfabid.png)

Finally I decided on 4 levels which gives a nice compromise, as the value for number of levels is a float, I could set the number of levels to 3.5 etc but I think 4 is a good round value to start. 
![toon 4](https://dev-to-uploads.s3.amazonaws.com/i/4ekexffuuz9vx26bmfg0.png)

# Conclusion
Toon shading is a relatively simple change from standard Phong lighting techniques and provides a nice effect, Whether it is the final shading style that I go for is still to be decided.

The source code for this project at this point can be found [here](https://github.com/longevity-software/AndroidVrGameDemo/releases/tag/B1.6).