shader_type spatial; render_mode diffuse_toon, specular_disabled, ambient_light_disabled; group_uniforms Albedo_Settings; uniform vec4 albedo_color : source_color = vec4(1.0); uniform sampler2D albedo_texture : source_color, filter_nearest; uniform bool use_texture = true; uniform vec2 uv_scale = vec2(1.0, 1.0); uniform float palette_shift_y : hint_range(0.0, 1.0) = 0.0; group_uniforms Height_Gradient; global uniform vec4 global_gradient_color_top; global uniform vec4 global_gradient_color_bot; global uniform float global_gradient_intensity; uniform float gradient_start_y = 0.0; uniform float gradient_end_y = 10.0; group_uniforms Toon_Lighting; uniform float light_steps : hint_range(1.0, 10.0, 1.0) = 3.0; uniform float step_softness : hint_range(0.01, 1.0) = 0.1; uniform vec4 shadow_color : source_color = vec4(0.4, 0.4, 0.6, 1.0); uniform float shadow_offset : hint_range(-1.0, 1.0) = 0.0; uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6; group_uniforms Ghibli_Directional_Glint; uniform bool use_ghibli_glint = true; uniform vec4 glint_color : source_color = vec4(1.0, 0.95, 0.85, 1.0); uniform float glint_intensity : hint_range(0.0, 10.0) = 1.0; uniform float glint_sharpness : hint_range(1.0, 128.0) = 32.0; group_uniforms Emission_Settings; uniform vec4 emission_color : source_color = vec4(0.0, 0.0, 0.0, 1.0); uniform float emission_energy : hint_range(0.0, 16.0) = 0.0; varying float world_y; void vertex() { world_y = (MODEL_MATRIX * vec4(VERTEX, 1.0)).y; } void fragment() { vec2 final_uv = (UV * uv_scale) + vec2(0.0, palette_shift_y); vec4 tex = texture(albedo_texture, final_uv); vec3 base_color = albedo_color.rgb; if (use_texture) base_color *= tex.rgb; float grad_factor = smoothstep(gradient_start_y, gradient_end_y, world_y); vec3 current_gradient_color = mix(global_gradient_color_bot.rgb, global_gradient_color_top.rgb, grad_factor); base_color = mix(base_color, current_gradient_color, global_gradient_intensity); ALBEDO = base_color; EMISSION = emission_color.rgb * emission_energy; } void light() { float shadow_factor = mix(1.0 - cast_shadow_strength, 1.0, ATTENUATION); float cutoff_mask = smoothstep(0.0, 0.1, ATTENUATION); float n_dot_l = dot(NORMAL, LIGHT); //dither float dither = fract(sin(dot(FRAGCOORD.xy, vec2(12.9898, 78.233))) * 43758.5453); float intensity = (clamp(n_dot_l, 0.0, 1.0) * shadow_factor) + (dither - 0.5) * 0.02; float raw_step = (intensity + shadow_offset) * light_steps; float lower_step = floor(raw_step); float fract_step = fract(raw_step); float soft_lerp = smoothstep(0.5 - step_softness, 0.5 + step_softness, fract_step); float stepped_intensity = (lower_step + soft_lerp) / light_steps; //Toon colors vec3 light_color_final = mix(shadow_color.rgb, vec3(1.1), clamp(stepped_intensity, 0.0, 1.0)); DIFFUSE_LIGHT += (light_color_final * LIGHT_COLOR) * cutoff_mask; if (use_ghibli_glint) { float glint_raw = pow(max(0.0, n_dot_l), glint_sharpness); float glint_mask = smoothstep(0.5 - step_softness*0.5, 0.5 + step_softness*0.5, glint_raw); glint_mask *= smoothstep(0.0, 0.1, n_dot_l); vec3 extra_sun_glint = glint_mask * glint_color.rgb * LIGHT_COLOR * glint_intensity * ATTENUATION; DIFFUSE_LIGHT += extra_sun_glint; } }