diff --git a/Core/Scripts/ConfigManager.cs b/Core/Scripts/ConfigManager.cs index 78bf933..d56e0fe 100644 --- a/Core/Scripts/ConfigManager.cs +++ b/Core/Scripts/ConfigManager.cs @@ -39,10 +39,10 @@ namespace IslaApocalypse.Core // Change this if your namespace is different // of OUTPUT height. ShelfEdgeVariation is the shelf-edge warp amplitude in // metres of INPUT height — how far the shelf/riser boundary contour is // displaced, not an elevation change; it is clamped at load time to the - // largest shift that keeps the curve's knots ordered. Defaults: v1, 3 m, 5 m. + // largest shift the curve's bands can absorb. Defaults: v1, 3 m, 12 m. public static string TerrainDetail = "v1"; public static float ShelfReliefAmp = 3.0f; - public static float ShelfEdgeVariation = 5.0f; + public static float ShelfEdgeVariation = 12.0f; public static void LoadConfig() { diff --git a/Tools/Scripts/TerrainDetailPass.cs b/Tools/Scripts/TerrainDetailPass.cs index 3b6f439..3687db3 100644 --- a/Tools/Scripts/TerrainDetailPass.cs +++ b/Tools/Scripts/TerrainDetailPass.cs @@ -34,19 +34,31 @@ public static class TerrainDetailPass // Pass B — shelf-edge variation. The amplitude is stated in metres of INPUT // height (raw × 251): it is how far, in raw-height terms, a shelf boundary - // contour is displaced — not an output elevation change. Lateral wander on - // the map is that displacement divided by the local raw gradient. - public const float EDGE_AMP_DEFAULT_M = 5f; // config dial: ShelfEdgeVariation (metres of input height) - public const float EDGE_FREQ_ISLANDS = 12f; // ~12 undulations per island width — a handful of notches - public const int EDGE_SEED_OFFSET = 7507; // per shelf perimeter, not hundreds of teeth - public const float EDGE_SAFETY_FRACTION = 0.5f; // shift ≤ half the smallest margin to a fixed knot + // contour is displaced — not an output elevation change. What the eye sees is + // the LATERAL wander, which is that displacement divided by the local raw + // gradient. Measured on seed 1375359975: |∇raw| at the K3/K4/K5 contours is + // p50 0.00088 raw/px, so 12 m of input height buys a median peak displacement + // of ~54 px and a mean of ~8 px along the boundary — coves and notches, which + // is where the developer's sketch sits. 5 m (the first try) moved the boundary + // a mean 3.7 px and was invisible at map scale. + public const float EDGE_AMP_DEFAULT_M = 12f; // config dial: ShelfEdgeVariation (metres of input height) + public const float EDGE_FREQ_ISLANDS = 20f; // ~410 px wavelength at 8K — coves and notches at the + public const int EDGE_SEED_OFFSET = 7507; // scale of the sketch, not a fringe of teeth + + // The shift squeezes whichever of the foothill riser / plateau bands it moves + // into. Bounding it at 2/3 of the smaller band means that band never compresses + // below a THIRD of its nominal width — i.e. its slope never more than triples, + // even where peak noise lands on a boundary. That is the real constraint; knot + // ordering follows from it. + public const float EDGE_SAFETY_FRACTION = 2f / 3f; /// - /// The largest per-column knot shift this preset can take while keeping the - /// knot set strictly ordered (K2 < K3+d, K5+d < K6) with margin to spare. - /// K1/K2/K6 never move, so the toe, the orange/red bands and the summit spike - /// are bit-identical whatever the warp does — which is what makes the - /// red-ceiling and peak-height guarantees exact rather than statistical. + /// The largest per-column knot shift this preset allows: bounded by the band + /// squeeze above, which also keeps the knot set strictly ordered + /// (K2 < K3+d, K5+d < K6) with a third of each band to spare. K1/K2/K6 never + /// move, so the toe, the orange/red bands and the summit spike are + /// bit-identical whatever the warp does — which is what makes the red-ceiling + /// floor and the 420 m cap exact rather than statistical. /// public static float MaxEdgeShift(CurveKnots k) {