feat(render3d): replace the world at run time, water bodies, terrain_sea
terrain_reload/terrain_unload release one map's height field, survey, photograph and patch bounds and generate another at any TERRAIN_HALF; scatter_clear_all (with streams), actor_clear_all, col_reset and mesh_free empty the scene; water_body_add/water_bodies_clear draw several still-water planes with one reflecting; terrain_sea separates the coast's sea level from the carved lake's, and grass keeps off both. Fixes CDLOD patch bounds for TERRAIN_HALF != 4096 and water_init leaking a mesh and program per call. examples/rendering/reload.ludic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
70bda0c4df
commit
a4a3d75cd9
13 changed files with 308 additions and 19 deletions
|
|
@ -20,6 +20,8 @@ uniform float u_ts_half;
|
|||
uniform sampler2D u_ortho;
|
||||
uniform float u_ortho_on;
|
||||
uniform float u_lake_level;
|
||||
uniform float u_sea_level; // the sea (terrain_sea); the lake's level when there is no separate sea
|
||||
uniform vec4 u_lake; // the carved lake: centre x/z, half extents (z = 0: none)
|
||||
uniform float u_snow_line;
|
||||
uniform float u_wind;
|
||||
uniform vec2 u_tile; // world xz of this tile's corner
|
||||
|
|
@ -92,7 +94,11 @@ void main() {
|
|||
if (croot.w < -1.0 || abs(croot.x) > croot.w * 1.25 + 1.5 || abs(croot.y) > croot.w * 1.4 + 1.5) { cull(); return; }
|
||||
vec3 gn = normalize(ht.gba);
|
||||
float h3 = bladeHash(ci, j, 2), h4 = bladeHash(ci, j, 3);
|
||||
float ok = (1.0 - smoothstep(0.30, 0.55, 1.0 - gn.y)) * smoothstep(0.0, 0.6, ht.r - u_lake_level - 0.15) * smoothstep(u_snow_line - 80.0, u_snow_line - 200.0, ht.r);
|
||||
// No blades under water: the sea's line everywhere, and the lake's inside its outline. One
|
||||
// line for both left a lake above the sea with grass on its bed or a valley with none.
|
||||
float wl = u_sea_level;
|
||||
if (u_lake.z > 0.0) { vec2 q = (xz - u_lake.xy) / u_lake.zw; if (dot(q, q) < 1.0) wl = max(wl, u_lake_level); }
|
||||
float ok = (1.0 - smoothstep(0.30, 0.55, 1.0 - gn.y)) * smoothstep(0.0, 0.6, ht.r - wl - 0.15) * smoothstep(u_snow_line - 80.0, u_snow_line - 200.0, ht.r);
|
||||
if (u_ortho_on > 0.5) {
|
||||
vec3 oc = textureLod(u_ortho, huv, 1.5).rgb;
|
||||
ok *= 0.25 + 0.75 * smoothstep(0.0, 0.02, oc.g - max(oc.r, oc.b));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ uniform float u_dem_base; // the elevation that becomes y = 0
|
|||
uniform vec2 u_origin; // world x/z of the map's centre
|
||||
uniform vec4 u_lake; // a lake: centre x/z, half extents (zero = none)
|
||||
uniform float u_lake_level; // its surface height; the model records the surface, the bed is carved below it
|
||||
uniform float u_sea_level; // the sea the coast falls into (terrain_sea); the lake's level unless set
|
||||
uniform vec4 u_isle; // an island: centre x/z, radius (or rim margin), falloff width
|
||||
uniform float u_isle_mode; // 0 none, 1 radial (terrain_island), 2 inward from the survey's edge (terrain_coast)
|
||||
// The DEM is Copernicus GLO-30 — 30 m data resampled onto this 4 m grid — so the stored
|
||||
|
|
@ -84,15 +85,15 @@ void main() {
|
|||
t = smoothstep(u_isle.z, u_isle.z + u_isle.w, d); // 0 inland, 1 past the fall
|
||||
shelf = 26.0 + 34.0 * smoothstep(0.0, 1.0, (d - u_isle.z - u_isle.w) / max(u_isle.w, 1.0));
|
||||
}
|
||||
float above = h - u_lake_level;
|
||||
h = u_lake_level + above * (1.0 - t) - t * shelf;
|
||||
float above = h - u_sea_level;
|
||||
h = u_sea_level + above * (1.0 - t) - t * shelf;
|
||||
// A strand. Scaling alone hands a 500 m mountainside a 40-degree plunge into the sea,
|
||||
// which is a cliff coast and nothing else. Real shores are cut flat by the water they
|
||||
// meet, so the last few metres of height either side of the line are compressed —
|
||||
// which stretches them out horizontally into beach and shallows. Only inside the
|
||||
// coastal band: an inland lake has its own bed and wants none of this.
|
||||
float near = 1.0 - smoothstep(0.0, 48.0, abs(h - u_lake_level));
|
||||
h = mix(h, u_lake_level + (h - u_lake_level) * 0.30, near * smoothstep(0.02, 0.30, t));
|
||||
float near = 1.0 - smoothstep(0.0, 48.0, abs(h - u_sea_level));
|
||||
h = mix(h, u_sea_level + (h - u_sea_level) * 0.30, near * smoothstep(0.02, 0.30, t));
|
||||
}
|
||||
o = vec4(h, 0.0, 0.0, 1.0);
|
||||
#elif defined(SMOOTH)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ uniform sampler2D u_snow_d; uniform sampler2D u_carpet; // the clump cards ba
|
|||
uniform float u_carpet_on;
|
||||
uniform float u_snow_line;
|
||||
uniform float u_lake_level; // the ground just above the water is wet and dark
|
||||
uniform float u_sea_level; // the sea's line: shore, forest and scree gates (terrain_sea)
|
||||
uniform vec2 u_origin; // world offset of the terrain grid
|
||||
|
||||
// The ground's own sun shadow comes from the baked height-field map (tershadow.frag),
|
||||
|
|
@ -236,14 +237,14 @@ vec3 groundShade(vec3 p, vec3 N, float slope, float dist, float viewDepth, bool
|
|||
vec3 ocf = textureLod(u_ortho, v_huv, 2.0).rgb;
|
||||
float gx = ocf.g - max(ocf.r, ocf.b);
|
||||
// (the photograph is sampled linear: sRGB 72 is 0.06, 92 is 0.11)
|
||||
forestW = smoothstep(0.12, 0.06, max(ocf.r, max(ocf.g, ocf.b))) * smoothstep(0.004, 0.012, gx) * smoothstep(u_lake_level + 0.8, u_lake_level + 1.8, p.y);
|
||||
forestW = smoothstep(0.12, 0.06, max(ocf.r, max(ocf.g, ocf.b))) * smoothstep(0.004, 0.012, gx) * smoothstep(u_sea_level + 0.8, u_sea_level + 1.8, p.y);
|
||||
// Classify from a ~60 m blur, never from the pixels: the survey's 10 m pixels carry
|
||||
// a foot trail as a broken line of bare ground, and thresholding them painted it
|
||||
// across the meadow as tan dashes (and, on the CPU, lined boulders up along it).
|
||||
vec3 ocl = textureLod(u_ortho, v_huv, 2.5).rgb;
|
||||
float mxc = max(ocl.r, max(ocl.g, ocl.b)), mnc = min(ocl.r, min(ocl.g, ocl.b));
|
||||
float greenEx = ocl.g - max(ocl.r, ocl.b);
|
||||
screeC = smoothstep(0.008, -0.002, greenEx) * smoothstep(0.06, 0.12, mxc) * (1.0 - smoothstep(0.55, 0.75, mxc)) * smoothstep(u_lake_level + 0.2, u_lake_level + 1.2, p.y);
|
||||
screeC = smoothstep(0.008, -0.002, greenEx) * smoothstep(0.06, 0.12, mxc) * (1.0 - smoothstep(0.55, 0.75, mxc)) * smoothstep(u_sea_level + 0.2, u_sea_level + 1.2, p.y);
|
||||
snowC = smoothstep(0.08, 0.04, mxc - mnc) * smoothstep(0.55, 0.8, mxc);
|
||||
}
|
||||
// snow lingering in the high gullies is drawn further down, but whether it can be
|
||||
|
|
@ -362,7 +363,7 @@ vec3 groundShade(vec3 p, vec3 N, float slope, float dist, float viewDepth, bool
|
|||
// the bank here: identical noise fields, identical time, identical phase, keyed off
|
||||
// height above the lake instead of depth below it. Across the seam the two agree, so
|
||||
// there is nothing there to read as an edge.
|
||||
float above = p.y - u_lake_level; // >0 on land, metres
|
||||
float above = p.y - u_sea_level; // >0 on land, metres
|
||||
// wet ground: darker and glossier near the water, fading out over ~1.2 m
|
||||
float wet = smoothstep(1.2, 0.0, above);
|
||||
alb *= mix(1.0, 0.5, wet * 0.85);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue