wip(assembler): round S4 -- continuous far ceiling at the strate's upper boundary

S3's far cap sat up to 8.2 m above the near roof and read as floating pieces.
The far render cap now projects onto the owning strate's upper boundary
(density unchanged), on a global XY lattice, LOD4 16-voxel grid + LOD5-8
128-voxel. Cap agreement 0.05 cm (100 cm control detected), 2520/2520 upward
rays hit roof on the owner walk. Far recipe v2; LOD0-3 hashes equal S2/S3.
Tile p95 flat; cold clipmap +4.4%. Far-cliff fluting left open (coarse MC step).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 00:41:13 +02:00
1 parent d0f97bf79a
commit 9d3c50ca95
14 files changed
+1376 -34

No files matched your search

@@ -195,7 +195,7 @@ namespace VoxelForgeCore
// L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles.
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 1;
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 4;
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 5;
enum class FieldChannel : std::uint32_t
{
@@ -662,6 +662,13 @@ namespace VoxelForgeCore
bool isValid() const noexcept;
HeightfieldPointSample point(std::int64_t xSubvoxels, std::int64_t ySubvoxels,
std::int64_t zSubvoxels) const noexcept;
// The far render surface is clipped to this strate's owned upper boundary; density stays unchanged.
// La surface lointaine est bornee au haut de la strate; la densite reste inchangee.
std::int64_t farSurfaceCapHeightSubvoxels(std::int64_t xSubvoxels,
std::int64_t ySubvoxels) const noexcept;
// Conservative global Z extent of this declared far roof, including biome and cap features.
// Bornes Z prudentes du plafond lointain declare, avec les biomes et les fonctions de cap.
std::array<std::int64_t, 2> capHeightBounds() const noexcept;
WorldAssemblyFeatureTileListV1 buildFeatureTileList(
const std::array<std::int64_t, 3>& tileMinimumSubvoxels,
const std::array<std::int64_t, 3>& tileMaximumSubvoxels) const;
@@ -995,11 +1002,11 @@ namespace VoxelForgeCore
// Validation control only; never participates in recipe/world identity.
// Controle de validation seulement, sans effet sur l'identite du monde.
bool useAssemblyFeatureQueries = true;
// Bump when the far-horizon mesh representation changes. Far tile mesh hashes are
// salted with this version; density and LOD0-3 hashes are intentionally unchanged.
// Incremente quand la representation d'horizon lointain change; les hashes de maillage
// lointain incluent cette version, sans toucher a la densite ni aux LOD0-3.
std::uint32_t farHorizonVersion = 1;
// Bump when the distant cap representation changes. LOD4-8 mesh hashes are salted;
// density and LOD0-3 hashes remain unchanged.
// Incremente quand le plafond lointain change. Les hashes LOD4-8 incluent cette version;
// densite et hashes LOD0-3 restent inchanges.
std::uint32_t farHorizonVersion = 2;
};
class VFCORE_API World
+81 -15
View File
@@ -10,6 +10,7 @@
#include <chrono>
#include <unordered_map>
#include <unordered_set>
#include <set>
namespace vfcore::detail
{
@@ -331,11 +332,11 @@ namespace VoxelForgeCore
for(const auto& Plan:Manifest.plan.strates)
{
const VoxelForgeCore::Heightfield2D Block(Manifest.recipe,Plan);
if(!Block.isValid())continue;
const int64 StratumMinZ=static_cast<int64>(Plan.bottomChunkZ)*CHUNK_SIZE*Scale;
const int64 StratumMaxZ=(static_cast<int64>(Plan.topChunkZ)+1)*CHUNK_SIZE*Scale;
if(TileMaxZ<StratumMinZ||TileMinZ>StratumMaxZ)continue;
const VoxelForgeCore::Heightfield2D Block(Manifest.recipe,Plan);
if(!Block.isValid())continue;
struct FGridSample
{
double Ground=0.0,Cap=0.0;
@@ -576,10 +577,10 @@ namespace VoxelForgeCore
const WorldAssemblyManifest& Manifest,const FVoxelTileKey& Key,FVoxelMeshData& Mesh)
{
FNativeCapRefinementStats Stats;
if(Key.Level<5||!Owner.Generator)return Stats;
constexpr int32 GridStepVoxels=128;
if(Key.Level<4||!Owner.Generator)return Stats;
const int32 GridStepVoxels=Key.Level<5?std::min(128,1<<Key.Level):128;
constexpr int64 Scale=WorldAssemblySubvoxelsPerVoxel;
constexpr int64 GridStepSubvoxels=GridStepVoxels*Scale;
const int64 GridStepSubvoxels=static_cast<int64>(GridStepVoxels)*Scale;
const FIntVector TileOrigin=Key.OriginVoxels();
const int32 TileExtent=Key.ExtentVoxels();
if(TileExtent<=0||TileExtent%GridStepVoxels!=0)return Stats;
@@ -599,11 +600,10 @@ namespace VoxelForgeCore
for(const auto& Plan:Manifest.plan.strates)
{
const int64 StratumMinZ=static_cast<int64>(Plan.bottomChunkZ)*CHUNK_SIZE*Scale;
const int64 StratumMaxZ=(static_cast<int64>(Plan.topChunkZ)+1)*CHUNK_SIZE*Scale;
if(TileMaxZ<StratumMinZ||TileMinZ>StratumMaxZ)continue;
const VoxelForgeCore::Heightfield2D Block(Manifest.recipe,Plan);
if(!Block.isValid())continue;
const auto CapHeightBounds=Block.capHeightBounds();
if(TileMaxZ<CapHeightBounds[0]||TileMinZ>CapHeightBounds[1])continue;
struct FGridSample
{
@@ -623,7 +623,7 @@ namespace VoxelForgeCore
const auto Column=Block.point(XSub,YSub,0);
auto& Sample=Grid[GridIndex(X,Y)];
Sample.Ground=static_cast<double>(Column.groundHeightSubvoxels);
Sample.Cap=static_cast<double>(Column.capHeightSubvoxels);
Sample.Cap=static_cast<double>(Block.farSurfaceCapHeightSubvoxels(XSub,YSub));
int32 Dominant=0,Neighbor=0;float Blend=0.0f;
Owner.Generator->GetBiomeMaterialAt(static_cast<float>(XSub)/Scale,
static_cast<float>(YSub)/Scale,static_cast<float>(Sample.Cap/Scale),
@@ -1160,6 +1160,71 @@ namespace VoxelForgeCore
VoxelClipmapDesiredTiles::Build(center,minZ,maxZ,parameters,nativeTiles);
std::vector<TileKey> tiles;tiles.reserve(static_cast<std::size_t>(nativeTiles.Num()));
for(const FVoxelTileKey& key:nativeTiles)tiles.push_back(FromNative(key));
if(impl_->worldAssembly&&!impl_->worldAssembly->plan.strates.empty())
{
constexpr std::int64_t SubvoxelsPerVoxel=WorldAssemblySubvoxelsPerVoxel;
const auto FloorDiv64=[](std::int64_t Value,std::int64_t Divisor)
{
const std::int64_t Quotient=Value/Divisor,Remainder=Value%Divisor;
return Quotient-((Remainder!=0&&Remainder<0)?1:0);
};
std::set<std::array<std::int32_t,3>> FarSurfaceColumns;
std::set<std::array<std::int32_t,4>> ExistingKeys;
for(const TileKey& Key:tiles)
{
ExistingKeys.insert({Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod});
if(Key.lod>=4&&Key.lod<=8)
FarSurfaceColumns.insert({Key.coordinate.x,Key.coordinate.y,Key.lod});
}
for(const auto& Plan:impl_->worldAssembly->plan.strates)
{
const Heightfield2D Field(impl_->worldAssembly->recipe,Plan);
if(!Field.isValid())continue;
const auto CapBounds=Field.capHeightBounds();
for(const auto& Column:FarSurfaceColumns)
{
const std::int32_t Lod=Column[2];
const std::int64_t Extent=static_cast<std::int64_t>(32)<<Lod;
const std::int64_t TileHeightSubvoxels=Extent*SubvoxelsPerVoxel;
const std::int64_t MinimumBand=FloorDiv64(CapBounds[0],TileHeightSubvoxels);
const std::int64_t MaximumBand=FloorDiv64(CapBounds[1],TileHeightSubvoxels);
for(std::int64_t Band=MinimumBand;Band<=MaximumBand;++Band)
{
if(Band<MIN_int32||Band>MAX_int32)continue;
const std::array<std::int32_t,4> Identity={Column[0],Column[1],
static_cast<std::int32_t>(Band),Lod};
if(!ExistingKeys.insert(Identity).second)continue;
const std::int64_t CandidateMinX=static_cast<std::int64_t>(Identity[0])*Extent;
const std::int64_t CandidateMinY=static_cast<std::int64_t>(Identity[1])*Extent;
const std::int64_t CandidateMinZ=
static_cast<std::int64_t>(Identity[2])*Extent;
bool bOverlapsClipmapTile=false;
for(const TileKey& Existing:tiles)
{
const std::int64_t ExistingExtent=static_cast<std::int64_t>(32)<<Existing.lod;
const std::int64_t ExistingMinX=static_cast<std::int64_t>(Existing.coordinate.x)*ExistingExtent;
const std::int64_t ExistingMinY=static_cast<std::int64_t>(Existing.coordinate.y)*ExistingExtent;
const std::int64_t ExistingMinZ=static_cast<std::int64_t>(Existing.coordinate.z)*ExistingExtent;
const bool bOverlapX=ExistingMinX<CandidateMinX+Extent
&&CandidateMinX<ExistingMinX+ExistingExtent;
const bool bOverlapY=ExistingMinY<CandidateMinY+Extent
&&CandidateMinY<ExistingMinY+ExistingExtent;
const bool bOverlapZ=ExistingMinZ<CandidateMinZ+Extent
&&CandidateMinZ<ExistingMinZ+ExistingExtent;
if(bOverlapX&&bOverlapY&&bOverlapZ)
{bOverlapsClipmapTile=true;break;}
}
// Preserve the clipmap's non-overlapping 3D partition. Where another
// requested tile already occupies this cap volume, that tile owns the
// shared roof surface; never add an overlapping LOD sibling.
// Garder la partition 3D sans recouvrement. Une tuile deja presente
// possede la surface de toit partagee; ne pas ajouter un voisin LOD superpose.
if(bOverlapsClipmapTile)continue;
tiles.push_back({{Identity[0],Identity[1],Identity[2]},Identity[3]});
}
}
}
}
std::sort(tiles.begin(),tiles.end(),[&](const TileKey& a,const TileKey& b)
{
const double da=TileDistanceSquared(a,{center.X,center.Y,center.Z});
@@ -1201,7 +1266,7 @@ namespace VoxelForgeCore
&&options.mesherRecipe!=MesherRecipe::worldAssemblerHybridV1
&&options.mesherRecipe!=MesherRecipe::worldAssemblerHybridV2)
{error="tile mesher recipe version is unsupported";return std::nullopt;}
if(level>=5&&options.farHorizonVersion==0)
if(level>=4&&options.farHorizonVersion==0)
{error="far-horizon recipe version must be nonzero";return std::nullopt;}
TArray<FVoxelHybridSharpFeatureBox> sharpFeatures;
if(options.mesherRecipe!=MesherRecipe::marchingCubesV1&&level==0&&impl_->worldAssembly)
@@ -1501,7 +1566,7 @@ namespace VoxelForgeCore
(options.hashDensity||options.captureDensitySamples)?&densityValues:nullptr);
const double MeshingMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-MeshingStart).count();
out.diagnostics.farHorizonVersion=key.lod>=5?options.farHorizonVersion:0;
out.diagnostics.farHorizonVersion=key.lod>=4?options.farHorizonVersion:0;
const auto FarShellStart=std::chrono::steady_clock::now();
const FStandaloneShapeWorld& farShape=tileShape.HasFarWorld()?tileShape:*impl_->shape;
out.diagnostics.farShellRepairSkipped=bSkipFarShellRepair;
@@ -1533,11 +1598,12 @@ namespace VoxelForgeCore
}
out.diagnostics.farShellMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-FarShellStart).count();
if(impl_->worldAssembly&&key.lod>=5&&!bOverlapsPlayerEdit)
if(impl_->worldAssembly&&key.lod>=4&&!bOverlapsPlayerEdit)
{
const auto HorizonStart=std::chrono::steady_clock::now();
const auto GroundStats=RefineFarNativeGround(
world,*impl_->worldAssembly,nativeKey,mesh);
FNativeCapRefinementStats GroundStats;
if(key.lod>=4)
GroundStats=RefineFarNativeGround(world,*impl_->worldAssembly,nativeKey,mesh);
const auto CapStats=RefineFarNativeCap(world,*impl_->worldAssembly,nativeKey,mesh);
out.diagnostics.farHorizonMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-HorizonStart).count();
@@ -1612,7 +1678,7 @@ namespace VoxelForgeCore
{ densityHash^=std::bit_cast<std::uint32_t>(value);densityHash*=1099511628211ull; }
out.densityHash=densityHash;out.meshHash=HashViewerMesh(mesh);
out.payloadHash=HashPayload(mesh);out.topologyHash=HashTopology(mesh);
if(key.lod>=5)
if(key.lod>=4)
{
out.meshHash=SaltFarHorizonHash(out.meshHash,options.farHorizonVersion);
out.payloadHash=SaltFarHorizonHash(out.payloadHash,options.farHorizonVersion);
+61 -1
View File
@@ -1463,8 +1463,9 @@ namespace world_assembly_detail
+secondaryHeight*(65536-primaryWeight))/65536;
out.biomeId=primary->stableId;out.neighborBiomeId=secondary->stableId;
out.biomeWeightQ16=primaryWeight;
out.capHeightSubvoxels=plan.capHeightSubvoxels+MulQ16(plan.capUndulationSubvoxels,
std::int64_t cap=plan.capHeightSubvoxels+MulQ16(plan.capUndulationSubvoxels,
Noise2D(x,y,plan.capWavelengthSubvoxels,recipe.seed,0x4341505f554e4431ull));
out.capHeightSubvoxels=cap;
out.waterSurfaceSubvoxels=plan.waterSurfaceSubvoxels;
return out;
}
@@ -1816,6 +1817,65 @@ bool Heightfield2D::isValid() const noexcept
});
}
std::array<std::int64_t,2> Heightfield2D::capHeightBounds() const noexcept
{
if(!isValid())return {0,0};
long double Minimum=std::numeric_limits<long double>::infinity();
long double Maximum=-std::numeric_limits<long double>::infinity();
const auto IncludeBiome=[&](const WorldAssemblyBiomeProfileV1& Biome)
{
const long double Base=Biome.hasCapProfile
?static_cast<long double>(Biome.capHeightSubvoxels)
:static_cast<long double>(plan_->capHeightSubvoxels);
const long double Undulation=Biome.hasCapProfile
?static_cast<long double>(Biome.capUndulationSubvoxels)
:static_cast<long double>(plan_->capUndulationSubvoxels);
const long double Detail=Biome.hasCapProfile
?static_cast<long double>(Biome.capDetailAmplitudeSubvoxels)
:static_cast<long double>(plan_->capDetailAmplitudeSubvoxels);
const long double Ridge=Biome.hasCapProfile
?static_cast<long double>(Biome.capRidgeAmplitudeSubvoxels)
:static_cast<long double>(plan_->capRidgeAmplitudeSubvoxels);
Minimum=std::min(Minimum,Base-Undulation-Detail-Ridge);
Maximum=std::max(Maximum,Base+Undulation);
};
if(recipe_->biomes.empty())
{
const WorldAssemblyBiomeProfileV1 Fallback{};
IncludeBiome(Fallback);
}
else for(const auto& Biome:recipe_->biomes)IncludeBiome(Biome);
long double FeatureAmplitude=0.0L;
for(const auto& Feature:plan_->features)
if(Feature.type==3)
FeatureAmplitude+=std::abs(static_cast<long double>(Feature.parametersSubvoxels[0]));
Minimum-=FeatureAmplitude;Maximum+=FeatureAmplitude;
if(recipe_->evaluatorVersion>=5)
{
const long double TopSubvoxels=(static_cast<long double>(plan_->topChunkZ)+1.0L)
*CoreTileVoxelCount*WorldAssemblySubvoxelsPerVoxel;
Minimum=std::min(Minimum,TopSubvoxels);
Maximum=std::min(Maximum,TopSubvoxels);
}
const long double Int64Minimum=static_cast<long double>(std::numeric_limits<std::int64_t>::min());
const long double Int64Maximum=static_cast<long double>(std::numeric_limits<std::int64_t>::max());
return {static_cast<std::int64_t>(std::clamp(Minimum,Int64Minimum,Int64Maximum)),
static_cast<std::int64_t>(std::clamp(Maximum,Int64Minimum,Int64Maximum))};
}
std::int64_t Heightfield2D::farSurfaceCapHeightSubvoxels(std::int64_t x,
std::int64_t y) const noexcept
{
if(!isValid())return 0;
const HeightfieldPointSample column=point(x,y,0);
if(recipe_->evaluatorVersion<5)return column.capHeightSubvoxels;
// Clip only the far render surface. Keep the near density evaluator bit-identical.
// Borner uniquement le plafond lointain. L'evaluateur de densite proche reste identique.
const std::int64_t ownedUpperBoundary=(static_cast<std::int64_t>(plan_->topChunkZ)+1)
*CoreTileVoxelCount*WorldAssemblySubvoxelsPerVoxel;
return std::min(column.capHeightSubvoxels,ownedUpperBoundary);
}
WorldAssemblyFeatureTileListV1 Heightfield2D::buildFeatureTileList(
const std::array<std::int64_t,3>& minimum,
const std::array<std::int64_t,3>& maximum) const
@@ -76,6 +76,25 @@ Nothing about the brief or the order of your runs made this round harder. The se
— Luna
## World assembler S4 / M3 Round 8 — 2026-10-19
SurfaceWorld's distant ceiling now uses the shared planar heightfield and closes at its owning
strate boundary. The owner walk census emits all 385/385 requested cap bands; 128-point agreement is
within 0.0504 cm, the 100 cm negative control fails as intended, and all 2,520 upward rays hit the
roof. LOD0–LOD3 hashes remain identical to S3/S2. Warmed SurfaceWorld LOD7/8 p95 changes are +0.03%
and +0.11%; the full cold clipmap adds 132 ms. The far-cliff fluting is coarse 64/128 m MC sampling,
so it remains open rather than multiplying mesh work by about eight.
Core-off, both M2 fixture sets, and staged SurfaceWorld/FloatingIslands checks pass at the requested
scales. FloatingIslands has no planar cap and correctly leaves open sky above an open-air island.
Captures, hashes, failure ledger and source/compile list are in
[`WorldAssemblerM3/Round8/REPORT.md`](../../WorldAssemblerM3/Round8/REPORT.md). CODEMAP section 3 and
ARCHITECTURE section 8.25 are updated. No new source file, owner asset edit, commit, push or stash.
— Luna
## Claude, after step 26 (2026-10-08, night)
Thank you, Luna. Naming `DEVICE_HUNG` down to the tile and the slot was the best kind of answer:
the owner's PC has had unexplained hard reboots, and "it was our out-of-bounds copy, in an audit-only
@@ -0,0 +1,137 @@
# World assembler S4 / M3 Round 8
Date: 2026-10-19. Base: S3 / `d0f97bf`. No commit, push or stash.
## Result
SurfaceWorld now has a continuous far ceiling at LOD5–8, projected from the same declared planar
heightfield and closed at the owning strate's upper boundary. The staged owner's real plan and walk
view pass cap census, root agreement and upward-ray coverage. LOD0–LOD3 hashes still match S3 and S2.
The far recipe is version 2. FloatingIslands still shows open sky overhead; it has no declared planar
cap, and that is expected for an open-air island strate.
## Count first: why S3 looked detached
The pre-fix owner-camera audit found 361 far XY tiles and 786,153 profile samples; all profile samples
had a roof. Of 401 cap bands requested, 401 emitted triangles, with 0 requested bands empty and 0
clipmap culls. So the proposed ground-height gate was not leaving requested cap bands unmeshed on this
walk view. The 128-point cap-to-near-root check did fail: maximum vertical error was 823.8525 cm
(one sample was -447.0469 voxels at the far cap versus -480.001 at the near root). The failure was
the cap datum sitting above its owning boundary, which made the roof read as detached pieces. The
128-voxel lattice itself was not leaving empty bands.
The fix is a render-surface projection to `(topChunkZ + 1) * 32` voxels, the owning strate's upper
boundary. `Heightfield2D::point()` and density values remain unchanged. The far cap and its bounds use
the shared projected height; the tile selector adds only non-overlapping cap bands. All samples use a
global XY lattice so neighboring cap tiles share edges. LOD4 uses a 16-voxel grid step; LOD5–8 use
128 voxels.
Post-fix audit: 385/385 requested cap bands emitted positive-area triangles (LOD4 88/88, LOD5 48/48,
LOD6 48/48, LOD7 48/48, LOD8 153/153); 0 empty and 0 culled. Across 128 shared XY points, far cap to
near-root error is at most 0.0504 cm (2 cm tolerance). A 100 cm datum-offset negative control measured
100.0015 cm and was detected. The S3 ground agreement still passes: max LOD7/8 to near-root error
0.0427 cm, cross-LOD error 0, and its 100 cm control is detected.
Coverage uses emitted cap triangles, not the height profile alone. At each of 33 owner route points
and two camera points, 72 upward rays span elevations 5, 10, 12, 15, 30, 45, 60, 75 and 90 degrees
over eight azimuths. Result: 2,520/2,520 hit the cap before the far clip or clipmap edge (100%);
0 profile-roof, mesh or clip-edge misses. All 35 points individually reached 100%. This verifies the
owner route and camera samples, not every possible point in the full strate volume.
## Visuals and fluting
Matched captures use the Round 7 views, the same staged plan and camera positions, 60 fps/VSync, and
the viewer closed after capture. Each S4 JPEG is 640x400 and under 19 KB.
| View | S3 | S4 | Readout |
|---|---|---|---|
| Owner walk horizon | [S3](../Round7/captures/after_s3_surface.jpg) | [S4](captures/s4_walk_horizon.jpg) | Walk horizon view after cap repair. |
| Cap at distance | [S3](../Round7/captures/after_s3_cap.jpg) | [S4](captures/s4_cap_distance.jpg) | The isolated-looking pieces are gone. |
| Far view, y=-1800 m | [S3](../Round7/captures/after_s3_far.jpg) | [S4](captures/s4_far_y_minus_1800.jpg) | Far-cliff fluting remains. |
| Looking straight up, far distance | — | [S4](captures/s4_far_straight_up.jpg) | Dark and low contrast; geometry/ray audit establishes the roof, pixels alone do not distinguish roof from dark sky. |
Fluting is coarse marching-cubes sampling on steep ground faces. Each far tile spans 16 coarse cells
per side: at 25 cm, LOD7's step is 256 voxels (64 m), LOD8's is 512 voxels (128 m). The strips cross
tile faces rather than appearing only at LOD seams; they predate S4 in S2/S3. Certified SurfaceWorld
tiles skip shell repair, native replacement affects upward-facing ground only, and this is not a
normal or backface-culling artifact. Refining all steep faces would multiply far 3D mesh work by
roughly eight; that is not a cheap shared fix, so S4 leaves it open.
## Timing, determinism and regression checks
SurfaceWorld timings are warmed p95s over the same eight staged 25 cm owner keys per LOD as S3.
Runs were serial at normal priority with no overlapping build or Unreal process. These are tile times,
not frame times.
| LOD | S3 full p95 | S4 full p95 | Delta |
|---:|---:|---:|---:|
| 7 | 19.801 ms | 19.8069 ms | +0.0059 ms (+0.03%) |
| 8 | 58.346 ms | 58.4113 ms | +0.0653 ms (+0.11%) |
The standalone cold full-clipmap benchmark took 3.107 s versus S3's 2.975 s on the same 2,553-tile,
12-worker workload: +132 ms (+4.4%). Far closure is therefore effectively flat in warmed owner tile
p95, with a small whole-clipmap cost. LOD8 cap refinement covered 385 tiles / 757,540 grid cells and
generated 1,515,082 cap triangles.
* SurfaceWorld BuildHost at 25 cm: PASS; W1/W8/W16 stable at density `0cd2a1a4152ee4aa`, mesh
`80a5b054b904b1a2`, payload `bf2f1b40dff38acc`, topology `56074198682d5e18`.
* FloatingIslands BuildHost at 25 cm: PASS; W1/W8/W16 stable and standalone hashes match. Its plan
contains 4 islands, 3 connectors and 28 route segments; water remains fixed.
* Core off / legacy at 12.5 cm: PASS.
* M2 HybridV1 and HybridV2 fixtures at 25 cm: PASS; each reports five analytic fixtures and one
border fixture.
* Standalone W1/W8/W16 determinism: PASS. Owner clipmap density hash remains
`c10697a8f48380c7`.
* LOD0–LOD3 hashes match S3 and S2 exactly:
| LOD | Density | Mesh | Payload | Topology |
|---:|---|---|---|---|
| 0 | `769f2a706d585a72` | `33eeeb39fa443816` | `645621a1d968983f` | `c2457ed905036c9d` |
| 1 | `69cc5a5c0a2c60af` | `b48335f5410c57d5` | `d15c5480162ab8ba` | `feca1bd025823604` |
| 2 | `85deed5683a77202` | `53469895987aeea2` | `e55f8ae7e1532033` | `d5feb12a0e85c09b` |
| 3 | `6518caefb3be7e7f` | `ec513c90b853a614` | `f62fa1137ff17f82` | `ccf1dcf681965816` |
Far output changes are salted by far recipe v2 in mesh, payload and topology hashes from LOD4 upward.
The final Standalone build and BuildHost Core compile/link-safety check pass. The editor commandlet
uses explicit RealtimeMesh section ranges for cap-only and ground/cap tiles. Final reruns had no
ensure. No new `UECC-*` folder appeared; the only crash directory is the pre-existing 2026-09-17
folder. No run hit
`0xC0000142`; all commandlets stayed below 4 GiB peak private memory. The surface commandlet was the
longest run at about 10 minutes, within the 15-minute limit.
The Standalone build also printed nonfatal environment/compiler warnings: `vswhere.exe` was not
recognized by the build script, and C4838 remains at `VoxelStrateManager.cpp:3974–3975`.
### Failed and retried runs
* The first post-fix coverage pass used a camera above the roof and reported 97.143% (72 rays, all
misses from that invalid origin). Re-running from the staged owner walk height passed 100%.
* The first clamp used the wrong chunk boundary and altered point density, changing the LOD3 density
hash. It was corrected to the upper boundary and render-only API; final LOD0–LOD3 hashes match S3.
* One hash invocation omitted `--stream-benchmark` and entered the interactive viewer; it was stopped
after 146 s and rerun with the correct mode. An absolute capture output path was split at the
workspace spaces by `Start-Process`; relative paths worked. A JPEG helper syntax error was corrected.
* An early BuildHost mesh apply raised an ensure when a cap material section did not yet exist.
Explicit `CreateSection` ranges fixed it; final SurfaceWorld and fixture runs pass without a new
crash or ensure. No `0xC0000142` retry was needed.
## Source and compile spots
No new source file was added. Modified sources:
* `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`,
`Standalone/Core/src/WorldAssemblerInternal.h`, `Standalone/Core/src/VoxelForgeCore.cpp` — shared
cap declaration API, clipped render surface, conservative bounds, cap tile selection/emission,
and far recipe version; compile through the Standalone Core build and BuildHost Core.
* `Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp` — owner cap census, agreement and
ray coverage audit; compile through the editor module / BuildHost commandlet.
* `Source/VoxelForge/Private/VoxelWorld.cpp` — explicit realtime mesh section ranges; compile through
the VoxelForge runtime module.
* `Standalone/Source/StandaloneViewer.cpp` — standalone audit and matched capture support; compile
through `Standalone/Build.ps1 -Target All`.
`CODEMAP.md` section 3 and `ARCHITECTURE.md` section 8.25 are updated. The API leaves the roof family
choice in the declared plan, so future cave-in-mountain families can get a far roof by declaring one;
no SurfaceWorld-only geometry rule is required. The owner need not change assets or settings: keep
Core enabled at 25 cm. Sprint streaming order and the 1.57 s cold-view target were not changed or
re-measured.
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+438 -3
View File
@@ -22,6 +22,7 @@
#include <windowsx.h>
#include <atomic>
#include <array>
#include <bit>
#include <complex>
#include <cstdio>
@@ -37,6 +38,7 @@
#include <mutex>
#include <numeric>
#include <optional>
#include <set>
#include <sstream>
#include <thread>
#include <unordered_map>
@@ -8311,8 +8313,435 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
return true;
}
bool RunWorldAssemblerCapAudit(FStandaloneOwnerWorld& owner,
const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,VoxelForgeCore::World& world,
VoxelForgeCore::Vec3d walkCameraVoxels)
{
// This audit follows the shipped owner manifest and Core clipmap, not the transient BuildHost fixture.
// Cet audit suit le manifeste owner livre et le clipmap Core, pas le fixture BuildHost transitoire.
constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
constexpr double Pi=3.14159265358979323846;
constexpr double RayStepVoxels=128.0;
constexpr double AgreementToleranceCm=2.0;
constexpr double NegativeDatumOffsetCm=100.0;
using FTileId=std::array<std::int32_t,4>;
using FXYLod=std::array<std::int32_t,3>;
const double VoxelSizeCm=static_cast<double>(world.configuration().voxelSizeMicrons)/10000.0;
const auto IdFor=[](const VoxelForgeCore::TileKey& key)
{return FTileId{key.coordinate.x,key.coordinate.y,key.coordinate.z,key.lod};};
const auto FloorDiv64=[](std::int64_t value,std::int64_t divisor)
{
const std::int64_t quotient=value/divisor,remainder=value%divisor;
return quotient-((remainder!=0&&remainder<0)?1:0);
};
const auto* manifest=snapshot.worldAssembly();
if(!manifest||manifest->plan.strates.empty())
{std::fprintf(stderr,"[WorldAssemblerFarCapAudit] no SurfaceWorld plan; status=FAIL\n");return false;}
const auto planIt=std::find_if(manifest->plan.strates.begin(),manifest->plan.strates.end(),
[](const auto& plan){return !plan.route.empty();});
if(planIt==manifest->plan.strates.end())
{std::fprintf(stderr,"[WorldAssemblerFarCapAudit] no authored walk route; status=FAIL\n");return false;}
const auto& plan=*planIt;
const VoxelForgeCore::Heightfield2D field(manifest->recipe,plan);
if(!field.isValid())
{std::fprintf(stderr,"[WorldAssemblerFarCapAudit] invalid Heightfield2D; status=FAIL\n");return false;}
struct FView
{
VoxelForgeCore::Vec3d Origin{};
std::vector<VoxelForgeCore::TileKey> Keys;
std::set<FTileId> KeySet;
VoxelForgeCore::TileGenerationOptions Options;
double ClipMinX=std::numeric_limits<double>::infinity();
double ClipMinY=std::numeric_limits<double>::infinity();
double ClipMaxX=-std::numeric_limits<double>::infinity();
double ClipMaxY=-std::numeric_limits<double>::infinity();
double ClipMaxZ=-std::numeric_limits<double>::infinity();
};
const auto MakeView=[&](VoxelForgeCore::Vec3d origin)
{
FView view;view.Origin=origin;
const FStandaloneDesiredTileSet native=StandaloneWorldMesher::BuildDesiredSet(owner,
FVector(origin.x,origin.y,origin.z));
view.Options.bandMinZVoxel=native.bHasStrate
?native.StrateBottomChunkZ*CHUNK_SIZE:MIN_int32;
view.Options.bandMaxZVoxel=native.bHasStrate
?(native.StrateTopChunkZ+1)*CHUNK_SIZE:MAX_int32;
view.Keys=world.desiredTiles(origin);
for(const auto& key:view.Keys)
{
view.KeySet.insert(IdFor(key));
const double extent=static_cast<double>(CHUNK_SIZE<<key.lod);
view.ClipMaxZ=std::max(view.ClipMaxZ,(key.coordinate.z+1.0)*extent);
if(key.lod<4||key.lod>8)continue;
view.ClipMinX=std::min(view.ClipMinX,key.coordinate.x*extent);
view.ClipMinY=std::min(view.ClipMinY,key.coordinate.y*extent);
view.ClipMaxX=std::max(view.ClipMaxX,(key.coordinate.x+1.0)*extent);
view.ClipMaxY=std::max(view.ClipMaxY,(key.coordinate.y+1.0)*extent);
}
return view;
};
const FView cameraView=MakeView(walkCameraVoxels);
std::set<FXYLod> farXY;
for(const auto& key:cameraView.Keys)
if(key.lod>=4&&key.lod<=8)farXY.insert({key.coordinate.x,key.coordinate.y,key.lod});
std::set<FTileId> capBands;
std::uint64_t profileSamples=0,profileSamplesWithoutRoof=0;
for(const FXYLod& xy:farXY)
{
const std::int32_t lod=xy[2];
const std::int64_t extent=static_cast<std::int64_t>(CHUNK_SIZE)<<lod;
const std::int64_t originX=static_cast<std::int64_t>(xy[0])*extent;
const std::int64_t originY=static_cast<std::int64_t>(xy[1])*extent;
const std::int64_t gridStep=lod<5?std::min<std::int64_t>(128,1ll<<lod):128;
for(std::int64_t y=0;y<=extent;y+=gridStep)
for(std::int64_t x=0;x<=extent;x+=gridStep)
{
++profileSamples;
const auto column=field.point((originX+x)*Scale,(originY+y)*Scale,0);
const std::int64_t farCap=field.farSurfaceCapHeightSubvoxels(
(originX+x)*Scale,(originY+y)*Scale);
if(farCap<=column.groundHeightSubvoxels)
{++profileSamplesWithoutRoof;continue;}
const std::int64_t band=FloorDiv64(farCap,extent*Scale);
if(band>=MIN_int32&&band<=MAX_int32)
capBands.insert({xy[0],xy[1],static_cast<std::int32_t>(band),lod});
if(farCap%(extent*Scale)==0&&band>MIN_int32)
capBands.insert({xy[0],xy[1],static_cast<std::int32_t>(band-1),lod});
}
}
struct FAgreement {std::int64_t X=0,Y=0;double FarZ=0.0;};
struct FGeometry
{
std::vector<std::array<VoxelForgeCore::Vec3d,3>> DownwardTriangles;
std::uint64_t CapTriangles=0;
std::vector<FAgreement> AgreementVertices;
};
constexpr std::int64_t AgreementGrid=128*Scale;
std::map<FTileId,FGeometry> geometryCache;
std::string coreError;
const auto GetGeometry=[&](const FTileId& id,const VoxelForgeCore::TileGenerationOptions& options)
->const FGeometry*
{
if(const auto found=geometryCache.find(id);found!=geometryCache.end())return &found->second;
const VoxelForgeCore::TileKey key{{id[0],id[1],id[2]},id[3]};
const auto mesh=world.generateTile(key,options,coreError);
if(!mesh)return nullptr;
FGeometry geometry;
geometry.CapTriangles=mesh->diagnostics.horizonCapTriangles;
const std::size_t capIndexStart=mesh->indices.size()
-static_cast<std::size_t>(geometry.CapTriangles)*3u;
for(std::size_t index=0;index+2<mesh->indices.size();index+=3)
{
const auto ia=mesh->indices[index],ib=mesh->indices[index+1],ic=mesh->indices[index+2];
if(ia>=mesh->vertices.size()||ib>=mesh->vertices.size()||ic>=mesh->vertices.size())continue;
const auto& a=mesh->vertices[ia];const auto& b=mesh->vertices[ib];const auto& c=mesh->vertices[ic];
if((a.normal.z+b.normal.z+c.normal.z)/3.0>=-0.05)continue;
geometry.DownwardTriangles.push_back({
VoxelForgeCore::Vec3d{a.position.x/VoxelSizeCm,a.position.y/VoxelSizeCm,a.position.z/VoxelSizeCm},
VoxelForgeCore::Vec3d{b.position.x/VoxelSizeCm,b.position.y/VoxelSizeCm,b.position.z/VoxelSizeCm},
VoxelForgeCore::Vec3d{c.position.x/VoxelSizeCm,c.position.y/VoxelSizeCm,c.position.z/VoxelSizeCm}});
}
for(std::size_t index=capIndexStart;index<mesh->indices.size();++index)
{
const std::uint32_t vertexIndex=mesh->indices[index];
if(vertexIndex>=mesh->vertices.size())continue;
const auto& vertex=mesh->vertices[vertexIndex];
if(vertex.normal.z>=-0.35)continue;
const std::int64_t x=static_cast<std::int64_t>(std::llround(
vertex.position.x/VoxelSizeCm*Scale));
const std::int64_t y=static_cast<std::int64_t>(std::llround(
vertex.position.y/VoxelSizeCm*Scale));
if(x%AgreementGrid!=0||y%AgreementGrid!=0)continue;
geometry.AgreementVertices.push_back({x,y,vertex.position.z/VoxelSizeCm});
}
return &geometryCache.emplace(id,std::move(geometry)).first->second;
};
std::uint64_t requested=0,emitted=0,requestedWithoutTriangles=0,culled=0;
std::uint64_t zeroAreaBoundaryTouches=0,unexplainedEmptyBands=0;
std::map<std::int32_t,std::array<std::uint64_t,4>> byLod;
std::set<std::pair<std::int64_t,std::int64_t>> agreementXY;
std::vector<FAgreement> agreementSamples;agreementSamples.reserve(128);
for(const FTileId& id:capBands)
{
auto& count=byLod[id[3]];++count[0];
if(!cameraView.KeySet.contains(id)){++culled;++count[1];continue;}
++requested;
const FGeometry* geometry=GetGeometry(id,cameraView.Options);
if(geometry==nullptr)
{
std::fprintf(stderr,"[WorldAssemblerFarCapAudit] tile generation failed key=(%d,%d,%d,lod%d): %s\n",
id[0],id[1],id[2],id[3],coreError.c_str());return false;
}
if(geometry->CapTriangles==0)
{
++requestedWithoutTriangles;++count[3];
const std::int64_t extent=static_cast<std::int64_t>(VoxelForgeCore::CoreTileVoxelCount)<<id[3];
const std::int64_t step=id[3]<5?std::min<std::int64_t>(128,1ll<<id[3]):128;
const std::int64_t minZ=static_cast<std::int64_t>(id[2])*extent*Scale;
const std::int64_t maxZ=minZ+extent*Scale;
const std::int64_t originX=static_cast<std::int64_t>(id[0])*extent;
const std::int64_t originY=static_cast<std::int64_t>(id[1])*extent;
std::uint64_t validSamples=0,boundarySamples=0,interiorSamples=0;
for(std::int64_t y=0;y<=extent;y+=step)
for(std::int64_t x=0;x<=extent;x+=step)
{
const auto column=field.point((originX+x)*Scale,(originY+y)*Scale,0);
const std::int64_t farCap=field.farSurfaceCapHeightSubvoxels(
(originX+x)*Scale,(originY+y)*Scale);
if(farCap<=column.groundHeightSubvoxels||farCap<minZ||farCap>maxZ)continue;
++validSamples;
if(farCap==minZ||farCap==maxZ)++boundarySamples;
else ++interiorSamples;
}
const bool zeroAreaTouch=validSamples>0&&boundarySamples==validSamples
&&interiorSamples==0;
if(zeroAreaTouch)++zeroAreaBoundaryTouches;else ++unexplainedEmptyBands;
std::printf("[WorldAssemblerFarCapEmptyBand] key=(%d,%d,%d,lod%d) valid_profile_samples=%llu boundary_samples=%llu interior_samples=%llu classification=%s\n",
id[0],id[1],id[2],id[3],static_cast<unsigned long long>(validSamples),
static_cast<unsigned long long>(boundarySamples),static_cast<unsigned long long>(interiorSamples),
zeroAreaTouch?"zero_area_boundary_touch":"UNEXPLAINED");
continue;
}
++emitted;++count[2];
for(const FAgreement& sample:geometry->AgreementVertices)
{
if(agreementSamples.size()>=128)break;
if(!agreementXY.insert({sample.X,sample.Y}).second)continue;
agreementSamples.push_back(sample);
}
}
std::uint64_t agreementCompared=0;
double maximumAgreementCm=0.0,maximumNegativeControlCm=0.0;
FAgreement maximumAgreementSample{};double maximumAgreementNearRoot=0.0;
for(const FAgreement& sample:agreementSamples)
{
const auto column=field.point(sample.X,sample.Y,0);
const std::int64_t farCap=field.farSurfaceCapHeightSubvoxels(sample.X,sample.Y);
if(farCap<=column.groundHeightSubvoxels)continue;
const double x=static_cast<double>(sample.X)/Scale,y=static_cast<double>(sample.Y)/Scale;
const double capVoxel=static_cast<double>(farCap)/Scale;
bool foundRoot=false;double nearRoot=0.0;
for(double radius=4.0;radius<=4096.0;radius*=2.0)
{
double lo=capVoxel-radius,hi=capVoxel+radius;
if(!(world.densityAt({x,y,lo})>=0.0f&&world.densityAt({x,y,hi})<0.0f))continue;
for(int iteration=0;iteration<16;++iteration)
{const double mid=(lo+hi)*0.5;if(world.densityAt({x,y,mid})>=0.0f)lo=mid;else hi=mid;}
nearRoot=(lo+hi)*0.5;foundRoot=true;break;
}
if(!foundRoot)continue;
const double sampleErrorCm=std::abs(sample.FarZ-nearRoot)*VoxelSizeCm;
if(sampleErrorCm>maximumAgreementCm)
{maximumAgreementCm=sampleErrorCm;maximumAgreementSample=sample;maximumAgreementNearRoot=nearRoot;}
maximumNegativeControlCm=std::max(maximumNegativeControlCm,
std::abs(sample.FarZ+NegativeDatumOffsetCm/VoxelSizeCm-nearRoot)*VoxelSizeCm);
++agreementCompared;
}
if(agreementCompared>0)
{
const double capVoxel=static_cast<double>(field.farSurfaceCapHeightSubvoxels(
maximumAgreementSample.X,maximumAgreementSample.Y))/Scale;
const double x=static_cast<double>(maximumAgreementSample.X)/Scale;
const double y=static_cast<double>(maximumAgreementSample.Y)/Scale;
std::printf("[WorldAssemblerFarCapAgreementMax] xy_vox=(%.1f,%.1f) profile_cap_vox=%.4f far_cap_vox=%.4f near_root_vox=%.4f density_at_cap=%.4f density_below=%.4f density_above=%.4f\n",
x,y,capVoxel,maximumAgreementSample.FarZ,maximumAgreementNearRoot,
world.densityAt({x,y,capVoxel}),world.densityAt({x,y,capVoxel-4.0}),
world.densityAt({x,y,capVoxel+4.0}));
}
const bool negativeControlDetected=agreementCompared>0
&&maximumNegativeControlCm>AgreementToleranceCm;
std::printf("[WorldAssemblerFarCapCensus] view=owner_camera far_xy_tiles=%zu profile_samples=%llu samples_without_roof=%llu cap_bands=%zu requested=%llu emitted=%llu requested_without_triangles=%llu zero_area_boundary_touches=%llu unexplained_empty_bands=%llu culled_by_clipmap=%llu\n",
farXY.size(),static_cast<unsigned long long>(profileSamples),
static_cast<unsigned long long>(profileSamplesWithoutRoof),capBands.size(),
static_cast<unsigned long long>(requested),static_cast<unsigned long long>(emitted),
static_cast<unsigned long long>(requestedWithoutTriangles),
static_cast<unsigned long long>(zeroAreaBoundaryTouches),
static_cast<unsigned long long>(unexplainedEmptyBands),static_cast<unsigned long long>(culled));
for(const auto& [lod,count]:byLod)
std::printf("[WorldAssemblerFarCapLod] lod=%d cap_bands=%llu culled=%llu emitted=%llu requested_without_triangles=%llu\n",
lod,static_cast<unsigned long long>(count[0]),static_cast<unsigned long long>(count[1]),
static_cast<unsigned long long>(count[2]),static_cast<unsigned long long>(count[3]));
std::printf("[WorldAssemblerFarCapAgreement] status=%s shared_points=%llu max_far_near_cm=%.4f tolerance_cm=%.2f negative_control=100cm_datum_offset max_error_cm=%.4f detected=%d\n",
agreementCompared>=32&&maximumAgreementCm<=AgreementToleranceCm&&negativeControlDetected?"PASS":"FAIL",
static_cast<unsigned long long>(agreementCompared),maximumAgreementCm,AgreementToleranceCm,
maximumNegativeControlCm,negativeControlDetected?1:0);
constexpr std::array<double,8> azimuths={0.0,45.0,90.0,135.0,180.0,225.0,270.0,315.0};
constexpr std::array<double,9> elevations={5.0,10.0,12.0,15.0,30.0,45.0,60.0,75.0,90.0};
const auto dot3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b)
{return a.x*b.x+a.y*b.y+a.z*b.z;};
const auto sub3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b)
{return VoxelForgeCore::Vec3d{a.x-b.x,a.y-b.y,a.z-b.z};};
const auto cross3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b)
{return VoxelForgeCore::Vec3d{a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};};
const auto rayTriangle=[&](const VoxelForgeCore::Vec3d& origin,const VoxelForgeCore::Vec3d& direction,
const std::array<VoxelForgeCore::Vec3d,3>& triangle,double minDistance,double maxDistance)
{
const auto edge1=sub3(triangle[1],triangle[0]),edge2=sub3(triangle[2],triangle[0]);
const auto p=cross3(direction,edge2);const double determinant=dot3(edge1,p);
if(std::abs(determinant)<1.0e-12)return false;
const double inverse=1.0/determinant;const auto t=sub3(origin,triangle[0]);
const double u=dot3(t,p)*inverse;if(u< -1.0e-8||u>1.0+1.0e-8)return false;
const auto q=cross3(t,edge1);const double v=dot3(direction,q)*inverse;
if(v< -1.0e-8||u+v>1.0+1.0e-8)return false;
const double distance=dot3(edge2,q)*inverse;
return distance>=minDistance-1.0e-6&&distance<=maxDistance+1.0e-6;
};
std::vector<VoxelForgeCore::Vec3d> walkOrigins;
walkOrigins.reserve(plan.route.size()+1);
for(const auto& point:plan.route)
walkOrigins.push_back({static_cast<double>(point.positionSubvoxels[0])/Scale,
static_cast<double>(point.positionSubvoxels[1])/Scale,
static_cast<double>(point.positionSubvoxels[2])/Scale});
const auto sameCamera=std::find_if(walkOrigins.begin(),walkOrigins.end(),[&](const auto& point)
{return std::abs(point.x-walkCameraVoxels.x)<1.0&&std::abs(point.y-walkCameraVoxels.y)<1.0
&&std::abs(point.z-walkCameraVoxels.z)<1.0;});
if(sameCamera==walkOrigins.end())walkOrigins.push_back(walkCameraVoxels);
const VoxelForgeCore::Vec3d farStraightUpCamera{0.0,-1800.0*4.0,walkCameraVoxels.z};
const std::size_t farStraightUpIndex=walkOrigins.size();
walkOrigins.push_back(farStraightUpCamera);
std::uint64_t rayCount=0,rayHits=0,profileCrossings=0,profileRoofCrossings=0;
std::uint64_t missesNoProfileRoof=0,missesMesh=0,missesClipEdge=0;
std::array<std::uint64_t,9> raysByElevation{},hitsByElevation{};
std::vector<std::string> firstMisses;firstMisses.reserve(8);
for(std::size_t viewIndex=0;viewIndex<walkOrigins.size();++viewIndex)
{
const std::uint64_t hitsBeforeView=rayHits;
const std::uint64_t raysBeforeView=rayCount;
const auto view=MakeView(walkOrigins[viewIndex]);
if(view.ClipMinX>view.ClipMaxX||view.ClipMinY>view.ClipMaxY)continue;
const auto startColumn=field.point(
static_cast<std::int64_t>(std::llround(view.Origin.x*Scale)),
static_cast<std::int64_t>(std::llround(view.Origin.y*Scale)),0);
const double startCap=static_cast<double>(field.farSurfaceCapHeightSubvoxels(
static_cast<std::int64_t>(std::llround(view.Origin.x*Scale)),
static_cast<std::int64_t>(std::llround(view.Origin.y*Scale))))/Scale;
for(std::size_t elevationIndex=0;elevationIndex<elevations.size();++elevationIndex)
for(const double azimuth:azimuths)
{
++rayCount;++raysByElevation[elevationIndex];
const double elevation=elevations[elevationIndex]*Pi/180.0;
const double radians=azimuth*Pi/180.0;
const VoxelForgeCore::Vec3d direction{
std::cos(elevation)*std::cos(radians),std::cos(elevation)*std::sin(radians),std::sin(elevation)};
double edgeDistance=std::numeric_limits<double>::infinity();
if(direction.x>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxX-view.Origin.x)/direction.x);
else if(direction.x< -1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMinX-view.Origin.x)/direction.x);
if(direction.y>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxY-view.Origin.y)/direction.y);
else if(direction.y< -1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMinY-view.Origin.y)/direction.y);
if(direction.z>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxZ-view.Origin.z)/direction.z);
if(!std::isfinite(edgeDistance)||edgeDistance<=0.0)
{++missesClipEdge;continue;}
bool profileCrossing=false,profileRoof=false;
double previousDistance=0.0,previousDelta=view.Origin.z-startCap;
for(double distance=std::min(RayStepVoxels,edgeDistance);;)
{
const auto column=field.point(
static_cast<std::int64_t>(std::llround((view.Origin.x+direction.x*distance)*Scale)),
static_cast<std::int64_t>(std::llround((view.Origin.y+direction.y*distance)*Scale)),0);
const double cap=static_cast<double>(field.farSurfaceCapHeightSubvoxels(
static_cast<std::int64_t>(std::llround((view.Origin.x+direction.x*distance)*Scale)),
static_cast<std::int64_t>(std::llround((view.Origin.y+direction.y*distance)*Scale))))/Scale;
const double delta=view.Origin.z+direction.z*distance-cap;
if(previousDelta<0.0&&delta>=0.0)
{
const double fraction=-previousDelta/(delta-previousDelta);
const double hitX=view.Origin.x+direction.x*(previousDistance+(distance-previousDistance)*fraction);
const double hitY=view.Origin.y+direction.y*(previousDistance+(distance-previousDistance)*fraction);
const auto hitColumn=field.point(static_cast<std::int64_t>(std::llround(hitX*Scale)),
static_cast<std::int64_t>(std::llround(hitY*Scale)),0);
profileCrossing=true;++profileCrossings;
profileRoof=field.farSurfaceCapHeightSubvoxels(
static_cast<std::int64_t>(std::llround(hitX*Scale)),
static_cast<std::int64_t>(std::llround(hitY*Scale)))
>hitColumn.groundHeightSubvoxels;
if(profileRoof)++profileRoofCrossings;
break;
}
previousDistance=distance;previousDelta=delta;
if(distance>=edgeDistance)break;
distance=std::min(distance+RayStepVoxels,edgeDistance);
}
bool meshHit=false,intersectedRequestedTile=false,intersectedEmptyTile=false;
const auto& rayOrigin=view.Origin;
for(const auto& key:view.Keys)
{
const double extent=static_cast<double>(CHUNK_SIZE<<key.lod);
const double minBounds[3]={key.coordinate.x*extent,key.coordinate.y*extent,key.coordinate.z*extent};
const double maxBounds[3]={minBounds[0]+extent,minBounds[1]+extent,minBounds[2]+extent};
const double origins[3]={rayOrigin.x,rayOrigin.y,rayOrigin.z};
const double directions[3]={direction.x,direction.y,direction.z};
double enter=0.0,exit=edgeDistance;bool intersects=true;
for(int axis=0;axis<3;++axis)
{
if(std::abs(directions[axis])<1.0e-12)
{if(origins[axis]<minBounds[axis]||origins[axis]>maxBounds[axis]){intersects=false;break;}continue;}
double tNear=(minBounds[axis]-origins[axis])/directions[axis];
double tFar=(maxBounds[axis]-origins[axis])/directions[axis];
if(tNear>tFar)std::swap(tNear,tFar);
enter=std::max(enter,tNear);exit=std::min(exit,tFar);
if(enter>exit){intersects=false;break;}
}
if(!intersects||exit<0.0||enter>edgeDistance)continue;
intersectedRequestedTile=true;
const FGeometry* geometry=GetGeometry(IdFor(key),view.Options);
if(geometry==nullptr)
{std::fprintf(stderr,"[WorldAssemblerFarCapAudit] ray tile generation failed: %s\n",coreError.c_str());return false;}
if(geometry->DownwardTriangles.empty()){intersectedEmptyTile=true;continue;}
for(const auto& triangle:geometry->DownwardTriangles)
if(rayTriangle(rayOrigin,direction,triangle,std::max(0.0,enter),std::min(edgeDistance,exit)))
{meshHit=true;break;}
if(meshHit)break;
}
if(meshHit){++rayHits;++hitsByElevation[elevationIndex];continue;}
if(!profileCrossing||!profileRoof)++missesNoProfileRoof;
else ++missesMesh;
if(firstMisses.size()<8)
{
std::ostringstream message;
message<<"view="<<viewIndex<<" elevation="<<elevations[elevationIndex]
<<" azimuth="<<azimuth<<" profile_crossing="<<(profileCrossing?1:0)
<<" profile_roof="<<(profileRoof?1:0)<<" requested_tile="<<(intersectedRequestedTile?1:0)
<<" empty_tile="<<(intersectedEmptyTile?1:0);
firstMisses.push_back(message.str());
}
}
const char* viewLabel=viewIndex<plan.route.size()?"route_point":
(viewIndex==farStraightUpIndex?"far_straight_up":"owner_camera");
std::printf("[WorldAssemblerFarCapCoverageView] view=%s index=%zu origin_vox=(%.1f,%.1f,%.1f) rays=%llu hits=%llu coverage_pct=%.3f\n",
viewLabel,viewIndex,walkOrigins[viewIndex].x,walkOrigins[viewIndex].y,
walkOrigins[viewIndex].z,static_cast<unsigned long long>(rayCount-raysBeforeView),
static_cast<unsigned long long>(rayHits-hitsBeforeView),
rayCount>raysBeforeView?100.0*static_cast<double>(rayHits-hitsBeforeView)/(rayCount-raysBeforeView):0.0);
}
std::printf("[WorldAssemblerFarCapCoverage] rays=%llu hits=%llu coverage_pct=%.3f profile_crossings=%llu profile_roof_crossings=%llu misses_no_profile_roof=%llu misses_mesh=%llu misses_clip_edge=%llu view_points=%zu\n",
static_cast<unsigned long long>(rayCount),static_cast<unsigned long long>(rayHits),
rayCount?100.0*static_cast<double>(rayHits)/rayCount:0.0,
static_cast<unsigned long long>(profileCrossings),static_cast<unsigned long long>(profileRoofCrossings),
static_cast<unsigned long long>(missesNoProfileRoof),static_cast<unsigned long long>(missesMesh),
static_cast<unsigned long long>(missesClipEdge),walkOrigins.size());
for(std::size_t i=0;i<elevations.size();++i)
std::printf("[WorldAssemblerFarCapCoverageElevation] elevation_deg=%.0f rays=%llu hits=%llu\n",
elevations[i],static_cast<unsigned long long>(raysByElevation[i]),
static_cast<unsigned long long>(hitsByElevation[i]));
for(const auto& miss:firstMisses)std::printf("[WorldAssemblerFarCapCoverageMiss] %s\n",miss.c_str());
const bool censusPassing=requested>0&&unexplainedEmptyBands==0&&culled==0;
const bool agreementPassing=agreementCompared>=32&&maximumAgreementCm<=AgreementToleranceCm
&&negativeControlDetected;
const bool coveragePassing=rayCount>0&&rayHits==rayCount;
std::printf("[WorldAssemblerFarCapAudit] census=%s agreement=%s coverage=%s status=%s\n",
censusPassing?"PASS":"FAIL",agreementPassing?"PASS":"FAIL",
coveragePassing?"PASS":"FAIL",censusPassing&&agreementPassing&&coveragePassing?"PASS":"FAIL");
return censusPassing&&agreementPassing&&coveragePassing;
}
int RunWorldAssemblerAudit(FStandaloneOwnerWorld& owner,
const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,const std::string& captureDirectory)
const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,const std::string& captureDirectory,
VoxelForgeCore::World* compiledWorld,VoxelForgeCore::Vec3d walkCameraVoxels)
{
const auto* manifest=snapshot.worldAssembly();
if(!manifest||manifest->plan.strates.empty())
@@ -8858,9 +9287,11 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
std::printf("[WorldAssemblerReadiness] local_field_query=%s analytic_collision_validation=%s physics_collision_cooking=deferred_to_Unreal_adapter render_mesh_readiness=reported_by_matched_view_runs\n",
coreQueryPass?"ready_without_render_meshes":"not_ready",
routeAudit.passed?"route_sweep_ready":"not_ready");
const bool farCapAuditPassing=compiledWorld!=nullptr
&&RunWorldAssemblerCapAudit(owner,snapshot,*compiledWorld,walkCameraVoxels);
return bounds.passed&&shelfThickness.passed&&routeAudit.passed
&&routeSupportNegativeControl&&cliffRegressionPassing&&seamClassificationPassing
&&deterministic&&coreQueryPass?0:11;
&&deterministic&&coreQueryPass&&farCapAuditPassing?0:11;
}
}
@@ -9254,7 +9685,11 @@ int main(int Argc,char** Argv)
App.bRoundTunnelEnhanced,Error);
if(!App.Snapshot)
{std::fprintf(stderr,"World assembler snapshot setup failed: %s\n",Error.c_str());return 2;}
return RunWorldAssemblerAudit(*App.World,App.Snapshot,WorldAssemblyCaptureDir);
App.bShapeWorld=true;
if(!App.BuildShapeWorldForCamera(Error,true,false,true))
{std::fprintf(stderr,"World assembler cap audit shape build failed: %s\n",Error.c_str());return 2;}
return RunWorldAssemblerAudit(*App.World,App.Snapshot,WorldAssemblyCaptureDir,
App.ShapeWorld.get(),{App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0});
}
const bool bNeedFarShapeWorld=bStreamBenchmark
?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels)