Comic / Cell / Toon – With up to 3 inputs, soft or hard banding, rimlight

Live preview on this page does not work properly. I recommend downloading the project from my github page:

https://github.com/frankschoeman/Godot-ComicShader

Shader code
[gd_resource type="VisualShader" format=3 uid="uid://dh22vh8mie7np"]

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_nhkbo"]
parameter_name = "Between_Size"
hint = 1
max = 0.7
default_value_enabled = true
default_value = 0.2

[sub_resource type="VisualShaderNodeTexture2DParameter" id="VisualShaderNodeTexture2DParameter_bd61v"]
parameter_name = "Texture_Between"
texture_type = 1

[sub_resource type="VisualShaderNodeFresnel" id="VisualShaderNodeFresnel_nhkbo"]
default_input_values = [2, false, 3, 4.695]

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_bd61v"]
operator = 2

[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_idutx"]
parameter_name = "RimLightColor"
default_value_enabled = true
default_value = Color(1.78084e-06, 0.32612, 0.322348, 1)

[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_mtfks"]
function = 2

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_lwp2i"]
operator = 2

[sub_resource type="VisualShaderNodeSmoothStep" id="VisualShaderNodeSmoothStep_m8r81"]
default_input_values = [0, 0.22, 1, 0.335, 2, 0.5]

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_1sk7y"]
parameter_name = "FresnelPower"
default_value_enabled = true
default_value = 3.0

[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_nhkbo"]
parameter_name = "Source_Shaded"
default_value_enabled = true
default_value = Color(0.37, 0.1406, 0.159717, 1)

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_k3sj7"]

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_bd61v"]
parameter_name = "Between_Transfer"
max = 0.7
default_value_enabled = true

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_nhkbo"]
operator = 2

[sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_bd61v"]
source = 5

[sub_resource type="VisualShaderNodeTexture2DParameter" id="VisualShaderNodeTexture2DParameter_j2jvq"]
parameter_name = "Texture_Lit"
texture_type = 1

[sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_idutx"]
source = 5

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_mtfks"]
operator = 2

[sub_resource type="VisualShaderNodeTexture2DParameter" id="VisualShaderNodeTexture2DParameter_7o6os"]
parameter_name = "Texture_Shaded"
texture_type = 1

[sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_2eqbp"]
source = 5

[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_bd61v"]
parameter_name = "Source_Between"
default_value_enabled = true
default_value = Color(0.91, 0.315467, 0.182, 1)

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_wek71"]
operator = 2

[sub_resource type="VisualShaderNodeClamp" id="VisualShaderNodeClamp_nhkbo"]
default_input_values = [0, Vector3(0, 0, 0), 1, Vector3(0, 0, 0), 2, Vector3(1, 1, 1)]
op_type = 4

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_j2jvq"]
parameter_name = "Light_Direction_Y"
hint = 1

[sub_resource type="VisualShaderNodeMix" id="VisualShaderNodeMix_idutx"]

[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_7o6os"]
function = 2

[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_2eqbp"]
function = 2

[sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_lwp2i"]
output_port_for_preview = 0
expanded_output_ports = [0]
input_name = "normal"

[sub_resource type="VisualShaderNodeMix" id="VisualShaderNodeMix_wek71"]

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_m8r81"]
parameter_name = "Light_Direction_X"
hint = 1

[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_nhkbo"]
function = 2

[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_j2jvq"]
parameter_name = "Source_Lit"
default_value_enabled = true
default_value = Color(1, 0.67515, 0.285238, 1)

[sub_resource type="VisualShaderNodeMix" id="VisualShaderNodeMix_bd61v"]

[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_idutx"]
parameter_name = "Light_Direction_Z"
default_value_enabled = true

[sub_resource type="VisualShaderNodeFloatConstant" id="VisualShaderNodeFloatConstant_nhkbo"]
constant = -0.01

[sub_resource type="VisualShaderNodeIf" id="VisualShaderNodeIf_idutx"]
output_port_for_preview = 0
default_input_values = [0, 0.0, 1, 0.0, 2, 0.1, 3, Vector3(0, 0, 0), 4, Vector3(0, 0, 0), 5, Vector3(0, 0, 0)]

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_7o6os"]

[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_2eqbp"]
default_input_values = [0, Vector3(0, 0, 0), 1, Vector3(1, 2, 2)]
operator = 1

[resource]
nodes/fragment/0/position = Vector2(700, 360)
nodes/fragment/2/node = SubResource("VisualShaderNodeColorParameter_nhkbo")
nodes/fragment/2/position = Vector2(-1120, 220)
nodes/fragment/3/node = SubResource("VisualShaderNodeColorParameter_bd61v")
nodes/fragment/3/position = Vector2(-880, -840)
nodes/fragment/4/node = SubResource("VisualShaderNodeColorParameter_j2jvq")
nodes/fragment/4/position = Vector2(-1160, -380)
nodes/fragment/5/node = SubResource("VisualShaderNodeIf_idutx")
nodes/fragment/5/position = Vector2(160, 520)
nodes/fragment/7/node = SubResource("VisualShaderNodeVectorOp_7o6os")
nodes/fragment/7/position = Vector2(-1040, 580)
nodes/fragment/8/node = SubResource("VisualShaderNodeVectorOp_2eqbp")
nodes/fragment/8/position = Vector2(-800, 860)
nodes/fragment/10/node = SubResource("VisualShaderNodeFloatParameter_nhkbo")
nodes/fragment/10/position = Vector2(-200, 1120)
nodes/fragment/11/node = SubResource("VisualShaderNodeTexture2DParameter_bd61v")
nodes/fragment/11/position = Vector2(-880, -1240)
nodes/fragment/12/node = SubResource("VisualShaderNodeFresnel_nhkbo")
nodes/fragment/12/position = Vector2(-1260, 1900)
nodes/fragment/13/node = SubResource("VisualShaderNodeVectorOp_bd61v")
nodes/fragment/13/position = Vector2(-480, 1620)
nodes/fragment/14/node = SubResource("VisualShaderNodeColorParameter_idutx")
nodes/fragment/14/position = Vector2(-820, 2020)
nodes/fragment/15/node = SubResource("VisualShaderNodeVectorFunc_mtfks")
nodes/fragment/15/position = Vector2(-480, 1360)
nodes/fragment/16/node = SubResource("VisualShaderNodeVectorOp_lwp2i")
nodes/fragment/16/position = Vector2(-200, 1560)
nodes/fragment/18/node = SubResource("VisualShaderNodeSmoothStep_m8r81")
nodes/fragment/18/position = Vector2(-840, 1740)
nodes/fragment/19/node = SubResource("VisualShaderNodeFloatParameter_1sk7y")
nodes/fragment/19/position = Vector2(-1600, 1940)
nodes/fragment/21/node = SubResource("VisualShaderNodeVectorOp_k3sj7")
nodes/fragment/21/position = Vector2(440, 460)
nodes/fragment/22/node = SubResource("VisualShaderNodeFloatParameter_bd61v")
nodes/fragment/22/position = Vector2(-220, 840)
nodes/fragment/23/node = SubResource("VisualShaderNodeVectorOp_nhkbo")
nodes/fragment/23/position = Vector2(-280, -780)
nodes/fragment/24/node = SubResource("VisualShaderNodeTexture_bd61v")
nodes/fragment/24/position = Vector2(-520, -980)
nodes/fragment/25/node = SubResource("VisualShaderNodeTexture2DParameter_j2jvq")
nodes/fragment/25/position = Vector2(-880, -600)
nodes/fragment/26/node = SubResource("VisualShaderNodeTexture_idutx")
nodes/fragment/26/position = Vector2(-520, -340)
nodes/fragment/27/node = SubResource("VisualShaderNodeVectorOp_mtfks")
nodes/fragment/27/position = Vector2(-280, -140)
nodes/fragment/28/node = SubResource("VisualShaderNodeTexture2DParameter_7o6os")
nodes/fragment/28/position = Vector2(-860, -80)
nodes/fragment/29/node = SubResource("VisualShaderNodeTexture_2eqbp")
nodes/fragment/29/position = Vector2(-500, 180)
nodes/fragment/30/node = SubResource("VisualShaderNodeVectorOp_wek71")
nodes/fragment/30/position = Vector2(-260, 380)
nodes/fragment/31/node = SubResource("VisualShaderNodeClamp_nhkbo")
nodes/fragment/31/position = Vector2(180, 1380)
nodes/fragment/32/node = SubResource("VisualShaderNodeFloatParameter_j2jvq")
nodes/fragment/32/position = Vector2(-1640, 1160)
nodes/fragment/33/node = SubResource("VisualShaderNodeMix_idutx")
nodes/fragment/33/position = Vector2(-1360, 1040)
nodes/fragment/34/node = SubResource("VisualShaderNodeVectorFunc_7o6os")
nodes/fragment/34/position = Vector2(-1620, 960)
nodes/fragment/35/node = SubResource("VisualShaderNodeVectorFunc_2eqbp")
nodes/fragment/35/position = Vector2(-1600, 800)
nodes/fragment/36/node = SubResource("VisualShaderNodeInput_lwp2i")
nodes/fragment/36/position = Vector2(-2080, 860)
nodes/fragment/37/node = SubResource("VisualShaderNodeMix_wek71")
nodes/fragment/37/position = Vector2(-1340, 620)
nodes/fragment/38/node = SubResource("VisualShaderNodeFloatParameter_m8r81")
nodes/fragment/38/position = Vector2(-1820, 520)
nodes/fragment/39/node = SubResource("VisualShaderNodeVectorFunc_nhkbo")
nodes/fragment/39/position = Vector2(-1600, 1440)
nodes/fragment/40/node = SubResource("VisualShaderNodeMix_bd61v")
nodes/fragment/40/position = Vector2(-1340, 1480)
nodes/fragment/41/node = SubResource("VisualShaderNodeFloatParameter_idutx")
nodes/fragment/41/position = Vector2(-1620, 1640)
nodes/fragment/43/node = SubResource("VisualShaderNodeFloatConstant_nhkbo")
nodes/fragment/43/position = Vector2(440, 260)
nodes/fragment/connections = PackedInt32Array(7, 0, 8, 0, 10, 0, 5, 2, 12, 0, 18, 2, 19, 0, 12, 3, 14, 0, 13, 1, 5, 0, 21, 0, 22, 0, 5, 1, 11, 0, 24, 2, 24, 0, 23, 0, 3, 0, 23, 1, 23, 0, 5, 3, 25, 0, 26, 2, 26, 0, 27, 0, 28, 0, 29, 2, 29, 0, 30, 0, 4, 0, 27, 1, 27, 0, 5, 4, 2, 0, 30, 1, 30, 0, 5, 5, 31, 0, 21, 1, 8, 0, 15, 0, 8, 0, 5, 0, 16, 0, 31, 0, 38, 0, 37, 2, 36, 1, 37, 0, 35, 0, 37, 1, 32, 0, 33, 2, 34, 0, 33, 1, 36, 1, 35, 0, 36, 2, 34, 0, 36, 2, 33, 0, 41, 0, 40, 2, 39, 0, 40, 1, 36, 3, 39, 0, 36, 3, 40, 0, 40, 0, 8, 1, 33, 0, 7, 1, 37, 0, 7, 0, 18, 0, 13, 0, 15, 0, 16, 0, 13, 0, 16, 1, 43, 0, 0, 0, 21, 0, 0, 5)
Live Preview
Tags
cartoon, cell, comic, godot4, stylized, 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.

Related shaders

guest

1 Comment
Oldest
Newest Most Voted
Krabolus
Krabolus
47 minutes ago

Translated the shader to the shader language:

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, depth_test_default, cull_back, diffuse_lambert, specular_schlick_ggx;

uniform float Light_Direction_X : hint_range(0.0, 1.0);
uniform float Light_Direction_Y : hint_range(0.0, 1.0);
uniform float Light_Direction_Z = 0.0;
uniform float Between_Transfer = 0.0;
uniform float Between_Size : hint_range(0.0, 0.69999998807907) = 0.20000000298023;
uniform sampler2D Texture_Between : source_color;
uniform vec4 Source_Between : source_color = vec4(0.910000, 0.315467, 0.182000, 1.000000);
uniform sampler2D Texture_Lit : source_color;
uniform vec4 Source_Lit : source_color = vec4(1.000000, 0.675150, 0.285238, 1.000000);
uniform sampler2D Texture_Shaded : source_color;
uniform vec4 Source_Shaded : source_color = vec4(0.370000, 0.140600, 0.159717, 1.000000);
uniform float FresnelPower = 3.0;
uniform vec4 RimLightColor : source_color = vec4(0.000002, 0.326120, 0.322348, 1.000000);

void fragment() {
const float const_float_mult = -0.01;

float normal_r = NORMAL.r;
float normal_g = NORMAL.g;
float normal_b = NORMAL.b;

float normal_r_mix = mix(normal_r, -(vec3(normal_r)).x, Light_Direction_X);
float normal_g_mix = mix(normal_g, -(vec3(normal_g)).x, Light_Direction_Y);

vec3 add_r_g_mix = vec3(normal_r_mix) + vec3(normal_g_mix);

float normal_b_mix = mix(normal_b, -(vec3(normal_b)).x, Light_Direction_Z);

vec3 sub_rg_b_mix = add_r_g_mix – vec3(normal_b_mix);

vec4 texture_between = texture(Texture_Between, UV);
vec3 texture_between_color = vec3(texture_between.xyz) * vec3(Source_Between.xyz);

vec4 texture_lit = texture(Texture_Lit, UV);
vec3 texture_lit_color = vec3(texture_lit.xyz) * vec3(Source_Lit.xyz);

vec4 texture_shaded = texture(Texture_Shaded, UV);
vec3 texture_shaded_color = vec3(texture_shaded.xyz) * vec3(Source_Shaded.xyz);

vec3 texture_color;
if(abs(sub_rg_b_mix.x – Between_Transfer) < Between_Size) {
texture_color = texture_between_color;
}
else if(sub_rg_b_mix.x < Between_Transfer) {
texture_color = texture_shaded_color;
}
else {
texture_color = texture_lit_color;
}

float fresnel_power = pow(1.0 – clamp(dot(NORMAL, VIEW), 0.0, 1.0), FresnelPower);
float fresnel_smoothstep = smoothstep(0.220, 0.335, fresnel_power);
vec3 fresnel = vec3(fresnel_smoothstep) * vec3(RimLightColor.xyz);

vec3 rim_light = -(sub_rg_b_mix) * fresnel;

vec3 rim_light_final = clamp(rim_light, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));

vec3 emission_final = texture_color + rim_light_final;

ALBEDO = vec3(const_float_mult);
EMISSION = emission_final;
}