Procedural Dirt or Swamp

Shader code
shader_type spatial;

// ============================================================
// COLORES
// ============================================================
uniform vec4 base_color : source_color = vec4(0.12, 0.12, 0.14, 1.0);
uniform vec4 dirt_color : source_color = vec4(0.72, 0.65, 0.52, 1.0);
uniform sampler2D dirt_texture : hint_default_white, repeat_enable;
uniform float dirt_texture_strength : hint_range(0.0, 1.0) = 0.25;
uniform float dirt_intensity : hint_range(0.0, 2.0) = 1.35;
uniform int dirt_blend_mode : hint_range(0, 2) = 0;

// ============================================================
// DOS CAPAS DE NOISE
// ============================================================
// Capa 1: Ruido de fondo GRANDE (manchas / distribución general)
uniform sampler2D noise_large : hint_default_black, repeat_enable;
uniform float large_scale : hint_range(0.01, 2.0) = 0.07;   // ← más grande (antes 0.15)
uniform float large_contrast : hint_range(0.1, 5.0) = 1.25;

// Capa 2: Ruido de PUNTOS DE POLVO (detalle fino)
uniform sampler2D noise_detail : hint_default_black, repeat_enable;
uniform float detail_scale : hint_range(0.1, 20.0) = 6.5;   // ← mucho más fino (antes 2.0)
uniform float detail_contrast : hint_range(0.1, 5.0) = 3.2;

// Mezcla: 0 = solo fondo grande, 1 = fondo + puntos de polvo
uniform float detail_strength : hint_range(0.0, 1.0) = 0.85;

// Brillo global del ruido combinado
uniform float noise_brightness : hint_range(-1.0, 1.0) = -0.05;

// ============================================================
// DISTRIBUCIÓN
// ============================================================
uniform float dirt_amount : hint_range(0.0, 1.0) = 0.82;
uniform float edge_softness : hint_range(0.001, 1.0) = 0.14;
uniform float invert_dirt : hint_range(0.0, 1.0) = 0.0;
uniform vec3 dirt_direction = vec3(0.0, -1.0, 0.0);
uniform float direction_strength : hint_range(0.0, 1.0) = 0.85;
uniform bool mirror_direction = false;
uniform float side_strength : hint_range(0.0, 1.0) = 0.55;
uniform float top_influence : hint_range(0.0, 1.0) = 0.08;
uniform bool world_space_noise = false;

// ============================================================
// MATERIAL
// ============================================================
uniform float roughness_base : hint_range(0.0, 1.0) = 0.28;
uniform float roughness_dirt : hint_range(0.0, 1.0) = 0.92;
uniform float normal_dirt_strength : hint_range(0.0, 1.0) = 0.18;

// ============================================================
// VARYINGS
// ============================================================
varying vec3 obj_pos;
varying vec3 obj_normal;
varying vec3 world_normal;
varying vec3 world_pos;

// ============================================================
// FUNCIONES
// ============================================================
vec4 sample_triplanar(sampler2D tex, vec3 pos, vec3 normal, float scale) {
	vec3 blend = abs(normal);
	blend = pow(blend, vec3(4.0));
	blend /= dot(blend, vec3(1.0));
	vec3 p = pos * scale;
	vec4 x = texture(tex, p.yz);
	vec4 y = texture(tex, p.xz);
	vec4 z = texture(tex, p.xy);
	return x * blend.x + y * blend.y + z * blend.z;
}

vec3 blend_colors(vec3 base, vec3 dirt, float mask, int mode) {
	if (mode == 0) return mix(base, dirt, mask * dirt_intensity);
	else if (mode == 1) return mix(base, base * dirt, mask);
	else return mix(base, min(base + dirt * dirt_intensity, vec3(1.0)), mask);
}

// ============================================================
// VERTEX
// ============================================================
void vertex() {
	obj_pos = VERTEX;
	obj_normal = NORMAL;
	world_normal = normalize((MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz);
	world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}

// ============================================================
// FRAGMENT
// ============================================================
void fragment() {
	vec3 noise_pos = world_space_noise ? world_pos : obj_pos;
	vec3 noise_normal = world_space_noise ? world_normal : obj_normal;
	
	// --------------------------------------------------------
	// CAPA 1: RUIDO DE FONDO GRANDE
	// --------------------------------------------------------
	float noise_1 = sample_triplanar(noise_large, noise_pos, noise_normal, large_scale).r;
	noise_1 = pow(clamp(noise_1, 0.0, 1.0), large_contrast);
	
	// --------------------------------------------------------
	// CAPA 2: PUNTOS DE POLVO (detalle fino)
	// --------------------------------------------------------
	float noise_2 = sample_triplanar(noise_detail, noise_pos, noise_normal, detail_scale).r;
	noise_2 = pow(clamp(noise_2, 0.0, 1.0), detail_contrast);
	
	// --------------------------------------------------------
	// COMBINAR NOISES
	// --------------------------------------------------------
	float combined_noise = mix(noise_1, noise_1 * noise_2, detail_strength);
	combined_noise = clamp(combined_noise + noise_brightness, 0.0, 1.0);
	
	// --------------------------------------------------------
	// DIRECCIÓN Y MÁSCARAS
	// --------------------------------------------------------
	vec3 dirt_dir = normalize(dirt_direction);
	float alignment = dot(world_normal, dirt_dir);
	float direction_factor = alignment * 0.5 + 0.5;
	float top_factor = world_normal.y * 0.5 + 0.5;
	direction_factor = mix(direction_factor, top_factor, top_influence);
	float direction_mask = 1.0 - direction_strength * (1.0 - direction_factor);
	
	float side_factor = 1.0 - abs(world_normal.y);
	float side_mask = 1.0 - side_strength * (1.0 - side_factor);
	
	// --------------------------------------------------------
	// MÁSCARA FINAL
	// --------------------------------------------------------
	float mask = combined_noise * direction_mask * side_mask;
	float dirt_mask = smoothstep(0.5 - edge_softness, 0.5 + edge_softness, mask);
	dirt_mask = mix(dirt_mask, 1.0 - dirt_mask, invert_dirt);
	dirt_mask *= dirt_amount;
	
	// --------------------------------------------------------
	// COLOR Y MATERIAL
	// --------------------------------------------------------
	vec3 final_dirt_color = dirt_color.rgb;
	if (dirt_texture_strength > 0.0) {
		vec4 tex_color = sample_triplanar(dirt_texture, noise_pos, noise_normal, large_scale * 0.6);
		final_dirt_color = mix(final_dirt_color, tex_color.rgb, dirt_texture_strength);
	}
	
	ALBEDO = blend_colors(base_color.rgb, final_dirt_color, dirt_mask, dirt_blend_mode);
	ROUGHNESS = mix(roughness_base, roughness_dirt, dirt_mask);
	SPECULAR = mix(0.5, 0.08, dirt_mask);
	
	if (normal_dirt_strength > 0.0) {
		NORMAL_MAP_DEPTH *= mix(1.0, 0.35, dirt_mask * normal_dirt_strength);
	}
	
	// DEBUG (descomenta para ver capas)
	// ALBEDO = vec3(noise_1);           // solo fondo grande
	// ALBEDO = vec3(noise_2);           // solo puntos de polvo
	// ALBEDO = vec3(combined_noise);    // combinado
	// ALBEDO = vec3(dirt_mask);         // máscara final
}
Live Preview
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

0 Comments
Oldest
Newest Most Voted