feat(ui): relief and vegetation texture over the terrain hue (T-1194)
RimWorld technique 4 from the reference map: texture as data, not decoration.
WHY IT WAS FLAT. The base layer reads hue from morphology and lightness from
elev_q. Below Global, morphology resolves to exactly ONE zone per canvas, so
the frame became a single colour whose only variation was a lightness ramp too
subtle to see. Measured on Ferrath at Region: 1 morphology zone, but 49
distinct elev_q values. The information was already on the wire and arriving —
the renderer was discarding it by expressing it in lightness alone.
TWO MARKS, NOT ONE SLIDER — the ticket's design question (b), settled by
looking at the reference rather than reasoning about it:
- RELIEF stipple: fine, dense, darker, keyed to RUGGEDNESS not height. The
reference's high flat plains carry none while its ranges are dense with it,
so the driver is the local elev_q gradient; a high plateau stays clean.
- VEGETATION blotch: coarser, softer, marked on a half-frequency lattice so
it reads as patches rather than a second speckle at the same pitch.
Inline in the existing per-cell loop (question (a)) and always-on, base layer
only (question (c)). The TMP/MST/VEG toggles are ANALYTIC reads — stippling a
temperature ramp would corrupt the quantity being read.
THE BASELINE IS MEASURED, NOT GUESSED, and the first attempt got it wrong: a
1-cell ruggedness delta samples mostly quantization noise, reads
near-identically everywhere, and rendered as uniform static over flat green —
grain, not structure. The gradient saturates by about 4 cells (Region: d1 1.40,
d4 2.38, d8 2.41, d16 2.51), so the baseline is 4 and the full scale 4.
Verified by capture at native resolution: on Global the stipple now
concentrates on rugged ground and leaves plains clean.
WATER TAKES NEITHER MARK, and gets a flat tone. An earlier version excluded
Lake alone and stippled the entire ocean — the one surface with no relief to
express. Both open-water zones are excluded now.
The ocean also stops shading by elev_q, which is the same argument T-1188
already made for lakes and never applied here: elev_q on a water cell is the
bedrock UNDER the water, not the surface, so shading the sea by it paints
seabed relief nobody can see. Near a coast that bedrock rises steeply and
quantizes hard, which is exactly where it showed — a pale, pixellated, broken
fringe hugging every shore (Jeroen, on the capture). One tone for the sea reads
as water and lets the coastline be the edge.
D-255(e)-legal throughout: texture-space dithering of already-derived per-cell
values, decided per server cell by a hash of its own coordinates and values —
no sample invented between cells, identical on cache hit and miss.
Two colorize tests updated: both asserted the old ocean shading incidentally
while testing zero-fill/no-crash. Property under test unchanged.
1838 client tests, 0 failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2582,9 +2582,41 @@ mod tests {
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
// Mean |elev_q delta| at several baselines. T-1194's relief stipple
|
||||
// needs a driver that VARIES across the frame; a baseline shorter
|
||||
// than the finest terrain octave measures quantization noise
|
||||
// instead and comes out near-constant, which renders as uniform
|
||||
// grain rather than as ruggedness.
|
||||
let w = raw.width as usize;
|
||||
let h = raw.height as usize;
|
||||
let mut grad = String::new();
|
||||
for base in [1usize, 4, 8, 16] {
|
||||
let mut sum = 0.0f64;
|
||||
let mut n = 0.0f64;
|
||||
let mut hits = 0.0f64;
|
||||
for r in 0..h {
|
||||
for c in 0..w.saturating_sub(base) {
|
||||
let a = raw.elev_q[r * w + c] as i32;
|
||||
let b = raw.elev_q[r * w + c + base] as i32;
|
||||
let d = (a - b).abs() as f64;
|
||||
sum += d;
|
||||
n += 1.0;
|
||||
if d >= 2.0 {
|
||||
hits += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
grad += &format!(
|
||||
" d{}[mean {:.2} p>=2 {:.0}%]",
|
||||
base,
|
||||
sum / n.max(1.0),
|
||||
100.0 * hits / n.max(1.0)
|
||||
);
|
||||
}
|
||||
|
||||
println!(
|
||||
"{:8?} {:>9.1} m/gu {}x{} elev[uniq {:3} span {:3}] moist[uniq {:3} span {:3}] \
|
||||
morph[uniq {:2}] veg[uniq {:2}] glac[uniq {:2}] courses {}",
|
||||
morph[uniq {:2}] veg[uniq {:2}] glac[uniq {:2}] courses {}{grad}",
|
||||
rung,
|
||||
spacing,
|
||||
raw.width,
|
||||
|
||||
Reference in New Issue
Block a user