Shader per Fra Scemo con Hatching

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;
}
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.

More from ZeroLemniscate

Shader per Fra Scemo

Related shaders

far distance water shader (sea shader)

Drawing board shader

Very simple CRT shader

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments