informa
3 min read
Blogs

General cel shader

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

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

 Cel shade(n=2, f=0.8)

n = 2, f = 0.5

 Cel shade (n=2, f=0.5)

n = 3, f = 0.8

 Cel shade (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
CelShade (float a)
{
    return GeneralCelShade (a, 2, 0.8);
}

Latest Jobs

Treyarch

Playa Vista, California
6.20.22
Audio Engineer

Digital Extremes

London, Ontario, Canada
6.20.22
Communications Director

High Moon Studios

Carlsbad, California
6.20.22
Senior Producer

Build a Rocket Boy Games

Edinburgh, Scotland
6.20.22
Lead UI Programmer
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more