Skip to content

Instantly share code, notes, and snippets.

@jwosty
Created April 19, 2026 06:26
Show Gist options
  • Select an option

  • Save jwosty/f65a83237d249c93374cdcf630d7b941 to your computer and use it in GitHub Desktop.

Select an option

Save jwosty/f65a83237d249c93374cdcf630d7b941 to your computer and use it in GitHub Desktop.
Simple toon shading lighting model used in Sheep, Inc.
float Quantize(float value, float n) {
return n <= 0 ? value : floor((value*(n-1.0))+0.5)/(n-1.0);
}
float3 Quantize(float3 value, float n) {
return float3(Quantize(value.x,n), Quantize(value.y,n), Quantize(value.z,n));
}
/**
* Lighting contribution of a single directional light source via Phong illumination.
*
* The vec3 returned is the RGB color of the light's contribution.
*
* k_a: Ambient color
* k_d: Diffuse color
* k_s: Specular color
* alpha: Shininess coefficient
* p: position of point being lit
* V: vector from the point being lit to the camera (`normalize(eye - p)` for perspective proj, or `-cameraForward` for orthographic proj)
* lightDir: the direction of the light
* lightIntensity: color/intensity of the light
* lightNormQuantization: a number representing the desired descrete levels to quantize the lighting into
*
* See https://en.wikipedia.org/wiki/Phong_reflection_model#Description
*/
#define phongContribForDirLight(/* float3 */ n, /* out float3 */ result, /* float3 */ k_d, /* float3 */ k_s, /* float */ alpha, /* float3 */ p, /* float3 */ V, /* float3 */ lightDir, /* float3 */ lightIntensity, /* float */ lightNormQuantization) { \
float3 N = n; \
float3 L = -lightDir; \
float3 R = normalize(reflect(-L, N)); \
/* Quantizing these vectors instead of output light values (or even colors later) gives a proper cel-shading effect */ \
float dotLN = Quantize(clamp(dot(L, N), 0.0, 1.0), lightNormQuantization); \
float dotRV = Quantize(dot(R, V), lightNormQuantization); \
if (dotLN < 0.0) { \
/* Light not visible from this point on the surface */ \
result = float3(0.0, 0.0, 0.0); \
} else if (dotRV < 0.0) { \
/* Light reflection in opposite direction as viewer, apply only diffuse component */ \
result = lightIntensity * (k_d * dotLN); \
} else { \
result = lightIntensity * (k_d * dotLN + k_s * pow(dotRV, alpha)); \
} \
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment