Toon Shader

Godot 4

 

Toon shader which uses the light function.

Shader code
/*
	Toon Shader by Firerabbit
	
	MIT License
*/

shader_type spatial;
render_mode ambient_light_disabled;

uniform vec4 color : source_color = vec4(1.0);
uniform sampler2D tex : source_color, hint_default_white;

uniform float shadow : hint_range(0.0, 1.0) = 0.5;
uniform float shadow_width : hint_range(0.001, 0.5) = 0.0;
uniform vec4 shadow_color: source_color = vec4(0.705);

uniform float _specular_smoothness : hint_range(0.0,0.5) = 0.01;
uniform float _specular_strength : hint_range(0.0,0.25) = 0.075;
uniform float _glossiness : hint_range(0.0,0.5) = 0.1;

uniform float _rim_size : hint_range(0,1) = 0.5;
uniform float _rim_smoothness : hint_range(0.0,0.5) = 0.01;


void fragment() {
	ALBEDO = pow(texture(tex, UV).rgb, vec3(2.2)) * color.rgb;
}


void light() {
	float NdotL = dot(NORMAL, LIGHT) * ATTENUATION.x;
	NdotL = smoothstep(shadow - shadow_width, shadow + shadow_width, NdotL);
	
	// specular
	vec3 H = normalize(VIEW + LIGHT);
	float NdotH = max(0, dot(NORMAL, H));
	float specular_intensity = pow(NdotH, 1.0 / _glossiness);
	vec3 specular = vec3(smoothstep(0.5 - _specular_smoothness, 0.5 + _specular_smoothness, specular_intensity));
	
	// rim
	float rimDot = 1.0 - dot(VIEW, NORMAL);
	float rim_intensity = rimDot * NdotL;
	vec3 rim = vec3(smoothstep(1.0 -_rim_size - _rim_smoothness, 1.0 -_rim_size + _rim_smoothness, rim_intensity));
	
	DIFFUSE_LIGHT = mix(ALBEDO * shadow_color.rgb, (ALBEDO + (rim + specular) * _specular_strength) * LIGHT_COLOR.rgb * 0.33, NdotL + 0.33 * (smoothstep(1.0 -_rim_size - _rim_smoothness, 1.0 -_rim_size + _rim_smoothness, rimDot)));
}
Live Preview
Tags
toon
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Firerabbit

Related shaders

Comments 10

  1. Henodude

    Nice! I haven't tested it out yet, but this seems to be exactly what I need.

    1
  2. Henodude

    Just so you know, this is mislabeled as a canvas item shader.

    0
  3. Purple

    I dont why . But cannot change color everything is Blueish !!!

    1
    1. hint_color become -> source_color
      and hint_white -> hint_default_white ! and now it work for 4.0

       

      thanks im having fun with this shader !

      4
  4. Halom

    This Shader looks amazing it's exactly what I need!
    Problem is, it's not working properly for me in Godot 4.

    In line 31. I get the following error, since ATTENUATION is no longer a float:

    Invalid member for 'float' expression: '.x'.
    

    And if I remove the '.x' from the attenuation it works - but I get this weird cutoff in shadow:
    https://imgur.com/saIsB5P

    2
    1. Can you post a link to a gihub repository with a project for reproducing the bug?

      0
    2. // Remove the .x since dot() already returns a float
      float NdotL = dot(NORMAL, LIGHT) * ATTENUATION;
      
      3
  5. Roman

    Tell me, why is the beam of the light source square when illuminating the material with this shader? I compared it with another toon shader, and the result is the same.

    0
    1. I'm not sure if I understand the question correctly.
      It could be the following:
      The normals of the 3D model are used to calculate the light. If the normals of the model are flat, all normals of a surface point in the same direction and the surface is displayed in only one color. An example is a cube. In the case of a sphere, the normals are smooth, the normals of the corner points point in different directions and the specular highlight is not angular but round. Normals can be edited with Blender, for example.
      https://www.youtube.com/watch?v=S1aJdBGolXA

       

      An example image of a sphere with soft and flat normal can be found here: https://3dmodels.org/wp-content/uploads/2023/07/26/03-flat-vs-smooth-shading.jpg

      0