Complete Cel Shader for Godot 4

Upgrade of my old Complete Toon Shader now for Godot 4. It supports:

  • Multiple lights;
  • Deeper control over specular blobs and Fresnel effect, all toonified;
  • 3D outlines;
  • Normal maps;
  • Ambient occlusion;
  • Anisotropy flowcharts;
  • Backlight;
  • Transparency;
  • Refraction;

Heightmap and subsurface scattering left out can be copied from the first version, I just left them out because I think they’re not goal of a toon shader.

It uses shader globals and shader includes, read everything carefully to set it up, just copying and pasting the code from this page won’t do it. Read the repository to set it up correctly. You can also watch the video for more information on how it works.

Shader code
// ATTENTION
// This shader uses multiple include files! Copying this file alone won't work!
// See https://github.com/eldskald/godot4-cel-shader for all the files! 

shader_type spatial;

#define USE_ALPHA 0
#define USE_ALPHA_CUTOFF 0
#define USE_EMISSION 0
#define USE_REFLECTIONS 0
#define USE_NORMAL_MAP 0
#define USE_OCCLUSION 0
#define USE_ANISOTROPY 0
#define USE_BACKLIGHT 0
#define USE_REFRACTION 0

#if USE_ALPHA
render_mode depth_draw_always;
#endif

#include "includes/base-cel-shader.gdshaderinc"

#if USE_EMISSION
#include "includes/emission.gdshaderinc"
#endif

#if USE_REFLECTIONS
#include "includes/reflections.gdshaderinc"
#endif

#if USE_NORMAL_MAP
#include "includes/normal-map.gdshaderinc"
#endif

#if USE_OCCLUSION
#include "includes/occlusion.gdshaderinc"
#endif

#if USE_ANISOTROPY
#include "includes/anisotropy.gdshaderinc"
#endif

#if USE_BACKLIGHT
#include "includes/backlight.gdshaderinc"
#endif

#if USE_REFRACTION
#include "includes/refraction.gdshaderinc"
#elif !USE_REFRACTION && USE_ALPHA
#include "includes/transparency.gdshaderinc"
#endif

group_uniforms BaseProperties;
#if USE_ALPHA_CUTOFF
uniform float alpha_cutoff: hint_range(0.0, 1.0) = 0.5;
#endif
uniform vec4 color: source_color = vec4(0.7, 0.12, 0.86, 1.0);
uniform sampler2D base_texture: source_color;
uniform vec4 specular: source_color = vec4(0.3, 0.3, 0.3, 0.5);
uniform sampler2D specular_texture: hint_default_white;
uniform vec4 fresnel: source_color = vec4(0.2, 0.2, 0.2, 0.3);
uniform sampler2D fresnel_texture: hint_default_white;
group_uniforms;

varying vec3 SPECULAR_COLOR;
varying float SPECULAR_AMOUNT;
varying vec3 FRESNEL_COLOR;
varying float FRESNEL_AMOUNT;

group_uniforms Tiling;
uniform vec2 uv_scale = vec2(1,1);
uniform vec2 uv_offset = vec2(0,0);
group_uniforms;

void vertex() {
	UV = UV * uv_scale.xy + uv_offset.xy;
}

void fragment() {
	ALBEDO = color.rgb * texture(base_texture, UV).rgb;
#if USE_ALPHA
	float alpha = color.a * texture(base_texture, UV).a;
	ALBEDO *= alpha;
#elif USE_ALPHA_CUTOFF
	ALPHA = color.a * texture(base_texture, UV).a;
	ALPHA_SCISSOR_THRESHOLD = color.a * texture(base_texture, UV).a;
#endif
	
#if USE_REFRACTION && USE_ALPHA
	EMISSION += refraction_fragment(alpha, NORMAL, SCREEN_UV, FRAGCOORD.z);
#elif !USE_REFRACTION && USE_ALPHA
	EMISSION += transparency_fragment(alpha, SCREEN_UV);
#endif
	
	SPECULAR_COLOR = specular.rgb * texture(specular_texture, UV).rgb;
	SPECULAR_AMOUNT = specular.a * texture(specular_texture, UV).a;
	FRESNEL_COLOR = fresnel.rgb * texture(fresnel_texture, UV).rgb;
	FRESNEL_AMOUNT = fresnel.a * texture(fresnel_texture, UV).a;
	
#if USE_EMISSION
	EMISSION += emission_fragment(UV);
#endif
	
#if USE_REFLECTIONS
	Surface surf = reflections_fragment(UV);
	METALLIC = surf.metallic;
	ROUGHNESS = surf.roughness;
#endif
	
#if USE_NORMAL_MAP
	NormalData normal = normal_map_fragment(UV, NORMAL, TANGENT, BINORMAL);
	NORMAL = normal.vector;
	NORMAL_MAP = normal.map;
	NORMAL_MAP_DEPTH = normal.depth;
#endif
	
#if USE_OCCLUSION
	OcclusionData occlusion = occlusion_fragment(UV);
	AO = occlusion.ao;
	AO_LIGHT_AFFECT = occlusion.ao_light_affect;
#endif
	
#if USE_ANISOTROPY
	AnisotropyData aniso = anisotropy_fragment(UV);
	ANISOTROPY_DIR = aniso.direction;
	ANISOTROPY_RATIO = aniso.ratio;
#endif
	
#if USE_BACKLIGHT
	BACKLIGHT = backlight_fragment(UV);
#endif
}

void light() {
#if USE_BACKLIGHT
	DIFFUSE_LIGHT += backlight_diffuse(
			ALBEDO,
			LIGHT_COLOR,
			LIGHT,
			NORMAL,
			ATTENUATION,
			BACKLIGHT
	);
#else
	DIFFUSE_LIGHT += diffuse_light(
			ALBEDO,
			LIGHT_COLOR,
			LIGHT,
			NORMAL,
			ATTENUATION
	);
#endif
	
#if USE_ANISOTROPY
	SPECULAR_LIGHT += anisotropy_specular(
			LIGHT_COLOR,
			SPECULAR_COLOR,
			SPECULAR_AMOUNT,
			NORMAL,
			VIEW,
			LIGHT,
			ATTENUATION,
			UV,
			ANISOTROPY_DIR,
			ANISOTROPY_RATIO
	);
#else
	SPECULAR_LIGHT += specular_light(
			LIGHT_COLOR,
			SPECULAR_COLOR,
			SPECULAR_AMOUNT,
			NORMAL,
			VIEW,
			LIGHT,
			ATTENUATION
	);
#endif

	SPECULAR_LIGHT += fresnel_light(
			LIGHT_COLOR,
			FRESNEL_COLOR,
			FRESNEL_AMOUNT,
			NORMAL,
			VIEW,
			LIGHT,
			ATTENUATION
	);
}
Tags
#celshader, #toonshader, godot4
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 eldskald

Complete Toon Shader

Related shaders

Complete Toon Shader

The Best Darn Grid Shader (Yet) for Godot

MToon Shader for Godot

Subscribe
Notify of
guest

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
buster
buster
1 year ago

I’m new to shaders. i tried this shader on an anime style character but i’m getting some kind of weird artifacts when i zoom in close. anybody know what could be causing this?
https://freeimage.host/i/HUAnjs4

Tsar Vul
Tsar Vul
11 months ago

This is some really good work. Thanks for publishing this.

AaronAllBlacks
8 months ago

Very nice, thank you so much!

Votron
7 months ago

Hey, awesome work! Is there anyway to disable the specular completely?

tateorrtot
tateorrtot
1 month ago

In the demo did you write the sky shader? It looks absolutely fantastic and I want to use it for my game. If I credit you, may I use it?

tateorrtot