Flat lighting shader

Godot Version

4.6.1

Question

Hello! I’ve been playing around with cel shaders in Godot but I’m hitting a barrier with an issue I’m running into. I want to create a shader that masks the lit area of an object and applies one color to the highlight and another color to the shadow. My main goal is for the object to only have three flat colors in it (each one color picked with a specific vec3) and apart from drawing the shadow and highlights, be completely unaffected by light. Something like this:

I’m still a beginner with Godot, so I haven’t figured out the best way to go about this. So far, I’ve tried using cel shading and a fesnel mask to create the highlight. It’s not the effect I’m going for, though, so any advice would be appreciated. Here is my current code:

shader_type spatial;
render_mode blend_mix,depth_draw_opaque,diffuse_toon,specular_toon;
uniform int bands : hint_range(2, 8) = 3;

uniform sampler2D mask_map;
uniform sampler2D normal_map : hint_normal;

//create rim lighting
float fresnel(float amount, vec3 normal, vec3 view)
{
	return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), amount);
}

void light() {
	//cel shading
	float NdotL = max(dot(NORMAL, LIGHT), 0.0);
	float lit_intensity=smoothstep(0.0,0.5,NdotL*ATTENUATION);
	vec3 light_col=lit_intensity * LIGHT_COLOR / PI;
	
	//shadow custom color
	vec3 shadow_col=vec3(0.0);
	{
		shadow_col=vec3(0.922,0.439,0.004);	
	}
	vec3 _shadow_col=shadow_col/ALBEDO;
	
	
	if (LIGHT_IS_DIRECTIONAL)
		DIFFUSE_LIGHT+=mix(_shadow_col,light_col,smoothstep(0.01,1.0,lit_intensity));
	else
		DIFFUSE_LIGHT+=mix(_shadow_col,light_col,smoothstep(0.01,1.0,lit_intensity))*ATTENUATION;
		
		
}
void fragment() {
	float normal_strength = 2.0;
	float fresnel_mask = fresnel(2, NORMAL,VIEW);
	vec3 base_color = vec3(0.992,0.647,0.004);
	vec3 rim_color = vec3(0.976,0.765,0.153);
	ALBEDO = mix(base_color,rim_color, fresnel_mask);
	NORMAL = texture(normal_map, UV).rgb* normal_strength;
}



It’s definitely pretty rough lol I’ve been frankensteining pieces of shaders I’ve found in tutorials but I’m not sure how best to proceed in improving this.

Isn’t that exactly what built-in toon shader does?

What does it look like right now? show us a screenshot with a lit sphere with your shader.
There are some toon shader examples on godotshaders that you can use as reference.

The problem I’m running into with the built in toon shader is that I want to be able to mask the hard and shadow areas to be a specific color, not just a darkened or lightened version of the albedo. And I want that to remain the same regardless of the lighting situation.

Did you think to use unshaded if you want to keep it the same and unaffected by light?

How should the thing behave in the case of multiple lights? Can you make a mockup of that, including cast shadows?