feat(world): depth-coloured water column fog and de-tiled sand ripples
A FogVolume covering the site carries a fog shader whose scattering albedo follows the same spectral transmittance as the seabed and whose density grows below the reference depth, so haze darkens and turns indigo with depth around every object; the global volumetric density moves into the volume and the far depth fog only covers what lies beyond 128 m. Sand ripples are bent by a slow domain warp, blended with a larger ripple scale and faded out between 40 and 60 m, which hides the 3.2 m tiling. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
61ef4a892d
commit
d7e50f8879
11 files changed
+82
-15
No files matched your search
@@ -29,6 +29,14 @@ uniform sampler2D sand_normal_map : hint_normal, repeat_enable, filter_linear_mi
|
||||
uniform sampler2D rock_normal_map : hint_normal, repeat_enable, filter_linear_mipmap;
|
||||
uniform sampler2D rock_grain_map : hint_default_white, repeat_enable, filter_linear_mipmap;
|
||||
uniform float sand_tile_m = 3.2;
|
||||
// Second ripple scale (megaripples) and the slow domain warp that hide the tiling.
|
||||
uniform float sand_macro_tile_m = 11.3;
|
||||
uniform float sand_macro_strength = 0.45;
|
||||
uniform float sand_warp_tile_m = 37.0;
|
||||
uniform float sand_warp_m = 1.4;
|
||||
// Swell-built ripples fade out with depth as the wave energy at the bed dies.
|
||||
uniform float ripple_fade_start_m = 40.0;
|
||||
uniform float ripple_fade_end_m = 60.0;
|
||||
uniform float rock_tile_m = 7.0;
|
||||
uniform float rock_grain_tile_m = 1.7;
|
||||
uniform float sand_normal_strength = 1.0;
|
||||
@@ -81,17 +89,27 @@ void fragment() {
|
||||
float up = clamp(n.y, 0.0, 1.0);
|
||||
float rockness = 1.0 - smoothstep(rock_slope_cosine, sand_slope_cosine, up);
|
||||
|
||||
// Sand: ripple normal map rotated to the swell direction, on the xz plane.
|
||||
// Sand: ripple normal map rotated to the swell direction, on the xz plane. The
|
||||
// plane is bent by a slow warp (two decorrelated reads of the seamless grain map)
|
||||
// and a second, larger ripple scale is blended in, so no period repeats across
|
||||
// the field. Ripples fade with depth.
|
||||
vec2 ripple_axis = normalize(ripple_direction);
|
||||
vec2 sand_uv = vec2(
|
||||
dot(world_position.xz, ripple_axis),
|
||||
dot(world_position.xz, vec2(-ripple_axis.y, ripple_axis.x))
|
||||
) / sand_tile_m;
|
||||
vec3 sand_tangent = unpack_normal(texture(sand_normal_map, sand_uv));
|
||||
vec3 sand_perturbation = (
|
||||
vec3(ripple_axis.x, 0.0, ripple_axis.y) * sand_tangent.x
|
||||
+ vec3(-ripple_axis.y, 0.0, ripple_axis.x) * sand_tangent.y
|
||||
) * sand_normal_strength;
|
||||
vec2 warp = vec2(
|
||||
texture(rock_grain_map, world_position.xz / sand_warp_tile_m).r,
|
||||
texture(rock_grain_map, world_position.xz / sand_warp_tile_m + vec2(0.37, 0.61)).r
|
||||
) - 0.5;
|
||||
vec2 bent_xz = world_position.xz + warp * sand_warp_m;
|
||||
vec2 ripple_frame = vec2(
|
||||
dot(bent_xz, ripple_axis),
|
||||
dot(bent_xz, vec2(-ripple_axis.y, ripple_axis.x))
|
||||
);
|
||||
vec3 sand_tangent = unpack_normal(texture(sand_normal_map, ripple_frame / sand_tile_m));
|
||||
vec3 macro_tangent = unpack_normal(texture(sand_normal_map, ripple_frame / sand_macro_tile_m + vec2(0.5, 0.25)));
|
||||
float depth_for_ripples = -world_position.y;
|
||||
float ripple_strength = sand_normal_strength * (1.0 - smoothstep(ripple_fade_start_m, ripple_fade_end_m, depth_for_ripples));
|
||||
vec2 tangent_xy = sand_tangent.xy * ripple_strength + macro_tangent.xy * sand_macro_strength * ripple_strength;
|
||||
vec3 sand_perturbation = vec3(ripple_axis.x, 0.0, ripple_axis.y) * tangent_xy.x
|
||||
+ vec3(-ripple_axis.y, 0.0, ripple_axis.x) * tangent_xy.y;
|
||||
vec3 sand_normal = normalize(n + sand_perturbation);
|
||||
|
||||
// Rock: coarse triplanar normal map plus fine grain, both in world space.
|
||||
|
||||
Reference in new issue
Block a user