177 lines
6.5 KiB
Plaintext
177 lines
6.5 KiB
Plaintext
shader_type spatial;
|
|
render_mode blend_mix, depth_draw_never, cull_disabled;
|
|
|
|
// Snow globals
|
|
global uniform float global_snow_start_time = -1.0;
|
|
global uniform float global_snow_accumulation_speed = 0.005;
|
|
global uniform float global_snow_melt_time = -1.0;
|
|
global uniform float global_snow_melt_speed = 0.1;
|
|
global uniform float global_snow_amount = 0.0;
|
|
global uniform vec4 global_snow_color;
|
|
const float SNOW_VISUAL_RESPONSE = 0.55;
|
|
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.15;
|
|
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15;
|
|
uniform float snow_color_variation : hint_range(0.0, 0.15) = 0.05;
|
|
|
|
|
|
// Rain wetness parameters
|
|
global uniform float global_rain_intensity;
|
|
global uniform float global_rain_puddle_amount;
|
|
uniform float ripple_scale : hint_range(0.1, 5.0) = 1.5;
|
|
uniform float ripple_speed : hint_range(0.5, 5.0) = 2.0;
|
|
uniform float ripple_layers : hint_range(1.0, 4.0) = 3.0;
|
|
uniform float streak_scale : hint_range(0.1, 5.0) = 2.0;
|
|
uniform float streak_speed : hint_range(0.1, 3.0) = 0.8;
|
|
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
|
|
uniform float wet_roughness : hint_range(0.0, 0.3) = 0.05;
|
|
uniform float rain_normal_strength : hint_range(0.0, 1.0) = 0.4;
|
|
uniform float puddle_noise_scale : hint_range(0.01, 0.5) = 0.08;
|
|
uniform float puddle_threshold : hint_range(0.0, 0.8) = 0.45;
|
|
|
|
uniform sampler2D noise_texture : filter_linear_mipmap, repeat_enable;
|
|
|
|
float ripple_ring(vec2 uv, float time_offset) {
|
|
float d = length(uv);
|
|
float ring = sin(d * 30.0 - TIME * ripple_speed + time_offset) * 0.5 + 0.5;
|
|
float fade = smoothstep(0.5, 0.0, d);
|
|
return ring * fade;
|
|
}
|
|
|
|
float get_snow_progress() {
|
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
|
|
|
if (global_snow_start_time >= 0.0) {
|
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
|
snow_progress = max(snow_progress, timed_progress);
|
|
}
|
|
if (global_snow_melt_time >= 0.0) {
|
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
|
snow_progress = min(snow_progress, 1.0 - melt);
|
|
}
|
|
|
|
return snow_progress;
|
|
}
|
|
|
|
float get_visual_snow_progress(float snow_progress) {
|
|
return pow(clamp(snow_progress, 0.0, 1.0), SNOW_VISUAL_RESPONSE);
|
|
}
|
|
|
|
float get_snow_noise_mask(vec3 world_pos, float snow_progress) {
|
|
float detail_noise = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
|
|
float broad_noise = texture(noise_texture, world_pos.xz * snow_noise_scale * 0.35 + vec2(19.1, 7.4)).r;
|
|
float combined_noise = mix(detail_noise, broad_noise, 0.35);
|
|
float threshold = mix(0.92, 0.08, snow_progress);
|
|
return smoothstep(threshold - 0.18, threshold + 0.18, combined_noise);
|
|
}
|
|
|
|
void fragment() {
|
|
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
|
|
|
// Plain shader: assume surface faces up (flat quads/planes)
|
|
float facing_up = 1.0;
|
|
|
|
// Snow accumulation
|
|
float snow_amount = get_visual_snow_progress(get_snow_progress());
|
|
|
|
// Plain surfaces accumulate through world-space noise so flat snow is not uniform.
|
|
float snow_noise_mask = get_snow_noise_mask(world_pos, snow_amount);
|
|
float snow_mask = mix(snow_amount * 0.35, snow_amount, snow_noise_mask);
|
|
snow_mask *= step(0.01, snow_amount);
|
|
|
|
// Snow color with slight variation
|
|
float shade = texture(noise_texture, world_pos.xz * snow_noise_scale * 2.0 + vec2(3.7, 11.2)).r;
|
|
shade = mix(-snow_color_variation, snow_color_variation, shade);
|
|
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);
|
|
|
|
// Rain
|
|
float rain_int = clamp(global_rain_intensity, 0.0, 1.0);
|
|
float rain_factor = 0.0;
|
|
vec3 rain_albedo = vec3(0.0);
|
|
float rain_rough = wet_roughness;
|
|
float rain_metallic = 0.0;
|
|
vec3 rain_normal = vec3(0.5, 0.5, 1.0);
|
|
|
|
if (rain_int > 0.01) {
|
|
// Ripples on surface
|
|
float ripple = 0.0;
|
|
for (float i = 0.0; i < ripple_layers; i += 1.0) {
|
|
float phase = i * 2.17;
|
|
vec2 cell_offset = vec2(
|
|
texture(noise_texture, world_pos.xz * ripple_scale * 0.3 + vec2(phase)).r,
|
|
texture(noise_texture, world_pos.xz * ripple_scale * 0.3 + vec2(0.0, phase)).r
|
|
);
|
|
vec2 ripple_uv = fract(world_pos.xz * ripple_scale + cell_offset) - 0.5;
|
|
ripple += ripple_ring(ripple_uv, phase * 3.7);
|
|
}
|
|
ripple /= ripple_layers;
|
|
|
|
float effect = ripple * rain_int;
|
|
float darkness = wetness_darkening * rain_int;
|
|
|
|
vec2 normal_offset = vec2(dFdx(effect), dFdy(effect)) * rain_normal_strength;
|
|
rain_normal = vec3(normal_offset.x + 0.5, normal_offset.y + 0.5, 1.0);
|
|
rain_albedo = vec3(0.05, 0.05, 0.06);
|
|
rain_metallic = 0.15 * rain_int;
|
|
rain_factor = darkness + effect * 0.15;
|
|
}
|
|
|
|
// Puddles
|
|
float puddle_factor = 0.0;
|
|
float puddle_amt = clamp(global_rain_puddle_amount, 0.0, 1.0);
|
|
|
|
if (puddle_amt > 0.01) {
|
|
// Large-scale distribution: sparse zones where puddles can form
|
|
float distribution = texture(noise_texture, world_pos.xz * puddle_noise_scale * 0.15 + vec2(13.7, 7.3)).r;
|
|
float sparse_mask = smoothstep(0.55 - puddle_amt * 0.3, 0.35 - puddle_amt * 0.2, distribution);
|
|
|
|
// Multi-scale noise for organic puddle shapes
|
|
float n1 = texture(noise_texture, world_pos.xz * puddle_noise_scale).r;
|
|
float n2 = texture(noise_texture, world_pos.xz * puddle_noise_scale * 2.7 + vec2(5.7, 3.1)).r;
|
|
float n3 = texture(noise_texture, world_pos.xz * puddle_noise_scale * 5.3 + vec2(11.2, 8.9)).r;
|
|
float puddle_noise = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;
|
|
|
|
// Puddles expand as puddle_amount increases
|
|
float threshold = puddle_threshold + (1.0 - puddle_amt) * 0.35;
|
|
float puddle_shape = smoothstep(threshold, threshold - 0.08, puddle_noise);
|
|
puddle_factor = puddle_shape * sparse_mask * puddle_amt;
|
|
|
|
// Ripples inside puddles
|
|
if (puddle_factor > 0.1 && rain_int > 0.01) {
|
|
float puddle_ripple = 0.0;
|
|
for (float i = 0.0; i < 2.0; i += 1.0) {
|
|
float phase = i * 3.14;
|
|
vec2 r_uv = fract(world_pos.xz * ripple_scale * 0.8 + vec2(phase * 0.7)) - 0.5;
|
|
puddle_ripple += ripple_ring(r_uv, phase * 2.3);
|
|
}
|
|
puddle_ripple *= 0.5 * rain_int;
|
|
|
|
vec2 p_normal_offset = vec2(dFdx(puddle_ripple), dFdy(puddle_ripple)) * 0.6;
|
|
rain_normal = vec3(p_normal_offset.x + 0.5, p_normal_offset.y + 0.5, 1.0);
|
|
}
|
|
}
|
|
|
|
// Combine
|
|
// Puddles override rain when stronger
|
|
if (puddle_factor > rain_factor) {
|
|
rain_albedo = vec3(0.01, 0.01, 0.02);
|
|
rain_rough = 0.02;
|
|
rain_metallic = 0.5 * puddle_amt;
|
|
rain_factor = puddle_factor;
|
|
}
|
|
|
|
if (snow_mask > rain_factor) {
|
|
ALBEDO = snow_albedo;
|
|
ROUGHNESS = 0.15;
|
|
METALLIC = 0.0;
|
|
ALPHA = snow_mask;
|
|
} else if (rain_factor > 0.01) {
|
|
ALBEDO = rain_albedo;
|
|
ROUGHNESS = rain_rough;
|
|
METALLIC = rain_metallic;
|
|
NORMAL_MAP = rain_normal;
|
|
ALPHA = rain_factor;
|
|
} else {
|
|
ALPHA = 0.0;
|
|
}
|
|
}
|