feat: shelf micro-relief + drainage incision (terrain-water task 10)
Two paired detail passes on the locked v5 skeleton, output-heights only (classify path untouched): PASS A — shelf micro-relief: +-ShelfReliefAmp (default 3 m) Simplex skin (seed resolved+7409, ~40 undulations/island ~ 200 m features), weighted by shelf-ness (full mid-shelf, feathered to zero 30% of a band half-width into the risers) — both shelves get their rolling texture back; risers and peaks untouched. PASS B — drainage incision: D8 steepest-descent routing + height- ordered flow accumulation over the curved+relieved land (TerrainDetailPass — pure array machinery, named C++ candidate per D-035); depth = K*accum^p*slope (K=0.78, p=0.45 concave, cap 30 m), masked full on risers / 30% on shelves / zero on the toe, above the plateau top, and within 1.2x CraterRadius (feathered to 1.4x); hard clamp: carved height >= sea + 1 m. Ordering: curve -> relief -> incision -> crater carve (the carve stays the final authority; carve moved to its own pass 2c, bit-identical expression on both maps). The pass prints its own MEASURED depth distribution. Gate TerrainDetail "off"|"v1" (default v1; both passes one judged unit; no-op without the curve) + ShelfReliefAmp dial. New TDTL section (38 B: version + relief/incision params + seed offset) across writer/parser/harness — blueprints stay self-describing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c71026fd94
commit
45fe2ce034
7 changed files with 354 additions and 13 deletions
|
|
@ -121,6 +121,7 @@ public partial class RoundTripHarness : Node
|
|||
ok &= CompareRoads("Trail", a.TrailRoads, b.TrailRoads);
|
||||
ok &= CompareWater(a, b);
|
||||
ok &= CompareTerrainCurve(a, b);
|
||||
ok &= CompareTerrainDetail(a, b);
|
||||
|
||||
if (ok)
|
||||
GD.Print($"[Harness] Semantic equality holds: {a.MapSize}x{a.MapSize} grid, " +
|
||||
|
|
@ -215,6 +216,31 @@ public partial class RoundTripHarness : Node
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool CompareTerrainDetail(WorldBlueprint a, WorldBlueprint b)
|
||||
{
|
||||
if (a.TerrainDetail == null && b.TerrainDetail == null)
|
||||
{
|
||||
GD.Print("[Harness] TDTL: absent in source — nothing to compare (and none reappeared).");
|
||||
return true;
|
||||
}
|
||||
if (a.TerrainDetail == null || b.TerrainDetail == null)
|
||||
{
|
||||
GD.PrintErr("[Harness] TDTL presence mismatch between source and reread.");
|
||||
return false;
|
||||
}
|
||||
var da = a.TerrainDetail; var db = b.TerrainDetail;
|
||||
float[] fa = { da.Version, da.ReliefAmpM, da.ReliefFreqIslands, da.IncK, da.IncP, da.IncCapM, da.SeaClampRaw, da.CraterExclFactor, da.ShelfIncWeight, da.ReliefSeedOffset };
|
||||
float[] fb = { db.Version, db.ReliefAmpM, db.ReliefFreqIslands, db.IncK, db.IncP, db.IncCapM, db.SeaClampRaw, db.CraterExclFactor, db.ShelfIncWeight, db.ReliefSeedOffset };
|
||||
for (int i = 0; i < fa.Length; i++)
|
||||
if (System.BitConverter.SingleToInt32Bits(fa[i]) != System.BitConverter.SingleToInt32Bits(fb[i]))
|
||||
{
|
||||
GD.PrintErr("[Harness] TDTL fields differ.");
|
||||
return false;
|
||||
}
|
||||
GD.Print($"[Harness] TDTL equal (detail v{da.Version}).");
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CompareRoads(string tier, List<Vector2[]> a, List<Vector2[]> b)
|
||||
{
|
||||
if (a.Count != b.Count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue