test(opstack): the tile sampler never left the (0,0) spine -- widen it to 4x RoomSpacing
The per-class breakdown refuted my own hypothesis on its first run. I predicted "tunnels >> rooms, so it is capsule bounding spheres". Tunnels ARE wildly over-counted (69.2 of 80.4 reach), but rooms hit all 40 tiles too, so fixing tunnels alone would have moved the number by exactly zero. Fourth confident chain this refactor that reversed on contact with a measurement. The real finding is that the measurement was invalid. The sampler drew tile XY from RandRange(-4,4)*8, i.e. +/-32 voxels, against RoomSpacing = 80 and a guaranteed OriginRoomRadius = 20 room at (0,0) whose cull radius is 42, with the (0,0) spine descending exactly there. All 40 tiles sat inside the origin room's cull sphere, in the most cave-riddled spot in the world. "4.9 of 7.2 rooms reach" was measuring the spine hub, not the world's cave density -- every conclusion about whether deep rock is provable was answering another question. Widened to +/-320 voxels (4x RoomSpacing). The report now prints its own sampling extent and how many tiles landed clear of the spine, because a sampler whose extent you cannot quote is one nobody is watching. This changes what the measurement LOOKS AT, never what it demands: every verdict is still brute-forced voxel by voxel, so a wider sampler that produced a false verdict still fails. Also worked out, before writing any code, why rooms cannot be tightened and tunnels can. SmoothMin's penalty is exactly zero once |A-B| >= K, so the running minimum saturates at K below the true minimum and Sdf >= min_i(SDF_i) - K for ANY number of primitives. With K=4, WormNetworkRange=24, mods gating at 3K=12, the threshold T is 24. For rooms the cull rejects at Rmax+3K=57 while an "Sdf >= T+K" test rejects only at Rmax+T+K=73 -- the cull is strictly better. For tunnels the cull is a capsule BOUNDING SPHERE, radius up to ~107 for a 200-long tube of radius 7, while the real segment distance rejects at 35. An order of magnitude, and sound because TaperedCapsule is a genuine distance function (verified, not assumed). That disjunction is NOT in this build on purpose: it changes what Identity means here, from "Sdf stays FLT_MAX" to "Sdf >= T", which is only sound if every consumer threshold is <= T. Three premises still need reading rather than assuming -- VF_NearCaveSurface's constant, the Blend passed to FSdfConvertOp, and whether any modifier re-probes the SDF outside the box before its gate. Fix the measurement first; it costs nothing and it is wrong today. Unbuilt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2762,3 +2762,91 @@ verbatim. **Measure, then tighten what the numbers name.**
|
||||
to look at; pits or chimneys leading would be a surprise worth stopping on.
|
||||
2. Whether removing the columns test alone moved `proved` off zero. If it did, that number is the
|
||||
first real T1.d saving in the plugin.
|
||||
|
||||
## 2026-07-28 — the breakdown refuted MY hypothesis, and found the sampler was the bug
|
||||
|
||||
```
|
||||
rooms 40, tunnels 40, pits 14, chimneys 0
|
||||
Averages per killed tile: 4.9 of 7.2 rooms reach, 69.2 of 80.4 tunnels reach
|
||||
```
|
||||
|
||||
I predicted "tunnels ≫ rooms ⇒ capsule bounding spheres". **Wrong, or rather insufficient:** tunnels
|
||||
*are* wildly over-counted (69 of 80), but **rooms hit all 40 tiles too**, so fixing tunnels alone
|
||||
would have moved the number by exactly zero. Fourth hypothesis this refactor has reversed on contact
|
||||
with a measurement. The instrument paid for itself on its first run.
|
||||
|
||||
### The real finding: the tile sampler never left the (0,0) spine
|
||||
|
||||
```cpp
|
||||
const int32 Extent = Step * Cells; // 1 * 8 = 8
|
||||
Rng.RandRange(-4, 4) * Extent // XY ∈ [-32, +32] voxels
|
||||
```
|
||||
|
||||
Against the defaults:
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `RoomSpacing` | **80** — ±32 does not cover half of one room cell |
|
||||
| `OriginRoomRadius` | **20**, guaranteed at (0,0); cull radius `max(20·1.5, 8) + 3·4` = **42** |
|
||||
| the (0,0) spine | descends exactly there |
|
||||
|
||||
So all 40 tiles sat inside the origin room's cull sphere, in the most cave-riddled cubic
|
||||
metre of the entire world. `4.9 of 7.2 rooms reach` was not measuring the world's cave density — it
|
||||
was measuring the spine hub. **Every conclusion about "is deep rock provable" drawn from that sample
|
||||
was answering a different question.**
|
||||
|
||||
Widened to ±320 voxels (4 × `RoomSpacing`), and the report now **prints its own sampling extent** plus
|
||||
how many tiles landed clear of the spine — because a sampler whose extent you cannot quote is one
|
||||
nobody is watching. The brute-force soundness assertion is untouched: this changes what the
|
||||
measurement *looks at*, never what it *demands*.
|
||||
|
||||
### Why rooms can't be tightened and tunnels can — the arithmetic, before writing any code
|
||||
|
||||
With `SDFBlendRadius K = 4`, `WormNetworkRange = 24`, mods gating at `3K = 12`, the strongest useful
|
||||
threshold is `T = max(Blend, 3K, WormNetworkRange) = 24`.
|
||||
|
||||
`SmoothMin(A,B,K) = min(A,B) − H³K/6`, `H = max(K−|A−B|,0)/K`. Two consequences worth writing down:
|
||||
the penalty is **exactly zero** once `|A−B| ≥ K`, and the running minimum therefore **saturates at
|
||||
`K` below the true minimum** — so `Sdf ≥ min_i(SDF_i) − K` for **any** number of primitives. That is
|
||||
the bound that makes an "`Sdf ≥ T`" criterion possible at all.
|
||||
|
||||
Now compare the two possible criteria per primitive:
|
||||
|
||||
- **rooms** — cull rejects at `dist > Rmax + 3K` (= 57 worst case). The `Sdf ≥ T+K` criterion rejects
|
||||
only at `dist ≥ Rmax + T + K` (= 73). Since `T + K = 28 > 3K = 12`, **the cull is strictly the
|
||||
better test for rooms.** Nothing to gain; leave them alone.
|
||||
- **tunnels** — the cull is the capsule's **bounding sphere**, and with `MaxTunnelLength = 200` that
|
||||
sphere has radius up to ~107 for a tube of radius 7. The `Sdf ≥ T+K` criterion uses the real
|
||||
distance to the segment, so it rejects at `dist(box, segment) ≥ 7 + 28 = 35`. **Order of magnitude
|
||||
tighter**, and sound because `TaperedCapsule` is a genuine distance function
|
||||
(`Dist(P, ClosestOnSegment) − Lerp(Ra,Rb,T)`), verified rather than assumed.
|
||||
|
||||
So the eventual fix is a **per-primitive disjunction** — a primitive cannot matter if it fails its
|
||||
cull *or* its own SDF stays ≥ `T + K` over the box — applied **only to tunnels**, where the SDF is
|
||||
exact. Mixing is sound: primitives failing the cull contribute nothing, the rest are all ≥ `T+K`, so
|
||||
the fold is ≥ `T`, and every consumer (converter at `Blend`, twelve mods at `3K`, worm at
|
||||
`WormNetworkRange`) is identity at `Sdf ≥ T`.
|
||||
|
||||
### NOT done in this build, deliberately
|
||||
|
||||
The tunnel disjunction changes what `Identity` *means* here — from "`Sdf` stays `FLT_MAX`" to
|
||||
"`Sdf ≥ T`" — and that is only sound if **every** consumer's threshold is ≤ `T`. Three premises still
|
||||
need reading rather than assuming: `VF_NearCaveSurface`'s exact constant, the `Blend` actually passed
|
||||
to `FSdfConvertOp` by `BuildTunnelNetworkStack`, and whether any modifier re-probes the SDF *outside*
|
||||
the box (`FCaveTerraceMod` samples Z±1) before its gate. Any one of those wrong is a hole with no
|
||||
collision behind it, and this session has already produced four confident chains that reversed on
|
||||
checking. **Fix the measurement first; it costs nothing and it is wrong today.**
|
||||
|
||||
### The prediction, stated so the next run can refute it
|
||||
|
||||
With the widened sampler: **rooms should stop hitting every tile** (cull spheres of mean radius ~42
|
||||
on an 80-lattice cover roughly 60 % of space, so ~40 % of tiles should be clear of all rooms), and
|
||||
**tunnels should now be the binding constraint on nearly all of them.** If instead tunnels stay at
|
||||
~100 % *and* rooms drop, the tunnel disjunction above is the whole remaining job. If rooms also stay
|
||||
at 100 %, my model of the room lattice is wrong and that is the thing to look at next — not the
|
||||
tunnels.
|
||||
|
||||
### Ready to build. Compile-error spots
|
||||
|
||||
`SpanCells` / `SpanVoxelsReported` / `NumTilesAwayFromSpine` are new locals hoisted **outside** the
|
||||
tile loop (the report line needs them); `P.OriginRoomRadius` and `P.RoomSpacing` are read in check 4.
|
||||
|
||||
@@ -1107,7 +1107,11 @@ bool FVoxelForgeOpStackTunnelTest::RunTest(const FString& Parameters)
|
||||
int32 NumBruteSamples = 0, NumViolations = 0;
|
||||
float WorstViolation = 0.0f;
|
||||
TMap<FString, int32> SolidKillerCounts;
|
||||
int32 NumRoomKilled = 0;
|
||||
int32 NumRoomKilled = 0, NumTilesAwayFromSpine = 0;
|
||||
// ±320 voxels = 4 x RoomSpacing. Hors de la boucle : la ligne de rapport en a besoin, et
|
||||
// une étendue d'échantillonnage qu'on ne peut pas citer est une étendue qu'on ne surveille pas.
|
||||
const int32 SpanCells = 40;
|
||||
const int32 SpanVoxelsReported = SpanCells * 8; // Extent = Step * Cells = 1 * 8
|
||||
int32 TilesHitByRooms = 0, TilesHitByTunnels = 0, TilesHitByPits = 0, TilesHitByChimneys = 0;
|
||||
int32 SumHitRooms = 0, SumNumRooms = 0, SumHitTunnels = 0, SumNumTunnels = 0;
|
||||
|
||||
@@ -1116,10 +1120,39 @@ bool FVoxelForgeOpStackTunnelTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const int32 Step = 1, Cells = 8;
|
||||
const int32 Extent = Step * Cells;
|
||||
|
||||
// ⚠️ L'ÉTENDUE XY ÉTAIT ±32 VOXELS, ET C'EST CE QUI RENDAIT CE BLOC INEXPLOITABLE.
|
||||
// `RandRange(-4, 4) * 8` échantillonnait 40 tuiles dans un cube de ±32 voxels autour de
|
||||
// (0,0) — c'est-à-dire l'endroit le PLUS creusé du monde entier, et de loin :
|
||||
// • `RoomSpacing = 80`, donc ±32 ne couvre même pas la moitié d'UNE cellule de salle ;
|
||||
// • `OriginRoomRadius = 20` garantit une grosse salle exactement à (0,0), de rayon de
|
||||
// cull `max(20·1.5, 8) + 3·4 = 42` — qui avale la quasi-totalité de la fenêtre ;
|
||||
// • la spine (0,0) descend précisément là.
|
||||
// La mesure « 4.9 salles sur 7.2 atteignent la boîte » ne décrivait donc pas la densité
|
||||
// de grottes du monde, elle décrivait le hub de la spine. Aucune conclusion sur la
|
||||
// prouvabilité du roc profond ne pouvait sortir de cet échantillon.
|
||||
//
|
||||
// ⚠️ CE N'EST PAS « ÉLARGIR JUSQU'À CE QUE ÇA PASSE ». Le verdict de chaque tuile reste
|
||||
// brute-forcé voxel par voxel juste en dessous : un échantillonneur plus large qui
|
||||
// produirait un verdict FAUX échoue exactement comme avant. On corrige ce que la mesure
|
||||
// REGARDE, pas ce qu'elle exige.
|
||||
//
|
||||
// The XY extent was ±32 voxels around (0,0) -- with RoomSpacing = 80 and a guaranteed
|
||||
// OriginRoomRadius = 20 room at the origin, that samples the single most cave-dense spot
|
||||
// in the world and says nothing about deep rock. Widening changes what the measurement
|
||||
// LOOKS AT, not what it demands: every verdict is still brute-forced below.
|
||||
const FIntVector Origin(
|
||||
Rng.RandRange(-4, 4) * Extent,
|
||||
Rng.RandRange(-4, 4) * Extent,
|
||||
Rng.RandRange(-SpanCells, SpanCells) * Extent,
|
||||
Rng.RandRange(-SpanCells, SpanCells) * Extent,
|
||||
FMath::Clamp(Rng.RandRange(BottomVoxelZ / Extent, TopVoxelZ / Extent), -4096, 4096) * Extent);
|
||||
|
||||
// Combien de tuiles échappent vraiment au hub de la spine : sans ce compte, un futur
|
||||
// resserrement de l'étendue redeviendrait invisible.
|
||||
if (FMath::Square((float)Origin.X) + FMath::Square((float)Origin.Y)
|
||||
> FMath::Square(3.0f * P.OriginRoomRadius))
|
||||
{
|
||||
++NumTilesAwayFromSpine;
|
||||
}
|
||||
const int32 GridDim = Cells + 1;
|
||||
const FBox Box(
|
||||
FVector(Origin.X - Step, Origin.Y - Step, Origin.Z - Step),
|
||||
@@ -1181,6 +1214,16 @@ bool FVoxelForgeOpStackTunnelTest::RunTest(const FString& Parameters)
|
||||
}
|
||||
}
|
||||
|
||||
AddInfo(FString::Printf(
|
||||
TEXT("Tile sampler: 40 tiles of 10 voxels, XY drawn from +/-%d voxels (= %.1f x ")
|
||||
TEXT("RoomSpacing %.0f), Z across the strate; %d of 40 landed further than 3 x ")
|
||||
TEXT("OriginRoomRadius from the (0,0) spine. THIS LINE EXISTS BECAUSE THE SAMPLER WAS ")
|
||||
TEXT("THE BUG ONCE: it drew XY from +/-32 voxels, i.e. entirely inside the origin room's ")
|
||||
TEXT("cull sphere, so every number below described the spine hub rather than the world. ")
|
||||
TEXT("If the last count is low, nothing below says anything about deep rock."),
|
||||
SpanVoxelsReported, (float)SpanVoxelsReported / FMath::Max(P.RoomSpacing, 1.0f),
|
||||
P.RoomSpacing, NumTilesAwayFromSpine));
|
||||
|
||||
AddInfo(FString::Printf(
|
||||
TEXT("Box verdicts over 40 TunnelNetwork tiles: %d proved (%d AllSolid, %d AllAir), ")
|
||||
TEXT("%d Mixed -- brute-forced over %d voxels, %d violations. This number was 0 proved / ")
|
||||
|
||||
Reference in New Issue
Block a user