shader_type spatial; render_mode cull_disabled, depth_draw_opaque; uniform vec3 sand_color : source_color = vec3(0.50, 0.46, 0.34); uniform vec3 rock_color : source_color = vec3(0.21, 0.20, 0.18); uniform vec3 deep_tint : source_color = vec3(0.04, 0.09, 0.15); uniform float sand_slope_cosine = 0.9397; // cos(20 deg) uniform float rock_slope_cosine = 0.7660; // cos(40 deg) uniform float depth_tint_start_m = 20.0; uniform float depth_tint_end_m = 90.0; uniform float ripple_wavelength_m = 1.6; uniform float ripple_contrast = 0.12; varying vec3 world_position; varying vec3 world_normal; void vertex() { world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; world_normal = normalize((MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz); } void fragment() { float up = clamp(world_normal.y, 0.0, 1.0); float rockness = 1.0 - smoothstep(rock_slope_cosine, sand_slope_cosine, up); vec3 albedo = mix(sand_color, rock_color, rockness); float phase = (world_position.x * 0.8 + world_position.z * 0.6) * TAU / ripple_wavelength_m; float ripple = sin(phase) * ripple_contrast * (1.0 - rockness); albedo *= 1.0 + ripple; float depth_m = -world_position.y; float tint = smoothstep(depth_tint_start_m, depth_tint_end_m, depth_m); albedo = mix(albedo, deep_tint, tint * 0.6); ALBEDO = albedo; ROUGHNESS = mix(0.95, 0.82, rockness); METALLIC = 0.0; }