Shader code
shader_type spatial;
render_mode blend_mix, cull_back, depth_draw_opaque;
// Screen texture uniform
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// Hatching uniforms
uniform bool enable_hatching = true;
uniform float hatching_density : hint_range(0.5, 10.0, 0.1) = 3.0;
uniform float hatching_angle : hint_range(0.0, 360.0, 1.0) = 45.0;
uniform float hatching_thickness : hint_range(0.1, 2.0, 0.1) = 0.5;
uniform float hatching_darkness : hint_range(0.0, 1.0, 0.05) = 0.7;
// NUOVI UNIFORMS per controllare dove applicare l'hatching
uniform float shadow_threshold : hint_range(0.0, 1.0, 0.05) = 0.6;
uniform float shadow_softness : hint_range(0.0, 0.5, 0.05) = 0.1;
// ============================================================================
// PERLIN NOISE FUNCTIONS
// ============================================================================
vec2 hash(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)),
dot(p, vec2(269.5, 183.3)));
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}
vec2 fade(vec2 t) {
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
float grad(vec2 hash_val, vec2 dir) {
vec2 grad_dir = vec2(hash_val.x * 2.0 - 1.0, hash_val.y * 2.0 - 1.0);
return dot(grad_dir, dir);
}
float perlin(vec2 pos) {
vec2 p = floor(pos);
vec2 f = fract(pos);
f = fade(f);
vec2 top_left = p;
vec2 top_right = p + vec2(1.0, 0.0);
vec2 bottom_left = p + vec2(0.0, 1.0);
vec2 bottom_right = p + vec2(1.0, 1.0);
float tl = grad(hash(top_left), f);
float tr = grad(hash(top_right), f - vec2(1.0, 0.0));
float bl = grad(hash(bottom_left), f - vec2(0.0, 1.0));
float br = grad(hash(bottom_right), f - vec2(1.0, 1.0));
float top = mix(tl, tr, f.x);
float bottom = mix(bl, br, f.x);
return mix(top, bottom, f.y);
}
// ============================================================================
// HATCHING EFFECT FUNCTION - Restituisce SOLO l'intensità dell'hatching
// ============================================================================
float hatching(vec2 uv, float brightness) {
// Converti l'angolo in radianti
float angle_rad = radians(hatching_angle);
// Rotazione dell'UV in base all'angolo
vec2 rotated_uv = vec2(
uv.x * cos(angle_rad) - uv.y * sin(angle_rad),
uv.x * sin(angle_rad) + uv.y * cos(angle_rad)
);
// Crea il pattern di hatching usando una onda sinusoidale
float pattern = sin(rotated_uv.x * hatching_density * 6.28318) * 0.5 + 0.5;
// Aggiungi variazione con Perlin noise per rendere più naturale
float noise = perlin(rotated_uv * 3.0) * 0.3;
pattern = pattern + noise;
pattern = fract(pattern);
// Inverti il pattern in base alla luminanza (aree scure hanno più hatching)
float hatching_amount = mix(0.0, 1.0, 1.0 - brightness);
// Applica la densità del hatching usando una curva di soglia
float threshold = hatching_thickness * (1.0 - hatching_amount);
float hatch = step(threshold, pattern);
// Restituisci SOLO dove c'è hatching, non il colore moltiplicato
return hatch * hatching_darkness * hatching_amount;
}
// ============================================================================
// FRAGMENT SHADER
// ============================================================================
void fragment() {
// Leggi il colore dal pass precedente tramite SCREEN_TEXTURE
vec3 base_color = texture(SCREEN_TEXTURE, SCREEN_UV).rgb;
// Calcola la luminanza del colore
float brightness = dot(base_color, vec3(0.2125, 0.7154, 0.0721));
// NUOVO: Calcola il fattore di ombra con transizione smooth
// Quando brightness è SOTTO il shadow_threshold, l'hatching si applica
float shadow_factor = smoothstep(shadow_threshold + shadow_softness, shadow_threshold - shadow_softness, brightness);
// Calcola solo l'intensità dell'hatching
float hatch_intensity = 0.0;
if (enable_hatching && shadow_factor > 0.0) {
hatch_intensity = hatching(UV * 100.0, brightness) * shadow_factor;
}
// Applica l'hatching SOLO dove il pattern lo richiede
// Mix tra il colore originale e il colore scurito
vec3 final_color = mix(base_color, base_color * (1.0 - hatching_darkness), hatch_intensity);
ALBEDO = final_color;
// Alpha per il blending
ALPHA = 1.0;
}