feat: SurfaceWorld step 2a — the bridge to density space; fix IsXYPure on the slab
Height stack is green: bit-identical to ComputeSurfaceTerrainZ on both passes, including all four F20 terrain ops on. MaxDisplacement is loose (27% used) and left that way — loose only costs CPU, tight-but-wrong is a hole. FIX: FSlabVoidSource::IsXYPure() returned true and that was wrong. The contract is "Eval does not depend on Z", and Eval computes min(Z - floor, ceil - Z). Section 3.1 made the SURFACES XY-pure; the density is a distance to them and never can be. I conflated the two while writing the operator that quotes the warning against it. Latent only because nothing reads the flag yet — and step 2b is where it would have gone live, since a generic T1.a column cache keyed without ChunkZ would have shared one density down the whole vertical chunk stack. AUDIT 6.3 says that corrupts every chunk silently and ValidateDeterminism would not catch it. That is also the clearest argument for the height-space split: what is XY-pure is the HEIGHT, and in VoxelHeightOp.h it lives in a type with no Z to get wrong. Step 2a: - FSkyCapHeightSource: the ceiling is an altitude, so it belongs in height space rather than density space as section 5 had it — same category slip as the terrain ops. The subtraction happens later, in the combine. - FSurfaceColumnSource: consumes both height stacks, IsXYPure false. - BuildSurfaceStack: source + 3 structural, no per-column memo inside the op since T1.a already exists one level up and a second cache key is a second thing to get wrong. NOT covered, and the test header now says so: the overhang (GetSurfaceDensity passes OverhangAmp = 0, so only the cached path computes it) and biome blending. Both are step 2b; do not wire SurfaceWorld into a biome or overhang world before then. UNVERIFIED: not compiled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -193,6 +193,24 @@ namespace VoxelDensityOps
|
||||
* `FillOnly` quand une colonne atteint la boîte, `Identity` (le cas courant) sinon. */
|
||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeGridColumnMod(const FSlabGenerationParams& P, int32 Seed);
|
||||
|
||||
/** Rôle 1 — le pont entre les deux espaces : consomme les piles de HAUTEUR (sol + voûte,
|
||||
* `VoxelHeightOp.h`) et en fait une densité. `IsXYPure()` est **false** — les hauteurs sont
|
||||
* pures en XY, la densité est une distance à celles-ci et ne peut pas l'être. */
|
||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeSurfaceColumnSource(const FSurfaceGenerationParams& P,
|
||||
int32 Seed);
|
||||
|
||||
/**
|
||||
* SurfaceWorld — ⚠️ PAS ENCORE COMPLET, et c'est délibéré. Équivaut exactement à
|
||||
* `GetSurfaceDensity`, c.-à-d. la version **sans overhang** et **sans mélange de biomes** :
|
||||
* • l'overhang a besoin d'une donnée par colonne que `GetSurfaceDensity` ne calcule pas
|
||||
* (il passe `OverhangAmp = 0`) — sa référence est le chemin caché ;
|
||||
* • le mélange de biomes est le combiner `Mask`, prototype de la Phase 3 (§5).
|
||||
* Les deux arrivent à l'étape 2b. Ne pas brancher dans un monde à biomes avant.
|
||||
*/
|
||||
VOXELFORGE_API void BuildSurfaceStack(FVoxelOpStack& OutStack, const FSurfaceGenerationParams& P,
|
||||
int32 Seed, float SpineRadius,
|
||||
const UVoxelStrateManager* StrateManager);
|
||||
|
||||
/**
|
||||
* FlatPlain ET CrystalChamber — la même pile, **sans branchement sur le type** :
|
||||
* SlabVoidSource → GridColumnMod → [structural post ×3]
|
||||
|
||||
Reference in New Issue
Block a user