// Underside of the calm surface as seen from below: dark everywhere, lit with // drifting crests only inside the pool where the occluder lets the sun through. // Purely visual; shadows and shafts come from the occluder mesh. shader_type spatial; render_mode unshaded, cull_disabled; uniform sampler2D ripple_noise : repeat_enable, filter_linear_mipmap; uniform vec2 pool_center_xz = vec2(-14.0, -31.0); uniform float pool_radius = 22.0; uniform float ripple_scale = 0.03; uniform float drift_speed = 0.012; uniform float lit_scale : hint_range(0.0, 1.0) = 0.3; uniform vec3 dark_color : source_color = vec3(0.01, 0.05, 0.09); uniform vec3 lit_color : source_color = vec3(0.5, 0.85, 1.0); varying vec2 world_xz; void vertex() { world_xz = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz; } void fragment() { vec2 slow_drift = vec2(TIME * drift_speed); vec2 cross_drift = vec2(-TIME * drift_speed * 0.7); float broad = texture(ripple_noise, world_xz * ripple_scale + slow_drift).r; float fine = texture(ripple_noise, world_xz * ripple_scale * 1.9 + cross_drift).r; float crest = smoothstep(0.45, 0.7, broad * 0.65 + fine * 0.35); float pool = 1.0 - smoothstep( pool_radius * 0.6, pool_radius * 1.6, distance(world_xz, pool_center_xz) ); ALBEDO = mix(dark_color, lit_color * (0.35 + crest) * lit_scale, pool); }