wip(assembler): round L12 -- region pages keep LOD1 block proofs: 24 m crossing 5x faster
Analytic region pages now retain the immutable shared manifest, so LOD1 page tiles get the L9 uniform-block proofs (71.7 -> 5.6 ms per tile). Reviewer W12 no-hash: 24 m crossing 0.898 -> 0.166 s; Luna: 1 km 5.89 -> 1.25 s. Spawn unchanged; all L1/FloatingIslands hashes and the 24 m crossing hash unchanged (W1/W12). KNOWN BUG (pre-existing, measured here): the same tile key yields different density from the base shape (manifest field) than from a region page (legacy field), sometimes different mesh too, so output depends on streaming history. To be fixed in L13. 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
b1cfaf53b8
commit
32b8670833
6 files changed
+292
-23
No files matched your search
@@ -120,6 +120,9 @@ namespace VoxelForgeCore
|
||||
struct TileGenerationStats
|
||||
{
|
||||
TileClass tileClass = TileClass::unknown;
|
||||
bool nativeOnlyRoute = false;
|
||||
bool analyticRegionPageRoute = false;
|
||||
bool nativeSurfaceTile = false;
|
||||
std::uint64_t solidBoxes = 0;
|
||||
std::uint64_t airBoxes = 0;
|
||||
std::uint64_t mixedBoxes = 0;
|
||||
@@ -1122,7 +1125,8 @@ namespace VoxelForgeCore
|
||||
const JobScheduler& scheduler, std::string& error,
|
||||
std::size_t* outCompiledTiles = nullptr,
|
||||
TileRegionCompileStats* outStats = nullptr,
|
||||
bool analyticOnly = true);
|
||||
bool analyticOnly = true,
|
||||
bool diagnosticIncludeBaseCoveredTiles = false);
|
||||
void retainTileRegions(std::span<const TileKey> desiredTiles);
|
||||
void buildFarWorld();
|
||||
bool isCompiled() const noexcept;
|
||||
|
||||
@@ -319,6 +319,7 @@ public:
|
||||
Owner=&World;WorldAssembly=InWorldAssembly;
|
||||
WorkerCount=std::clamp(Workers,1,16);DetailVariant=Variant;
|
||||
Scheduler=InScheduler;RoundTunnelsEnabled=bInRoundTunnels;
|
||||
bUseNativeManifestFields=true;
|
||||
bAnalyticOnly=false;
|
||||
bProfileDetailBand=bInProfileDetailBand;
|
||||
for(int32 A=0;A<3;++A)
|
||||
@@ -470,10 +471,16 @@ public:
|
||||
bool BuildAnalyticRegion(FStandaloneOwnerWorld& World,const FIntVector& MinVoxels,
|
||||
const FIntVector& MaxVoxels,const FIntVector& ClipMinVoxels,
|
||||
const FIntVector& ClipMaxVoxels,EDetailVariant Variant,
|
||||
bool bInRoundTunnels,std::string& Error)
|
||||
bool bInRoundTunnels,
|
||||
const VoxelForgeCore::WorldAssemblyManifest* InWorldAssembly,
|
||||
std::string& Error)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
Owner=&World;WorkerCount=1;DetailVariant=Variant;Scheduler=nullptr;
|
||||
Owner=&World;WorldAssembly=InWorldAssembly;
|
||||
WorkerCount=1;DetailVariant=Variant;Scheduler=nullptr;
|
||||
// Region pages use the immutable manifest for conservative block proofs, while keeping
|
||||
// the legacy SurfaceWorld density evaluator so existing tile hashes remain exact.
|
||||
bUseNativeManifestFields=false;
|
||||
RoundTunnelsEnabled=bInRoundTunnels;bAnalyticOnly=true;bProfileDetailBand=false;
|
||||
for(int32 A=0;A<3;++A)
|
||||
{
|
||||
@@ -509,7 +516,7 @@ public:
|
||||
{
|
||||
Owner=&World;WorldAssembly=InWorldAssembly;
|
||||
NativeOnlyMinimum=InMinimum;NativeOnlyMaximum=InMaximum;
|
||||
bNativeOnly=true;bAnalyticOnly=true;Built=true;
|
||||
bUseNativeManifestFields=true;bNativeOnly=true;bAnalyticOnly=true;Built=true;
|
||||
NativeOnlyViolations.store(0,std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -2050,7 +2057,7 @@ private:
|
||||
|
||||
bool NativeSurfaceDensityAt(float X,float Y,float Z,float& OutDensity) const
|
||||
{
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false;
|
||||
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CHUNK_SIZE));
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
|
||||
@@ -2075,7 +2082,7 @@ private:
|
||||
|
||||
bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const
|
||||
{
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false;
|
||||
// Convert Core query Z back to the owner's legacy chunk coordinate.
|
||||
// Convertir Z du Core vers la coordonnee de chunk legacy du proprietaire.
|
||||
@@ -5360,6 +5367,7 @@ private:
|
||||
EDetailVariant DetailVariant=EDetailVariant::Coherent;
|
||||
bool Built=false;
|
||||
bool bNativeOnly=false;
|
||||
bool bUseNativeManifestFields=false;
|
||||
FIntVector NativeOnlyMinimum=FIntVector::ZeroValue;
|
||||
FIntVector NativeOnlyMaximum=FIntVector::ZeroValue;
|
||||
mutable std::atomic<uint32> NativeOnlyViolations{0};
|
||||
|
||||
@@ -1226,7 +1226,8 @@ namespace VoxelForgeCore
|
||||
bool World::compileTileRegion(std::span<const TileKey> tiles,std::uint32_t workerLimit,
|
||||
const JobScheduler& scheduler,std::string& error,
|
||||
std::size_t* outCompiledTiles,
|
||||
TileRegionCompileStats* outStats,bool analyticOnly)
|
||||
TileRegionCompileStats* outStats,bool analyticOnly,
|
||||
bool diagnosticIncludeBaseCoveredTiles)
|
||||
{
|
||||
if(outCompiledTiles)*outCompiledTiles=0;
|
||||
if(outStats)*outStats={};
|
||||
@@ -1269,18 +1270,19 @@ namespace VoxelForgeCore
|
||||
||origin+extent>std::numeric_limits<std::int32_t>::max()-RegionPadding)
|
||||
{error="tile region coordinate is out of range";return false;}
|
||||
}
|
||||
if(CoveredByBaseShape(impl_->buildRequest,impl_->configuration,key))continue;
|
||||
if(!diagnosticIncludeBaseCoveredTiles
|
||||
&&CoveredByBaseShape(impl_->buildRequest,impl_->configuration,key))continue;
|
||||
if(impl_->tileRegions.contains(key)||!seenTiles.insert(key).second)continue;
|
||||
// Keep every region's bounds spatially finite. A large camera step can bring in
|
||||
// disjoint tiles across the whole view; coalescing an entire LOD slab makes the
|
||||
// dense axis-bin grid grow with the bounding rectangle of all of them at once.
|
||||
// Garder chaque region spatialement bornee: un grand deplacement peut amener des
|
||||
// tuiles disjointes; fusionner tout un niveau ferait croitre les bins avec son
|
||||
// grand rectangle englobant.
|
||||
const TileKey pageKey=ShapePageKey(key);
|
||||
auto [found,inserted]=regionByPage.try_emplace(pageKey,pendingRegions.size());
|
||||
if(inserted)pendingRegions.push_back({pageKey,{}});
|
||||
pendingRegions[found->second].tiles.push_back(key);
|
||||
// Keep every region's bounds spatially finite. A large camera step can bring in
|
||||
// disjoint tiles across the whole view; coalescing an entire LOD slab makes the
|
||||
// dense axis-bin grid grow with the bounding rectangle of all of them at once.
|
||||
// Garder chaque region spatialement bornee: un grand deplacement peut amener des
|
||||
// tuiles disjointes; fusionner tout un niveau ferait croitre les bins avec son
|
||||
// grand rectangle englobant.
|
||||
const TileKey pageKey=ShapePageKey(key);
|
||||
auto [found,inserted]=regionByPage.try_emplace(pageKey,pendingRegions.size());
|
||||
if(inserted)pendingRegions.push_back({pageKey,{}});
|
||||
pendingRegions[found->second].tiles.push_back(key);
|
||||
}
|
||||
}
|
||||
if(pendingRegions.empty())return true;
|
||||
@@ -1317,7 +1319,8 @@ namespace VoxelForgeCore
|
||||
const FIntVector fineMax(regionMax.X+PagePad,regionMax.Y+PagePad,regionMax.Z+PagePad);
|
||||
auto region=std::make_shared<FStandaloneShapeWorld>();
|
||||
if(!region->BuildAnalyticRegion(*impl_->owner,fineMin,fineMax,regionMin,regionMax,
|
||||
ToNative(base.detail),base.roundTunnels,regionErrors[index]))return;
|
||||
ToNative(base.detail),base.roundTunnels,impl_->worldAssembly.get(),
|
||||
regionErrors[index]))return;
|
||||
compiledRegions[index]=std::move(region);
|
||||
};
|
||||
struct FAnalyticBuildContext
|
||||
@@ -1749,6 +1752,11 @@ namespace VoxelForgeCore
|
||||
FVoxelMarchingCubesStageTimings McStageTimings;
|
||||
TileMesh out;out.key=key;
|
||||
out.diagnostics.featureRefinedResolution=bFeatureRefinedResolution;
|
||||
if(options.profileMesherStages)
|
||||
{
|
||||
out.diagnostics.nativeOnlyRoute=bNativeOnly;
|
||||
out.diagnostics.analyticRegionPageRoute=page&&page->IsAnalyticOnly();
|
||||
}
|
||||
const bool bHasWorldAssembly=impl_->worldAssembly!=nullptr;
|
||||
const bool bNeedsFarShell=bHasWorldAssembly&&key.lod>=7
|
||||
&&(tileShape.HasFarWorld()||(bShapeReady&&impl_->shape->HasFarWorld()));
|
||||
@@ -1812,6 +1820,8 @@ namespace VoxelForgeCore
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds
|
||||
-columnMillisecondsBeforeClassification);
|
||||
bNativeSurfaceTile=Classification.bNativeSurface;
|
||||
if(options.profileMesherStages)
|
||||
out.diagnostics.nativeSurfaceTile=bNativeSurfaceTile;
|
||||
// NativeSurfaceDensityAt consumes only the bounded manifest heightfield and its
|
||||
// bounded type-2/type-4 features. Unknown tile occupancy does not make that Z support
|
||||
// unknown; edits and cross-strate tiles are still excluded below.
|
||||
@@ -1870,7 +1880,7 @@ namespace VoxelForgeCore
|
||||
int32 MeshBandMinZVoxel=options.bandMinZVoxel;
|
||||
int32 MeshBandMaxZVoxel=options.bandMaxZVoxel;
|
||||
bool bNativeHeightfieldBandLimited=false;
|
||||
if(bHasWorldAssembly&&bNativeSurfaceBandSafe
|
||||
if(bHasWorldAssembly&&bNativeSurfaceBandSafe&&!(page&&page->IsAnalyticOnly())
|
||||
&&!options.hashDensity&&!options.captureDensitySamples&&world.Manager!=nullptr)
|
||||
{
|
||||
// La surface 2D et les bornes de volume du manifeste definissent tout le support Z.
|
||||
|
||||
Reference in new issue
Block a user