docs(assembler): round L20 -- design for director / generators / mesher, layout in metres
Standalone/DESIGN_STRATA_UNITS_AND_LAYERS.md: maps today's code to the three layers, ranks 9 violations (top: no single physical stratum-bounds/interface record; SurfaceWorld 8 m vs FloatingIslands 4 m per chunk), defines the director-resolved generator request/result contract, moves seals/caps/voids/interfaces into shared composition, and proposes an explicit LOD-stable interface surface for the L19 ledges. 6-step migration plan with "worlds don't move" checks; owner decisions listed. No code or world change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
1 parent
811c4b7b17
commit
6f9c7bd652
2 files changed
+344
No files matched your search
@@ -0,0 +1,263 @@
|
|||||||
|
# VoxelForge strata, units, and generation layers
|
||||||
|
|
||||||
|
**Design round L20 — 2026-10-20**
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Author strate layout in metres and give each strate a voxel size. Keep Core's internal tile at 32³
|
||||||
|
voxels; its physical width follows that strate's voxel size and the tile's LOD. Use one director to
|
||||||
|
resolve the season, layout, seed, generator recipe, resolution, and interfaces before workers start.
|
||||||
|
Generators then evaluate an immutable, common field contract. A shared composition layer applies
|
||||||
|
strata boundaries, gaps, seals, edits, caches, and proofs. The mesher consumes that composed field
|
||||||
|
and generic surface hints; it should not branch on SurfaceWorld, FloatingIslands, or feature type IDs.
|
||||||
|
|
||||||
|
The code already has parts of this shape, but not the boundaries between them. In particular,
|
||||||
|
`FStandaloneShapeWorld` is both a dispatch layer and a collection of field adapters, while
|
||||||
|
`World::generateTile` contains generator-aware far-surface and feature refinement. The Unreal
|
||||||
|
adapter currently translates two different meanings of “chunk” into Core coordinates.
|
||||||
|
|
||||||
|
The L19 ledges are not explained by a different density recipe per LOD. The ring audit found
|
||||||
|
upward-facing terrain from the same lower SurfaceWorld field at different extracted heights on
|
||||||
|
adjacent LODs. At the default 25 cm Core voxel size, LOD1, LOD2, and LOD3 sample at 0.5 m, 1 m,
|
||||||
|
and 2 m. The maximum LOD1→2 ring difference is 1.49862 m; LOD2→3 reaches 7.73318 m, with 8
|
||||||
|
no-hit samples among 308. An explicit shared surface contract can give all LODs common boundary
|
||||||
|
geometry and a controlled transition band. A planar ceiling alone will not fix these ground ledges.
|
||||||
|
|
||||||
|
One conversion issue needs an explicit preservation target. The current Core path maps one
|
||||||
|
SurfaceWorld slot chunk to 32 Core voxels (8 m at 25 cm), but one FloatingIslands slot chunk to
|
||||||
|
32 owner voxels at 12.5 cm (4 m). Converting each current interpretation independently into metres
|
||||||
|
can preserve each field's current positions, but it does not make shared chunk indices one common
|
||||||
|
physical boundary. The converter must record the actual per-strate bounds and any resulting gap or
|
||||||
|
overlap before choosing a unified interface. Do not promise a no-movement migration from a single
|
||||||
|
global “metres per chunk” constant.
|
||||||
|
|
||||||
|
Metres are not a runtime cost concern. Resolution is. Halving voxel spacing in all three axes means
|
||||||
|
about eight times as many density samples for the same physical volume, plus more tiles, queue work,
|
||||||
|
and cache entries because each internal tile remains 32³ voxels. With 25 cm as the default for all
|
||||||
|
strates, the proposed starting resolution matches today's Core sampling resolution.
|
||||||
|
|
||||||
|
## 1. Current code mapped to the three layers
|
||||||
|
|
||||||
|
There is no single class called “director” today. The director work is split between Unreal's
|
||||||
|
season/layout code, the Core adapter, and Core's tile scheduler.
|
||||||
|
|
||||||
|
| Intended layer | Current location and symbols | Current responsibility and boundary issue |
|
||||||
|
|---|---|---|
|
||||||
|
| **Director / orchestrator** | `VoxelStrateComposer.cpp`; `VoxelSeasonManifest.cpp`; `VoxelStrateManager.cpp` (`Initialize`, `GetGeneratorTypeForChunk`, `GetGenerationParams`); `VoxelWorld.cpp` (`BuildDesiredTiles`, tile scheduling, epochs); `VoxelForgeCoreAdapter.cpp` (`BuildSurfaceStratumPlan`, `BuildFloatingIslandStratumPlan`, `AttachValidatedWorldAssembly`) | Composes season params and stacked slots, resolves generator kind and seed, and serializes the Core snapshot. `WorldAssemblyManifest`, `WorldAssemblyPlanV1`, and their `FromJson`/`finalize`/`validate` functions in `WorldAssemblerInternal.h` are the current plan/manifest format. Resolution and bounds are not fully resolved here: Core re-derives them using generator-specific conversions. `TopWorldZ`, `BottomWorldZ`, `HeightInChunks`, and `InterStrateGapChunks` remain chunk/voxel-coordinate based in owner-facing data. |
|
||||||
|
| **Generators** | SurfaceWorld: `Heightfield2D` in `VoxelForgeCore.h` and `WorldAssemblerInternal.h`; plan construction in `VoxelForgeCoreAdapter.cpp`. FloatingIslands: `FloatingIslandFieldV1` in `VoxelForgeCore.h` and `FloatingIslandsInternal.h`; plan construction in the adapter. Legacy: `UVoxelGenerator::GetDensityAt` in `VoxelGenerator.cpp`, `VoxelDensityOpStack.cpp`, and `VoxelCaveMorphology.cpp`. | SurfaceWorld and FloatingIslands have distinct plan and evaluator APIs. Legacy generation still asks the manager for the current chunk's params and generator type. In Core, the “generator” boundary is obscured by `FStandaloneShapeWorld`, which selects native fields or falls back to the copied owner generator. |
|
||||||
|
| **Shared field / composition library** | Noise and fixed-point evaluation: `WorldAssemblerInternal.h`, `FloatingIslandsInternal.h`. CPU/HLSL far-field math: `VoxelForgeFieldShared.h`. FP contract: `CoreNamespacePreamble.h`. Feature culling and caches: `BuildWorldAssemblyFeatureTileListV1`, `ScopedWorldAssemblyFeatureQueriesV1`, `SharedColumnCache.h`, `ThreadLocalStorage.h`. Field bounds/proofs: `Heightfield2D::interval`, FloatingIslands bounds, `FStandaloneShapeWorld::ClassifyBoxDetailed` and `BuildShapeDependencyProof`. Density seals: `VoxelDensityPrimitives.h`. | Useful shared pieces exist, but only for subsets of recipes. Noise is not one library used by every legacy and native generator. Bounds, density, and output identity still use subvoxels of a Core voxel. The canonical stratum bounds descriptor `FResolvedStratumBounds` is private to `ShapeWorldInternal.h`, not part of the plan contract. `AppendStratumBoundaryCeilings` is under far-shell/meshing code, even though the boundary meaning is shared composition policy. |
|
||||||
|
| **Mesher** | `UVoxelMarchingCubesMesher::GenerateMesh` in `VoxelMarchingCubesMesher.cpp`; dispatch and mesh assembly in `World::generateTile` in `VoxelForgeCore.cpp`; `FarShellsInternal.h`; hybrid sharp support in `VoxelHybridSharpMesher.h` and `VoxelMarchingCubesMesher.cpp`. | MC, skirts, far shells, connector repair panels, LOD refinement, and cap repair are spread across the production mesher and Core tile builder. `World::generateTile` scans recipe feature type IDs, refines type-4 shelves only at LOD0–2, selects a native SurfaceWorld horizon, and invokes separate ground/cap repair. `FStandaloneShapeWorld::BuildFarFieldTileInput` constructs FloatingIslands connector panels. These are recipe-aware mesh paths. |
|
||||||
|
|
||||||
|
### What crosses a boundary today that should not
|
||||||
|
|
||||||
|
- `FStandaloneShapeWorld` reads `UVoxelStrateManager`, `FStrateSlot`, `WorldAssemblyManifest`, legacy
|
||||||
|
generator params, and generator type. It selects a recipe, evaluates a field, resolves its bounds,
|
||||||
|
applies a seal, and builds GPU far-field input. That combines director, generator adapter, shared
|
||||||
|
field, and renderer responsibilities.
|
||||||
|
- `World::generateTile` knows `WorldAssemblyPlanV1`, SurfaceWorld heightfields, feature numeric IDs,
|
||||||
|
and FloatingIslands presence. The generic mesher should receive capabilities and surface data,
|
||||||
|
not know those recipe identities.
|
||||||
|
- The adapter exports one layout but encodes physical positions in `WorldAssemblySubvoxelsPerVoxel`.
|
||||||
|
That makes a physical length's fixed integer depend on the selected Core voxel size.
|
||||||
|
- Core `WorldAssemblyStratumPlanV1` carries `topChunkZ`/`bottomChunkZ`; validation in
|
||||||
|
`WorldAssemblerInternal.h` multiplies those values by `32`. FloatingIslands additionally stores
|
||||||
|
its own owner-to-Core size ratio and metric-equivalent bounds in Core-voxel units.
|
||||||
|
- The Core boundary path calls `GetResolvedStratumBounds` differently for SurfaceWorld and
|
||||||
|
FloatingIslands. The director should resolve a single physical boundary record once.
|
||||||
|
- Legacy density still reaches into manager-owned params and operations. It must become a generator
|
||||||
|
adapter that consumes the same resolved request as a native recipe, or remain explicitly marked as
|
||||||
|
a compatibility route until it can be ported.
|
||||||
|
|
||||||
|
## 2. Violations, ranked by risk
|
||||||
|
|
||||||
|
Rank 1 is the highest risk to correct physical layout and cross-LOD output.
|
||||||
|
|
||||||
|
| Rank | Risk | Violation and evidence | Why it matters |
|
||||||
|
|---:|---|---|---|
|
||||||
|
| 1 | **Critical** | **No single physical bounds/interface contract.** `FResolvedStratumBounds` in `ShapeWorldInternal.h` derives SurfaceWorld bounds from `Slot.*ChunkZ × 32`, but derives native FloatingIslands bounds from `layout*ZSubvoxels` and an owner/Core scale ratio. `GetResolvedStratumBounds` is then reused by field classification, far-field protection, and far ceiling generation. | A shared logical slot boundary can map to different metre positions depending on generator. This can make an apparent seam a gap, overlap, or misplaced terrain surface before the mesher samples it. It also makes “preserve the old heights” ambiguous unless the old per-field physical bounds are recorded. |
|
||||||
|
| 2 | **Critical** | **LOD extraction has no required shared surface representation.** `World::generateTile` uses normal MC sampling for LOD1–3; native SurfaceWorld ground refinement is only invoked at LOD4+. L19's strict ring probe excludes skirts and masked triangles and measured 149.862 cm max at LOD1→2 and 773.318 cm max at LOD2→3. | A coordinate-stable density function does not guarantee equal extracted surfaces when sample grids differ. Thin seals can be skipped, and a heightfield root can shift with coarse XY/Z samples. This is the measured ledge failure. |
|
||||||
|
| 3 | **High** | **Chunk, owner-voxel, Core-voxel, and fixed-point units are mixed.** `WorldAssemblyFixed` in the Unreal adapter serializes lengths as 1/256 Core voxel. SurfaceWorld plan bounds use `Slot.BottomChunkZ * 32` and `(TopChunkZ-BottomChunkZ+1)*32`. FloatingIslands uses `32 × ownerToCoreScaleNumerator / denominator`. `ShapeWorldInternal.h` reverses Core Z to legacy chunk coordinates with `/ GetCoreVoxelsPerOwnerChunk()`. | A parameter's physical interpretation depends on generator and runtime Core size. `/32`, `*32`, and scale-ratio logic are reasonable only in a single boundary adapter or for the internal fixed tile; they are incorrect as the authored layout contract. |
|
||||||
|
| 4 | **High** | **The Unreal adapter and manager both resolve the same layout.** `VoxelStrateManager.cpp` creates chunk slots and per-generator runtime params; `VoxelForgeCoreAdapter.cpp` re-reads those params and builds distinct native plans; `ShapeWorldInternal.h` maps Core samples back through the manager again. `WorldAssemblyStratumPlanV1::topChunkZ/bottomChunkZ` are checked against the manager in `AttachValidatedWorldAssembly`. | The runtime can validate matching integer slots without validating that the resulting physical bounds mean the same thing for both generators. The future adapter should serialize already-resolved metres and per-strate resolution. |
|
||||||
|
| 5 | **High** | **Generators read director state.** Legacy `UVoxelGenerator::GetDensityAt` asks the manager for type/params and builds/refetches operator stacks. Core native lookup also asks the manager which generator applies at a Core sample. | The generator cannot be a pure evaluator of a resolved recipe. It is hard to cache, audit, or replay independently, and unit conversion is repeated in worker code. |
|
||||||
|
| 6 | **High** | **Boundary behavior is split between recipe and shared paths.** FloatingIslands geometry v3 special-cases top seal evaluation in `NativeFloatingIslandDensityAt`; older geometry versions retain two-sided seals. `VF_ApplyBoundarySeal`/`VF_ApplyUpperBoundarySeal` provide shared density math, while `AppendStratumBoundaryCeilings` separately patches missing mesh coverage. SurfaceWorld also owns a heightfield cap. | Density closure, boundary ownership, and visible cap geometry can disagree. A shared operator alone does not guarantee a shared, LOD-stable surface. Preserve versioned historical fields during migration, then route new plans through one contract. |
|
||||||
|
| 7 | **Medium-high** | **Mesher contains recipe policy.** `World::generateTile` has SurfaceWorld native-horizon selection, a SurfaceWorld-only far skip condition, type-2 sharp boxes, type-4 shelf refinement, separate native ground/cap refinement, and a `farHorizonVersion` identity. `ShapeWorldInternal.h` creates connector panel repairs from FloatingIslands. | A new recipe requires mesher edits and generator details leak into extraction. The mesher should consume explicit surfaces, generic feature constraints, and a requested error/refinement hint. |
|
||||||
|
| 8 | **Medium-high** | **Legacy paths do not share the new generator format.** `UVoxelGenerator`, operator stacks, morphology caches, Core's native `Heightfield2D`, and `FloatingIslandFieldV1` have separate recipe/parameter routes. | “One generator format” is not yet true. A migration wrapper is needed so behavior can be ported in small, hash-checked steps instead of reimplementing all legacy archetypes at once. |
|
||||||
|
| 9 | **Medium** | **Shared helpers and numeric policies are partial.** Core's FP preamble/self-test applies to Core translation units; fixed-point noise is implemented in assembler code, island noise is in a separate implementation, and far CPU/HLSL math has its own shared header. Feature bounds/caches are more reusable than the field interfaces. | Keep the tested Core determinism contract, but promote the shared numeric/noise primitives only where their exact semantics can be versioned. “Shared” code is not automatically cross-platform identical if separate float evaluators remain. |
|
||||||
|
|
||||||
|
### Unit measurements relevant to migration
|
||||||
|
|
||||||
|
`CHUNK_SIZE` is 32 and `VOXEL_SIZE` is 12.5 cm, so the owner's legacy chunk is 4 m
|
||||||
|
([`VoxelTypes.h`](../Source/VoxelForge/Public/VoxelTypes.h), [`Round5`](Research/WorldAssemblerM3/Round5/REPORT.md)). The current default Core voxel is 25 cm. In the current native Core routes:
|
||||||
|
|
||||||
|
| Route | Current conversion | Physical chunk width at default | Evidence |
|
||||||
|
|---|---|---:|---|
|
||||||
|
| SurfaceWorld | `32` Core voxels per slot chunk | 8 m | `BuildSurfaceStratumPlan` uses chunk bounds directly in Core voxel units; L18 records the preserved `topChunkZ × 32` mapping. |
|
||||||
|
| FloatingIslands | `32 × 125000/250000 = 16` Core voxels per owner chunk | 4 m | `BuildFloatingIslandStratumPlan` serializes the ratio and applies it to layout bounds; `GetCoreVoxelsPerOwnerChunk` uses the same ratio. |
|
||||||
|
|
||||||
|
This confirms the claimed factor of two. It does **not** prove that this conversion alone caused
|
||||||
|
the L19 ring delta. L19 isolated the observed step to coarse extraction of lower SurfaceWorld
|
||||||
|
terrain, and the reported LOD4+ horizon refiner cannot affect those LOD1→2 and LOD2→3 values.
|
||||||
|
|
||||||
|
## 3. Generator contract and one-time interface handling
|
||||||
|
|
||||||
|
### What the director resolves before generation
|
||||||
|
|
||||||
|
The director should publish an immutable `ResolvedWorld` (exact type/schema is an implementation
|
||||||
|
choice) containing:
|
||||||
|
|
||||||
|
- a stable world/season identity and seed;
|
||||||
|
- an ordered list of strates with a stable ID, generator kind and recipe version;
|
||||||
|
- each strate's physical minimum and maximum bounds in metres, including height as their difference;
|
||||||
|
- a voxel size in metres per strate (25 cm default for every strate);
|
||||||
|
- route points, island anchors/connectors, and all top/bottom/ceiling positions in the same physical
|
||||||
|
coordinate space;
|
||||||
|
- one resolved interface record per adjacent pair, including any explicit void, bedrock gap,
|
||||||
|
sealed contact, upper cap, passage, or open boundary;
|
||||||
|
- any season-level values that affect world output, such as routes, islands, water datum, or biome
|
||||||
|
selection, already attached to their owning strate or interface;
|
||||||
|
- a canonical identity over the sorted resolved layout, seed, resolution map, recipes, and interface
|
||||||
|
records.
|
||||||
|
|
||||||
|
Do not make generators ask the director for the active `FStrateSlot`, chunk number, season, or
|
||||||
|
neighbour generator while evaluating a point.
|
||||||
|
|
||||||
|
### Request to every generator
|
||||||
|
|
||||||
|
A worker request should give the generator:
|
||||||
|
|
||||||
|
1. The immutable resolved recipe and stable stratum ID.
|
||||||
|
2. Physical query/tile bounds in metres, including the exact halo requested by the mesher.
|
||||||
|
3. The canonical sample coordinates or a clearly defined lattice origin and step. Voxel coordinates
|
||||||
|
are useful as an internal derived lattice, but metres/physical fixed units are the identity space.
|
||||||
|
4. The resolved per-strate voxel size and seed. LOD can be included as a sampling hint; the canonical
|
||||||
|
field value itself must not change just because the caller chose another LOD.
|
||||||
|
5. Read-only interface descriptors that touch the request bounds. Pass boundary records, not a
|
||||||
|
pointer back to the neighbour's manager or mutable generator.
|
||||||
|
|
||||||
|
### Result from every generator
|
||||||
|
|
||||||
|
The common result should provide a deterministic field evaluator and its declared capabilities:
|
||||||
|
|
||||||
|
- signed density using one documented solid/air sign convention;
|
||||||
|
- optional material or surface-class data;
|
||||||
|
- conservative interval/classification proofs and conservative feature/influence bounds, or an
|
||||||
|
explicit “unknown, evaluate” result;
|
||||||
|
- optional semantic 2D surfaces such as a ground heightfield or a cap, in physical coordinates;
|
||||||
|
- a detail envelope / maximum safe sample spacing hint. It is a hint to generic LOD/refinement
|
||||||
|
policy, not permission for a recipe to choose its own mesh path;
|
||||||
|
- generator/schema/evaluator versions for stable plan and output identity.
|
||||||
|
|
||||||
|
Keep the established fail-open behavior: an unknown interval or influence bound causes evaluation,
|
||||||
|
not a solid/air skip. Existing feature candidate lists and worker caches fit this contract as
|
||||||
|
optimizations beneath the evaluator.
|
||||||
|
|
||||||
|
### Interfaces, seals, caps, and voids belong to shared composition
|
||||||
|
|
||||||
|
The director resolves the meaning and exact physical location of each interface once. The shared
|
||||||
|
composition layer then combines generator fields and applies boundary semantics in a fixed order:
|
||||||
|
|
||||||
|
1. Evaluate each generator only for its declared physical domain, retaining its ordinary
|
||||||
|
field/feature behavior.
|
||||||
|
2. Apply the interface contract once: for example, a physically measured seal band, a cap surface,
|
||||||
|
open void, bedrock gap, or permitted passage. The contract declares ownership, sidedness, material
|
||||||
|
class, collision/support policy, and whether player edits may cut it. A gap is data, not an
|
||||||
|
accidental “no generator found” branch.
|
||||||
|
3. Apply world edits through the canonical composed field, so both sides see the same edit in
|
||||||
|
physical space.
|
||||||
|
4. Give the resulting field, proofs, and any explicit surfaces to the mesher.
|
||||||
|
|
||||||
|
This centralizes the semantics currently spread across generator density wrappers,
|
||||||
|
`FResolvedStratumBounds`, and `AppendStratumBoundaryCeilings`. Existing versioned manifests still
|
||||||
|
need compatibility adapters: do not silently reinterpret old `boundarySealSubvoxels` values.
|
||||||
|
|
||||||
|
For two different generator kinds that meet at a plane, both should reference the same stable
|
||||||
|
interface ID and exact physical boundary. Their density fields can remain independent; shared
|
||||||
|
composition owns the boundary rule. If the plan intentionally has open space between them, the
|
||||||
|
resolved layout records that metre-valued interval explicitly.
|
||||||
|
|
||||||
|
## 4. Why LOD changes thin features, and the interface surface contract
|
||||||
|
|
||||||
|
MC samples density at lattice corners. A thin seal or cap can be narrower than one coarse cell, so
|
||||||
|
the coarse grid may see no sign change at all. If it does see a crossing, interpolation uses the
|
||||||
|
coarse cell's endpoint values; its root can differ from the finer grid's root. A shared analytic
|
||||||
|
density function guarantees the same values at the same physical coordinates, not the same triangles
|
||||||
|
from different sample grids.
|
||||||
|
|
||||||
|
For a physical strate boundary, use an explicit surface descriptor with exact height/shape in metres
|
||||||
|
and a globally stable sample phase. Every LOD must use common anchors along tile and LOD transition
|
||||||
|
edges. The mesher can fill the interior at its chosen rate, then build a deterministic transition
|
||||||
|
band from those common anchors into its coarser interior. A seal/cap should not rely on a sub-cell
|
||||||
|
thin density strip surviving arbitrary MC sampling.
|
||||||
|
|
||||||
|
For the L19 lower-ground ledge, the same rule needs a SurfaceWorld ground profile available to the
|
||||||
|
mesher as semantic surface data. A shared planar boundary cap would only close the strate ceiling;
|
||||||
|
it would not align these upward-facing ground triangles. The surface can be band-limited by LOD, but
|
||||||
|
the adjacent LODs must share their transition samples and be checked against a physical error
|
||||||
|
tolerance. If that cannot be met with a transition band, refine only the affected boundary tiles.
|
||||||
|
|
||||||
|
The costs are extra boundary vertices/triangles and some CPU work to construct common transition
|
||||||
|
strips. Collision/support must consume the same interface representation where that surface is
|
||||||
|
collision-relevant. The owner would see caps and ledges hold one physical height as the camera moves
|
||||||
|
between LODs, instead of steps or holes appearing at the ring. Authoring remains in metres; internal
|
||||||
|
tile and transition details stay hidden.
|
||||||
|
|
||||||
|
This is not free geometry, but it is bounded to boundaries and LOD transition bands. L19 has already
|
||||||
|
shown why “add a thin density seal and sample it normally” is not a sufficient all-LOD guarantee.
|
||||||
|
|
||||||
|
## 5. Keep the per-strate resolution door open
|
||||||
|
|
||||||
|
Yes. A 25 cm per-strate default preserves the current Core sample spacing, and the common physical
|
||||||
|
field coordinate contract leaves room for later different sizes. Do not enable mixed resolutions
|
||||||
|
until the Round5 boundary contract is met:
|
||||||
|
|
||||||
|
1. Canonical physical-space field queries and explicit ownership at a shared boundary.
|
||||||
|
2. Deterministic transition meshes with common LOD ancestry on both resolutions.
|
||||||
|
3. Physical-space edit rasterization/replay that reaches both grids exactly once, with no holes or
|
||||||
|
double application.
|
||||||
|
4. A stable, canonically sorted strate-ID-to-size map included in plan/season identity and border
|
||||||
|
hashes.
|
||||||
|
5. Streaming and collision rules for tiles that touch or span two resolutions.
|
||||||
|
|
||||||
|
At today's one-size setting, the size map has one value (250,000 microns) for every strate. It adds
|
||||||
|
no mixed-resolution mesh, edit, or streaming cost. Tile width remains `32 × voxel size × 2^LOD`;
|
||||||
|
different future sizes change physical tile width and workload, but never change the 32³ internal
|
||||||
|
tile format.
|
||||||
|
|
||||||
|
## 6. Migration plan with “worlds don't move” checks
|
||||||
|
|
||||||
|
The checkpoints distinguish expected equality from a deliberately changed interface mesh. A plan
|
||||||
|
or schema identity can change even when field output remains equal; record both identities and mesh
|
||||||
|
hashes separately.
|
||||||
|
|
||||||
|
| Step | Work | Expected equality / check | Changes output? / Unreal PC? |
|
||||||
|
|---:|---|---|---|
|
||||||
|
| 0 | Freeze the L19 evidence as the baseline: W12, Clang with FP contraction off; retain the whole-view hashes, full-detail hashes, strict ceiling audit, captures, and FI/SW ring tables. | Baseline hashes recorded below; pin the protected SW LOD0–2 hashes too. Capture byte/pixel comparisons and ring samples must retain location, LOD, and skirt exclusion. | No. No new build needed for this design round. |
|
||||||
|
| 1 | Add a versioned resolved-metre layout representation and a read-only conversion/audit path. The audit reports, per strate, old input units, resolved old physical bounds, new metre bounds, voxel size, interfaces, and identity. Keep the old evaluator active. | Exact old-vs-new resolved positions at all authored top, bottom, height, route, island, and cap anchors. Old Core density/mesh/payload/topology hashes remain equal where the conversion is exactly representable; otherwise list the precise quantization delta before accepting a new baseline. | No. Core parser/audit can be Linux-only; adapter export needs Unreal BuildHost on the owner's PC. |
|
||||||
|
| 2 | Change owner-facing layout authoring and season serialization to metres. Convert each old slot using its **current resolved physical bounds**, not one global chunk multiplier. Represent any historical gap/overlap explicitly. Default each strate's voxel size to 25 cm. | Same physical top/bottom/height values and field anchors before/after. Run default W12 hashes and matched captures. The report must call out any interface whose two old generator bounds disagree instead of silently forcing them together. | Intended no. Touches `VoxelForgeCoreAdapter.cpp`, `VoxelStrateManager`, season manifest/composer and likely `VoxelWorld`; compile and actor validation require the owner's Unreal PC. |
|
||||||
|
| 3 | Add the common generator request/result contract and adapt `Heightfield2D` and `FloatingIslandFieldV1`; wrap the legacy `UVoxelGenerator` route without moving it yet. Move manager lookups out of evaluator calls in stages. | Per-strate exact density queries, proof classifications, full-detail hashes, whole-view hashes, W1/W8/W12 determinism, and generator-to-legacy route parity. Existing current output hashes remain equal for adapters that preserve their exact physical recipe. | No intended visual change. Unreal adapter/legacy wrappers need owner-PC UHT/build and actor validation; native Core pieces can be audited on Linux. |
|
||||||
|
| 4 | Resolve interface records once in the director; route new seal, cap, void, bedrock-gap, and passage behavior through shared composition. Keep old manifest versions on compatibility adapters. | Preserve density hashes where only a mesh closure was missing. Run the strict LOD0–8 ceiling interior/perimeter audit, edge pairing, same-LOD border hashes, matched captures, and field proofs. Any newly closed boundary is a named expected mesh/payload/topology delta. | Affected boundary mesh may change. Adapter serialization needs owner-PC validation; Core audit can run here. This step fixes thin seals/caps, not the L19 ground ledges. |
|
||||||
|
| 5 | Add the generic explicit-surface and LOD-transition contract. Feed SurfaceWorld ground-profile data into common transition bands; prototype on the measured FI/SW interface. | Produce before/after matched readable captures and full ring tables. Require zero no-hit interface samples and a chosen physical seam-error limit; retain L19 hash equality for unaffected tiles/LODs. For intended changes, list changed mesh/payload/topology hashes and keep density unchanged if the field itself is unchanged. | **This is the step that fixes the L19 ledges.** It changes protected SurfaceWorld LOD2 output, so implement only after the owner approves that specific output change. Unreal capture/collision review is on the owner's PC. |
|
||||||
|
| 6 | Enable a per-strate size map behind the already-resolved contract, initially set to 25 cm on all strates. Add one non-default diagnostic size case only after the default remains green. | At all-25-cm map, reproduce the approved default hashes and captures. Include sorted size-map identity in a negative control; boundary/transition hashes must change when one size changes. Re-run edit-across-boundary, collision, streaming, and W1/W8/W12 checks. | No default change; non-default diagnostic intentionally changes sampling. Touches Unreal reflected settings, snapshot adapter, and world identity; full compile/run requires the owner's PC. |
|
||||||
|
|
||||||
|
### L19 reference hashes
|
||||||
|
|
||||||
|
Representative W12 Clang `-ffp-contract=off`, density / mesh / payload / topology:
|
||||||
|
|
||||||
|
| Whole view | L19 hash |
|
||||||
|
|---|---|
|
||||||
|
| SurfaceWorld | `c10697a8f48380c7 / 4197fc1072f0ff58 / 7b3e616ec9459851 / c879e35592bf33e5` |
|
||||||
|
| FloatingIslands | `00bc3607a7839854 / 4baa66127c2b0892 / e11ef05e851a1517 / 1278bc4b1fffb869` |
|
||||||
|
|
||||||
|
Protected SurfaceWorld LOD0–2 hashes are in the L19 report and should be retained through steps
|
||||||
|
1–4 except for explicitly approved boundary geometry. The whole-view hash gate alone cannot prove
|
||||||
|
that a ring improved; step 5 needs the strict ring table and readable captures as well.
|
||||||
|
|
||||||
|
### Owner decisions this design needs
|
||||||
|
|
||||||
|
1. **Preservation target:** confirm that migration snapshots each current generator's resolved
|
||||||
|
physical bounds (including any current overlap or gap) before later tuning them into a single
|
||||||
|
authored metre layout. If instead the initial migration should force currently different bounds
|
||||||
|
to meet, that is a deliberate world change and needs its own baseline/capture review.
|
||||||
|
2. **Ledge output:** approve the specific SurfaceWorld LOD2/transition change before step 5
|
||||||
|
implementation, as required by the existing protected-output rule.
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# Linux20 — design research for metre-based strata and generation layers
|
||||||
|
|
||||||
|
**Date:** 2026-10-20
|
||||||
|
**Scope:** read current owner/Core code and L19 evidence; measure unit conversions and LOD ring
|
||||||
|
errors; write the L20 design only.
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
- `CHUNK_SIZE` is 32 and legacy `VOXEL_SIZE` is 12.5 cm, so the owner chunk is 4 m
|
||||||
|
(`Source/VoxelForge/Public/VoxelTypes.h`). Core defaults to 25 cm and keeps 32 voxels per tile.
|
||||||
|
- `BuildSurfaceStratumPlan` computes SurfaceWorld layout from `Slot.*ChunkZ × CHUNK_SIZE` in Core
|
||||||
|
voxel units. This is 32 × 25 cm = **8 m per slot chunk**. L18 records this as the retained
|
||||||
|
SurfaceWorld `topChunkZ × 32` interpretation.
|
||||||
|
- `BuildFloatingIslandStratumPlan` serializes owner/Core voxel size and the reduced ratio. At the
|
||||||
|
default 12.5/25 cm ratio, its slot chunk is 32 × 0.5 = 16 Core voxels = **4 m**. Core reverses
|
||||||
|
sample Z using `GetCoreVoxelsPerOwnerChunk` in `ShapeWorldInternal.h`.
|
||||||
|
- This factor-of-two difference is real, but it is not enough to claim that it caused the L19 ring
|
||||||
|
heights. L19's ring evidence points to LOD-dependent extraction of the lower SurfaceWorld field.
|
||||||
|
It does mean there is no single metres-per-chunk conversion that both preserves the current native
|
||||||
|
bounds and makes their shared slot indices one physical interface. The design records the current
|
||||||
|
resolved bounds and treats a later interface unification as an explicit change.
|
||||||
|
- The L19 FloatingIslands-camera table reports LOD1→2 median / p95 / max = 147.141 / 148.403 /
|
||||||
|
149.862 cm, zero no-hit samples; LOD2→3 = 128.603 / 200.789 / 773.318 cm, with 8 no-hit samples
|
||||||
|
among 308. LOD1/2/3 step sizes at 25 cm are 0.5/1/2 m. The ring audit excludes skirts and masked
|
||||||
|
triangles. Native far-ground refinement starts at LOD4, so it cannot fix those two transitions.
|
||||||
|
- The exact location and current geometry evidence are from `Linux19/REPORT.md`: lower SurfaceWorld
|
||||||
|
terrain at approximately −60…−73 m; its terrain triangles remain visible below FloatingIslands.
|
||||||
|
The worst sampled LOD1→2 roots are −60.497 m and −61.996 m. The LOD2→3 pair is −73.080 m and
|
||||||
|
−65.347 m.
|
||||||
|
|
||||||
|
## Layer map
|
||||||
|
|
||||||
|
The owner-facing layout is composed by `VoxelStrateComposer.cpp`, stored/loaded by
|
||||||
|
`VoxelSeasonManifest.cpp`, and resolved into `FStrateSlot`s by `VoxelStrateManager.cpp`. The Core
|
||||||
|
snapshot adapter (`VoxelForgeCoreAdapter.cpp`) builds separate SurfaceWorld and FloatingIslands
|
||||||
|
plans. Core streams work from `VoxelForgeCore.cpp` and evaluates native fields in
|
||||||
|
`WorldAssemblerInternal.h` / `FloatingIslandsInternal.h`; legacy `UVoxelGenerator::GetDensityAt`
|
||||||
|
and operator-stack/cave paths remain in `VoxelGenerator.cpp`, `VoxelDensityOpStack.cpp`, and
|
||||||
|
`VoxelCaveMorphology.cpp`.
|
||||||
|
|
||||||
|
Shared pieces already include Core's FP-contract preamble, fixed-point field code, feature bounds,
|
||||||
|
column caches, and interval proofs. `ShapeWorldInternal.h` still chooses among native fields, manager
|
||||||
|
state, and the copied legacy evaluator. `World::generateTile` in `VoxelForgeCore.cpp` owns MC setup,
|
||||||
|
recipe feature branches, native SurfaceWorld far-ground/cap refinement, and recipe identity salts.
|
||||||
|
`FarShellsInternal.h` adds shared boundary ceilings and GPU far-shell repairs; its connector repair
|
||||||
|
input is prepared from FloatingIslands geometry in `ShapeWorldInternal.h`.
|
||||||
|
|
||||||
|
The complete mapping, boundary proposal, ranked violations, generator contract, and migration plan
|
||||||
|
are in [`DESIGN_STRATA_UNITS_AND_LAYERS.md`](../../../DESIGN_STRATA_UNITS_AND_LAYERS.md).
|
||||||
|
|
||||||
|
## Direction review
|
||||||
|
|
||||||
|
The proposed metre authoring, 25 cm per-strate default, fixed 32³ internal tiles, and separation of
|
||||||
|
director/generators/shared composition/mesher are sound. Two qualifications are recorded in the
|
||||||
|
design:
|
||||||
|
|
||||||
|
1. “Units cost nothing” is true for metre conversion itself. Voxel size affects the physical width
|
||||||
|
of 32³ tiles and the number of tiles/tasks/caches; halving spacing in XYZ implies about 8× the
|
||||||
|
density samples per physical volume, with more per-tile overhead on top.
|
||||||
|
2. A no-movement migration cannot use one global chunk-to-metre multiplier. Current Core paths use
|
||||||
|
8 m per SurfaceWorld slot chunk and 4 m per FloatingIslands slot chunk at defaults. Preserve and
|
||||||
|
report those current resolved bounds first; decide separately whether to leave any gap/overlap or
|
||||||
|
intentionally make the new metre-authored interface contiguous.
|
||||||
|
|
||||||
|
The L19 density/mesh evidence supports LOD extraction as the direct cause of the measured lower-ground
|
||||||
|
ring steps. A shared explicit ceiling surface is the right approach for seals/caps, but not sufficient
|
||||||
|
for those upward-facing ground ledges. Step 5 therefore exposes the SurfaceWorld ground profile to a
|
||||||
|
generic explicit-surface/transition contract and remains subject to the protected LOD2 approval.
|
||||||
|
|
||||||
|
## Output and worktree status
|
||||||
|
|
||||||
|
No source, manifest, generator, mesher, or build input was changed. No build or world run was made.
|
||||||
|
Thus no new W12 hash claim is needed for this documentation-only round. The L19 reference hashes
|
||||||
|
remain the expected equality gates for later source changes:
|
||||||
|
|
||||||
|
- SurfaceWorld whole view: `c10697a8f48380c7 / 4197fc1072f0ff58 / 7b3e616ec9459851 / c879e35592bf33e5`
|
||||||
|
- FloatingIslands whole view: `00bc3607a7839854 / 4baa66127c2b0892 / e11ef05e851a1517 / 1278bc4b1fffb869`
|
||||||
|
|
||||||
|
The pre-existing untracked `Standalone/Research/WorldAssemblerM3/Linux18/exports/` directory was
|
||||||
|
left untouched. No commit, push, or stash was made.
|
||||||
|
|
||||||
Reference in new issue
Block a user