Toon Shading for 2D Sprites v1

This is a shader that mimics toon or cell shading with 2D sprites and Light2D. Azagaya from Laigter gave me his version of a toon shader to work with and I modified it to include multiple levels and setting of light ranges.

It has its limits and I am positive this code could be done better so please contact me know if you update it in your own projects. I would love to use a refined version. I hope you find it useful!

More info:
Leaving level_2 set to 0 will put the shader into 2 tone mode which will ignore the level_2_smoothing and mid_light settings. When using level_2, you do not need to set a mid_light unless you want to. It defaults to midway between max and min light.

Shader code
shader_type canvas_item;

uniform float level_1 : hint_range(0.0, 1.0) = 0.5; 
uniform float level_1_smoothing : hint_range(0.0, 1.0) = 0.03; // Lengthens the color transition
uniform float level_2 : hint_range(0.0, 1.0) = 0.0;   // If left at 0, only level 1 is used.
uniform float level_2_smoothing : hint_range(0.0, 1.0) = 0.03;
uniform float min_light : hint_range(0.0, 1.0) = 0.0;
uniform float mid_light : hint_range(0.0, 1.0) = 0.0; // If left at 0 it defaults to calculating between min and max.
uniform float max_light : hint_range(0.0, 1.0) = 1.0;

void light() {
	float nl = -dot(normalize(vec3(LIGHT_VEC,-LIGHT_HEIGHT)), NORMAL);
	float diff = max(nl, 0.0)*LIGHT_COLOR.a;
	float mid_range_light = mid_light;
	if (mid_light == 0.0) { mid_range_light = (max_light * 0.66) + (min_light * 0.33); }
	if (level_1 != 0.0 && level_2 == 0.0) {
		diff = smoothstep(level_1, (level_1 + level_1_smoothing), diff) + min_light;
		if (diff == 0.0) { diff = min_light; } else if (diff >= 1.0 || diff > max_light) { diff = max_light; }
	} else if (level_1 != 0.0 && level_2 != 0.0) {
		if (diff <= level_1) { 
			diff = smoothstep((level_1 - level_1_smoothing), level_1, diff) + min_light;
			if (diff == 0.0) { diff = min_light; } 
			if (diff > mid_range_light) { diff = mid_range_light; }
		} else if (diff > level_2) {
			diff = smoothstep(level_2, (level_2 + level_2_smoothing), diff) + (mid_range_light);
			if (diff < mid_range_light) { diff = mid_range_light; }
			if (diff >= 1.0 || diff >= max_light) { diff = max_light; }
		} else {
			diff = mid_range_light;
		} 
	} 
	LIGHT_VEC = -NORMAL.xy*length(LIGHT_VEC); 
	LIGHT_COLOR = diff*LIGHT_COLOR;
	LIGHT = LIGHT;
}
Tags
cel, shader, toon
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from MightyMochiGames

2D Cel / Toon Shader v2 +Plus

2D Cel / Toon Shader v2 (Basic)

2D Light Z-Depth

Related shaders

Line pattern cell shading

Glitchy Sprites

Toon Shader for Godot 4

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Grandpa_Pit
2 years ago

Great!