# General cel shader

General cel shader used in Labyrinthica: The quest of lima.

Ofer Rubinstein

September 17, 2009

Hello,
In a new development blog at www.pompidev.net, I will be making posts relating game development.
I wish to share with you the post about genereal cel shader used in labyrinthica.
The code in this post might be useful for some people.

Labyrinthica features cel shaded graphics.

On the most simplistic level shading is taking a color value from the surface's texture and multiply it by an intensity scalar, which is based on how the light source affect the surface.
The scalar value is usually a floating point that goes from 0 to an unbounded positive number.
In cel shading, we want to quantize this scalar into non continuous values.

The general cel shader is a piece of code that quantize the intensity scalar. The parameters to the function are:
a - The original intensity scalar.
n - The number of quantization cels.
f - The cel transaction factor.
Return value = The quantized intensity scalar.

There are actually n+1 cel levels, the additional cel level is for intensity values greater than 1.
I will not explain the shader in details. I hope the code will be clear enough for people to understand on their own. Though I could explain it in more details if there will be a demand.
A few screen shots with different parameter values:

n = 2, f = 0.8

n = 2, f = 0.5

n = 3, f = 0.8

One last word before the code. My older CelShade function got only one parameter, the intensity.
I made the new CelShade with 3 paramters, but then I saw I would need to update every place I called the function.
Instead I have created GeneralCelShade as the function with 3 parameters, and replaced the old function with a function that calls GeneralCelShade with appropriate parameters.
The bonus is that now changing the parameters in only one place affect the whole game/shaders.
Very simple, yet very useful.

Quantize (float a, float n)
{
return floor(a*n)+1.;
}

float
Trunc (float c, float f)
{
return (c>f)*(c-f)/(1.-f);
}

float
SubCel (float a, float n, float f)
{
float q = Quantize(a, n);
float c = q-a*n;
return (q>1.)*Trunc(c, f)/n;
}

float
GeneralCelShade (float a, float n, float f)
{
float c = Quantize(a, n)/n;
a = c-SubCel (a, n, f);
a = min (a, (n+1)/n)*(3./2.)/((n+1)/n);
return a;
}

float