diag: passage source-floor clamp rejected (L91); field has steep non-distance tails
Clamping the passage-composition source density at -c (c=2..6 voxels, diagnostic, default off) changes the surface far beyond the bar: c=6 still 65 sign flips, up to 165 cm displacement, 120 deg normal change (downstream composition consumes deep values). Source gradient at crossings is distance-like at the median but has huge tails (FI p90 |grad| 512, max 894 vox/vox), so the density-dependent passage reach is inflated by non-distance values. No world change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
a7a03d42b4
commit
8805291d3e
9 files changed
+937
-11
No files matched your search
@@ -1809,6 +1809,10 @@ namespace VoxelForgeCore
|
|||||||
bool profileMesherStages = false;
|
bool profileMesherStages = false;
|
||||||
// Research-only: count passage-composer work per generated tile.
|
// Research-only: count passage-composer work per generated tile.
|
||||||
bool profilePassageComposer = false;
|
bool profilePassageComposer = false;
|
||||||
|
// Research-only field comparison. A nonnegative value clamps the source density
|
||||||
|
// entering passage composition to at least -N voxel units for this tile.
|
||||||
|
// A negative value leaves the process-level diagnostic override in control.
|
||||||
|
double diagnosticPassageSourceFloorVoxels = -1.0;
|
||||||
// Research-only: collect tile-drain kernel counters and floating-island cache metrics.
|
// Research-only: collect tile-drain kernel counters and floating-island cache metrics.
|
||||||
// Inactive on ordinary generation so the hot path only pays the option check.
|
// Inactive on ordinary generation so the hot path only pays the option check.
|
||||||
bool instrumentTileDrain = false;
|
bool instrumentTileDrain = false;
|
||||||
@@ -1907,6 +1911,8 @@ namespace VoxelForgeCore
|
|||||||
std::string densityDispatchPathAt(Vec3d voxelPosition) const;
|
std::string densityDispatchPathAt(Vec3d voxelPosition) const;
|
||||||
// Analytic source distance without the occupancy-preserving near-zero clamp or packed proxy.
|
// Analytic source distance without the occupancy-preserving near-zero clamp or packed proxy.
|
||||||
float unclampedDensityAt(Vec3d voxelPosition) const;
|
float unclampedDensityAt(Vec3d voxelPosition) const;
|
||||||
|
// Research-only source field entering passage composition, with passage carving omitted.
|
||||||
|
float passageSourceDensityAt(Vec3d voxelPosition) const;
|
||||||
DetailFieldSample detailSampleAt(Vec3d voxelPosition) const;
|
DetailFieldSample detailSampleAt(Vec3d voxelPosition) const;
|
||||||
float densityAtLattice(Vec3i voxelPosition) const;
|
float densityAtLattice(Vec3i voxelPosition) const;
|
||||||
bool isSolidAt(Vec3d voxelPosition) const;
|
bool isSolidAt(Vec3d voxelPosition) const;
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ static bool VF_IsL90PassageCandidateCensusEnabled()
|
|||||||
return bEnabled;
|
return bEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double VF_L91PassageSourceFloorVoxels()
|
||||||
|
{
|
||||||
|
static const double Value=[]
|
||||||
|
{
|
||||||
|
const char* Raw=std::getenv("VOXELFORGE_L91_PASSAGE_SOURCE_FLOOR_VOXELS");
|
||||||
|
if(!Raw||!*Raw)return 0.0;
|
||||||
|
char* End=nullptr;
|
||||||
|
const double Parsed=std::strtod(Raw,&End);
|
||||||
|
return End!=Raw&&*End=='\0'&&std::isfinite(Parsed)&&Parsed>0.0
|
||||||
|
?Parsed:0.0;
|
||||||
|
}();
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
// Standalone-only world compiler. It compiles the runtime room/tunnel/passages into
|
// Standalone-only world compiler. It compiles the runtime room/tunnel/passages into
|
||||||
// axis-line intervals, composes rock/cave signs into packed Z-column words, then displaces
|
// axis-line intervals, composes rock/cave signs into packed Z-column words, then displaces
|
||||||
// only the conservative surface band. The copied Unreal generator remains the A/B reference.
|
// only the conservative surface band. The copied Unreal generator remains the A/B reference.
|
||||||
@@ -226,12 +240,18 @@ public:
|
|||||||
FScopedPassageTileQueries(const FStandaloneShapeWorld& shape,
|
FScopedPassageTileQueries(const FStandaloneShapeWorld& shape,
|
||||||
const std::array<std::int64_t,3>& minimumSubvoxels,
|
const std::array<std::int64_t,3>& minimumSubvoxels,
|
||||||
const std::array<std::int64_t,3>& maximumSubvoxels,
|
const std::array<std::int64_t,3>& maximumSubvoxels,
|
||||||
VoxelForgeCore::TileGenerationStats* profileStats=nullptr,int32 profileLod=0)
|
VoxelForgeCore::TileGenerationStats* profileStats=nullptr,int32 profileLod=0,
|
||||||
|
double passageSourceFloorVoxels=-1.0)
|
||||||
:shape_(&shape),minimumSubvoxels_(minimumSubvoxels),
|
:shape_(&shape),minimumSubvoxels_(minimumSubvoxels),
|
||||||
maximumSubvoxels_(maximumSubvoxels),previous_(ActivePassageTileQueries),
|
maximumSubvoxels_(maximumSubvoxels),previous_(ActivePassageTileQueries),
|
||||||
profileStats_(profileStats),profileLod_(profileLod),
|
profileStats_(profileStats),profileLod_(profileLod),
|
||||||
candidateProfiled_(profileStats!=nullptr&&shape.L90PassageCandidateProgramEnabled)
|
candidateProfiled_(profileStats!=nullptr&&shape.L90PassageCandidateProgramEnabled),
|
||||||
|
passageSourceFloorVoxels_(std::isfinite(passageSourceFloorVoxels)
|
||||||
|
&&passageSourceFloorVoxels>=0.0?passageSourceFloorVoxels
|
||||||
|
:VF_L91PassageSourceFloorVoxels())
|
||||||
{
|
{
|
||||||
|
if(passageSourceFloorVoxels_>0.0)
|
||||||
|
clampCounters_=std::make_shared<FPassageSourceClampCounters>();
|
||||||
mayContainResolvedBoundaryBand_=shape.ResolvedBoundaryBandsIntersectSubvoxelRange(
|
mayContainResolvedBoundaryBand_=shape.ResolvedBoundaryBandsIntersectSubvoxelRange(
|
||||||
minimumSubvoxels_[2],maximumSubvoxels_[2]);
|
minimumSubvoxels_[2],maximumSubvoxels_[2]);
|
||||||
const bool disablePassageComposition=VF_IsL88PassageCompositionDisabled();
|
const bool disablePassageComposition=VF_IsL88PassageCompositionDisabled();
|
||||||
@@ -338,11 +358,18 @@ public:
|
|||||||
mayContainResolvedBoundaryBand_(source.mayContainResolvedBoundaryBand_),
|
mayContainResolvedBoundaryBand_(source.mayContainResolvedBoundaryBand_),
|
||||||
mayContainTransitionPassageFade_(source.mayContainTransitionPassageFade_),
|
mayContainTransitionPassageFade_(source.mayContainTransitionPassageFade_),
|
||||||
previous_(ActivePassageTileQueries),profileLod_(source.profileLod_),
|
previous_(ActivePassageTileQueries),profileLod_(source.profileLod_),
|
||||||
candidateProfiled_(source.candidateProfiled_)
|
candidateProfiled_(source.candidateProfiled_),
|
||||||
|
passageSourceFloorVoxels_(source.passageSourceFloorVoxels_),
|
||||||
|
clampCounters_(source.clampCounters_),ownsClampCounters_(false)
|
||||||
{ ActivePassageTileQueries=this; }
|
{ ActivePassageTileQueries=this; }
|
||||||
~FScopedPassageTileQueries()
|
~FScopedPassageTileQueries()
|
||||||
{
|
{
|
||||||
ActivePassageTileQueries=previous_;
|
ActivePassageTileQueries=previous_;
|
||||||
|
if(ownsClampCounters_&&clampCounters_&&passageSourceFloorVoxels_>0.0)
|
||||||
|
std::printf("[L91PassageSourceClampTile] lod=%d floor_vox=%.3f source_clamped=%llu source_delta_sum=%.9g deepest_source_vox=%.9g\n",
|
||||||
|
profileLod_,passageSourceFloorVoxels_,
|
||||||
|
static_cast<unsigned long long>(clampCounters_->samples.load()),
|
||||||
|
clampCounters_->deltaSum.load(),clampCounters_->deepestSource.load());
|
||||||
if(!candidateProfiled_||l90Queries_==0)return;
|
if(!candidateProfiled_||l90Queries_==0)return;
|
||||||
std::array<std::array<char,360>,4> HistText{};
|
std::array<std::array<char,360>,4> HistText{};
|
||||||
constexpr std::array<const char*,4> Names={"carve","tread","clearance","mouth_column"};
|
constexpr std::array<const char*,4> Names={"carve","tread","clearance","mouth_column"};
|
||||||
@@ -451,6 +478,20 @@ public:
|
|||||||
VoxelForgeCore::TileGenerationStats* profileStats() const noexcept
|
VoxelForgeCore::TileGenerationStats* profileStats() const noexcept
|
||||||
{return profileStats_;}
|
{return profileStats_;}
|
||||||
bool candidateCensusProfiled() const noexcept{return candidateProfiled_;}
|
bool candidateCensusProfiled() const noexcept{return candidateProfiled_;}
|
||||||
|
double passageSourceFloorVoxels() const noexcept{return passageSourceFloorVoxels_;}
|
||||||
|
void recordPassageSourceClamp(float sourceDensity) const noexcept
|
||||||
|
{
|
||||||
|
if(passageSourceFloorVoxels_<=0.0)return;
|
||||||
|
const double delta=-passageSourceFloorVoxels_-static_cast<double>(sourceDensity);
|
||||||
|
if(!(delta>0.0)||!std::isfinite(delta))return;
|
||||||
|
if(!clampCounters_)clampCounters_=std::make_shared<FPassageSourceClampCounters>();
|
||||||
|
clampCounters_->samples.fetch_add(1,std::memory_order_relaxed);
|
||||||
|
clampCounters_->deltaSum.fetch_add(delta,std::memory_order_relaxed);
|
||||||
|
double prior=clampCounters_->deepestSource.load(std::memory_order_relaxed);
|
||||||
|
while(static_cast<double>(sourceDensity)<prior
|
||||||
|
&&!clampCounters_->deepestSource.compare_exchange_weak(prior,sourceDensity,
|
||||||
|
std::memory_order_relaxed,std::memory_order_relaxed)){}
|
||||||
|
}
|
||||||
void recordL90CandidateHit(const std::array<std::size_t,4>& counts,bool haveBrick) const
|
void recordL90CandidateHit(const std::array<std::size_t,4>& counts,bool haveBrick) const
|
||||||
{
|
{
|
||||||
if(!candidateProfiled_)return;
|
if(!candidateProfiled_)return;
|
||||||
@@ -491,6 +532,12 @@ public:
|
|||||||
{return cavernFeatureIndices_;}
|
{return cavernFeatureIndices_;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct FPassageSourceClampCounters
|
||||||
|
{
|
||||||
|
std::atomic<std::uint64_t> samples{0};
|
||||||
|
std::atomic<double> deltaSum{0.0};
|
||||||
|
std::atomic<double> deepestSource{0.0};
|
||||||
|
};
|
||||||
const FStandaloneShapeWorld* shape_;
|
const FStandaloneShapeWorld* shape_;
|
||||||
std::array<std::int64_t,3> minimumSubvoxels_,maximumSubvoxels_;
|
std::array<std::int64_t,3> minimumSubvoxels_,maximumSubvoxels_;
|
||||||
std::vector<std::uint32_t> featureIndices_;
|
std::vector<std::uint32_t> featureIndices_;
|
||||||
@@ -508,6 +555,9 @@ public:
|
|||||||
VoxelForgeCore::TileGenerationStats* profileStats_=nullptr;
|
VoxelForgeCore::TileGenerationStats* profileStats_=nullptr;
|
||||||
int32 profileLod_=0;
|
int32 profileLod_=0;
|
||||||
bool candidateProfiled_=false;
|
bool candidateProfiled_=false;
|
||||||
|
double passageSourceFloorVoxels_=0.0;
|
||||||
|
mutable std::shared_ptr<FPassageSourceClampCounters> clampCounters_;
|
||||||
|
bool ownsClampCounters_=true;
|
||||||
mutable std::uint64_t l90Queries_=0,l90NoBrickQueries_=0;
|
mutable std::uint64_t l90Queries_=0,l90NoBrickQueries_=0;
|
||||||
mutable std::uint64_t l90FallbackIterations_=0,l90FallbackNanoseconds_=0,
|
mutable std::uint64_t l90FallbackIterations_=0,l90FallbackNanoseconds_=0,
|
||||||
l90QueryNanoseconds_=0,l90FallbackCarveVisits_=0,l90FallbackTreadVisits_=0,
|
l90QueryNanoseconds_=0,l90FallbackCarveVisits_=0,l90FallbackTreadVisits_=0,
|
||||||
@@ -1269,6 +1319,16 @@ public:
|
|||||||
~FL90CandidateBrickScope()
|
~FL90CandidateBrickScope()
|
||||||
{FStandaloneShapeWorld::ActivePassageCandidateBrick=previous;}
|
{FStandaloneShapeWorld::ActivePassageCandidateBrick=previous;}
|
||||||
} l90CandidateBrickScope(l90CandidateBrick);
|
} l90CandidateBrickScope(l90CandidateBrick);
|
||||||
|
const double passageSourceFloorVoxels=passageTileScopeMatches
|
||||||
|
?passageTileQueries->passageSourceFloorVoxels()
|
||||||
|
:VF_L91PassageSourceFloorVoxels();
|
||||||
|
if(passageSourceFloorVoxels>0.0
|
||||||
|
&&static_cast<double>(density)<-passageSourceFloorVoxels)
|
||||||
|
{
|
||||||
|
if(passageTileScopeMatches)
|
||||||
|
passageTileQueries->recordPassageSourceClamp(density);
|
||||||
|
density=static_cast<float>(-passageSourceFloorVoxels);
|
||||||
|
}
|
||||||
if(passageTileScopeMatches&&density>=0.0f
|
if(passageTileScopeMatches&&density>=0.0f
|
||||||
&&!passageTileQueries->hasRouteFeatureOverlap()
|
&&!passageTileQueries->hasRouteFeatureOverlap()
|
||||||
&&!passageTileQueries->hasColumnZOverlap()
|
&&!passageTileQueries->hasColumnZOverlap()
|
||||||
@@ -4002,6 +4062,9 @@ public:
|
|||||||
return AnalyticDensityAt(X,Y,Z);
|
return AnalyticDensityAt(X,Y,Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float PassageSourceDensityAt(float X,float Y,float Z) const
|
||||||
|
{return NativePassageDensityAt(X,Y,Z);}
|
||||||
|
|
||||||
std::vector<std::uint32_t> OreVeinTileCandidates(
|
std::vector<std::uint32_t> OreVeinTileCandidates(
|
||||||
const std::array<std::int64_t,3>& minimum,
|
const std::array<std::int64_t,3>& minimum,
|
||||||
const std::array<std::int64_t,3>& maximum) const
|
const std::array<std::int64_t,3>& maximum) const
|
||||||
@@ -5900,12 +5963,24 @@ private:
|
|||||||
L90PassageCandidateBricks.clear();
|
L90PassageCandidateBricks.clear();
|
||||||
L90PassageCandidateProgramValid=false;
|
L90PassageCandidateProgramValid=false;
|
||||||
L90PassageCandidateBuildFailures=0;
|
L90PassageCandidateBuildFailures=0;
|
||||||
L90PassageCandidateReachMetres=10.0;
|
const auto ReadPositiveEnv=[](const char* Name,double Default)
|
||||||
|
{
|
||||||
|
const char* Raw=std::getenv(Name);
|
||||||
|
if(!Raw||!*Raw)return Default;
|
||||||
|
char* End=nullptr;
|
||||||
|
const double Parsed=std::strtod(Raw,&End);
|
||||||
|
return End!=Raw&&*End=='\0'&&std::isfinite(Parsed)&&Parsed>0.0
|
||||||
|
?Parsed:Default;
|
||||||
|
};
|
||||||
|
L90PassageCandidateReachMetres=ReadPositiveEnv(
|
||||||
|
"VOXELFORGE_L90_PASSAGE_REACH_METRES",10.0);
|
||||||
|
const double brickMetres=ReadPositiveEnv(
|
||||||
|
"VOXELFORGE_L90_PASSAGE_BRICK_METRES",4.0);
|
||||||
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
const double qPerMetre=Q*1000000.0/std::max<std::uint32_t>(1,
|
const double qPerMetre=Q*1000000.0/std::max<std::uint32_t>(1,
|
||||||
ResolvedLayout->coreVoxelSizeMicrometres);
|
ResolvedLayout->coreVoxelSizeMicrometres);
|
||||||
const double voxelsPerMetre=qPerMetre/Q;
|
const double voxelsPerMetre=qPerMetre/Q;
|
||||||
L90PassageCandidateBrickEdgeSubvoxels=4.0*qPerMetre;
|
L90PassageCandidateBrickEdgeSubvoxels=brickMetres*qPerMetre;
|
||||||
const double reachSubvoxels=L90PassageCandidateReachMetres*qPerMetre;
|
const double reachSubvoxels=L90PassageCandidateReachMetres*qPerMetre;
|
||||||
const double cubicPadding=1.0;
|
const double cubicPadding=1.0;
|
||||||
std::array<std::uint64_t,4> emittedReferences{};
|
std::array<std::uint64_t,4> emittedReferences{};
|
||||||
@@ -6241,8 +6316,9 @@ private:
|
|||||||
L90PassageCandidateProgramValid=L90PassageCandidateBuildFailures==0;
|
L90PassageCandidateProgramValid=L90PassageCandidateBuildFailures==0;
|
||||||
const double buildMilliseconds=std::chrono::duration<double,std::milli>(
|
const double buildMilliseconds=std::chrono::duration<double,std::milli>(
|
||||||
FClock::now()-buildStart).count();
|
FClock::now()-buildStart).count();
|
||||||
std::printf("[L90PassageCandidateBuild] brick_m=4 reach_m=%.1f bricks=%zu emitted=(%llu,%llu,%llu,%llu) unique=(%llu,%llu,%llu,%llu) bytes_estimate=%zu build_ms=%.3f failures=%llu valid=%d\n",
|
std::printf("[L90PassageCandidateBuild] brick_m=%.3f reach_m=%.3f source_floor_vox=%.3f bricks=%zu emitted=(%llu,%llu,%llu,%llu) unique=(%llu,%llu,%llu,%llu) bytes_estimate=%zu build_ms=%.3f failures=%llu valid=%d\n",
|
||||||
L90PassageCandidateReachMetres,L90PassageCandidateBricks.size(),
|
brickMetres,L90PassageCandidateReachMetres,VF_L91PassageSourceFloorVoxels(),
|
||||||
|
L90PassageCandidateBricks.size(),
|
||||||
static_cast<unsigned long long>(emittedReferences[0]),
|
static_cast<unsigned long long>(emittedReferences[0]),
|
||||||
static_cast<unsigned long long>(emittedReferences[1]),
|
static_cast<unsigned long long>(emittedReferences[1]),
|
||||||
static_cast<unsigned long long>(emittedReferences[2]),
|
static_cast<unsigned long long>(emittedReferences[2]),
|
||||||
|
|||||||
@@ -1909,6 +1909,8 @@ namespace VoxelForgeCore
|
|||||||
:"uncompiled"; }
|
:"uncompiled"; }
|
||||||
float World::unclampedDensityAt(Vec3d position) const
|
float World::unclampedDensityAt(Vec3d position) const
|
||||||
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->DensityAtUnclamped(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
|
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->DensityAtUnclamped(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
|
||||||
|
float World::passageSourceDensityAt(Vec3d position) const
|
||||||
|
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->PassageSourceDensityAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
|
||||||
DetailFieldSample World::detailSampleAt(Vec3d position) const
|
DetailFieldSample World::detailSampleAt(Vec3d position) const
|
||||||
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->DetailSampleAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):DetailFieldSample{}; }
|
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->DetailSampleAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):DetailFieldSample{}; }
|
||||||
float World::densityAtLattice(Vec3i position) const
|
float World::densityAtLattice(Vec3i position) const
|
||||||
@@ -2794,7 +2796,8 @@ namespace VoxelForgeCore
|
|||||||
// queryMinimum/queryMaximum ci-dessus couvrent exactement ce domaine inclusif.
|
// queryMinimum/queryMaximum ci-dessus couvrent exactement ce domaine inclusif.
|
||||||
const FStandaloneShapeWorld::FScopedPassageTileQueries passageFeatureScope(
|
const FStandaloneShapeWorld::FScopedPassageTileQueries passageFeatureScope(
|
||||||
tileShape,queryMinimum,queryMaximum,
|
tileShape,queryMinimum,queryMaximum,
|
||||||
options.profilePassageComposer?&out.diagnostics:nullptr,key.lod);
|
options.profilePassageComposer?&out.diagnostics:nullptr,key.lod,
|
||||||
|
options.diagnosticPassageSourceFloorVoxels);
|
||||||
if(options.profilePassageComposer)
|
if(options.profilePassageComposer)
|
||||||
{
|
{
|
||||||
out.diagnostics.passageComposerProfiled=true;
|
out.diagnostics.passageComposerProfiled=true;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Linux 91 — passage source floor
|
||||||
|
|
||||||
|
## Acceptance bar declared before measurement
|
||||||
|
|
||||||
|
For every owner stratum and LOD0–2: zero density sign flips, maximum edge-interpolated surface displacement ≤1 cm, maximum paired mesh-vertex normal-angle change ≤2°, and all passage audits passing. Capture and inspect moved surfaces. Measure source-field gradients at surface crossings. Apply any candidate floor only to the source passed into passage composition, preserving other field features.
|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
**No tested floor is acceptable; stop before the census and prototype.** The comparison clamped only the passage-composition source. Each floor changed samples and meshes, so this is not a no-op. Each stratum covered its full desired near set at LOD0–2: S0 1,408 tiles (512/448/448); FI 1,216 (512/448/256); TN 1,344 (512/448/384); S3 1,344 (512/448/384). There were 174,736,448 total density samples per floor across the four strata.
|
||||||
|
|
||||||
|
The 0.25 m core voxel makes the proposed reach `c·Q + 0.24 m`: c=2/3/4/6 gives 0.74/0.99/1.24/1.74 m. No smallest acceptable c exists.
|
||||||
|
|
||||||
|
| c (vox) | Stratum | Changed samples | Sign flips | Max / mean displacement (cm) | Max normal change (°) | Changed mesh tiles |
|
||||||
|
|---:|:---|---:|---:|---:|---:|---:|
|
||||||
|
| 2 | S0 | 22.17M | 212 | 89.72 / 1.62 | 36.65 | 237 |
|
||||||
|
| 2 | FI | 25.76M | 124 | 91.67 / 1.06 | 84.80 | 155 |
|
||||||
|
| 2 | TN | 16.46M | 124 | 95.01 / 1.54 | 79.33 | 164 |
|
||||||
|
| 2 | S3 | 4.03M | 0 | 185.92 / 9.47 | 116.43 | 198 |
|
||||||
|
| 3 | S0 | 21.98M | 121 | 71.62 / 0.81 | 34.46 | 210 |
|
||||||
|
| 3 | FI | 25.66M | 54 | 72.08 / 0.47 | 80.24 | 147 |
|
||||||
|
| 3 | TN | 16.36M | 54 | 76.92 / 0.67 | 80.24 | 151 |
|
||||||
|
| 3 | S3 | 4.01M | 0 | 180.36 / 6.60 | 118.75 | 189 |
|
||||||
|
| 4 | S0 | 21.79M | 91 | 58.19 / 0.38 | 35.29 | 141 |
|
||||||
|
| 4 | FI | 25.55M | 6 | 59.35 / 0.16 | 82.15 | 107 |
|
||||||
|
| 4 | TN | 16.27M | 6 | 62.94 / 0.24 | 82.15 | 134 |
|
||||||
|
| 4 | S3 | 3.99M | 0 | 175.11 / 4.60 | 120.47 | 189 |
|
||||||
|
| 6 | S0 | 21.40M | 65 | 38.24 / 0.08 | 35.24 | 121 |
|
||||||
|
| 6 | FI | 1.67M | 0 | 43.78 / 0.04 | 81.05 | 101 |
|
||||||
|
| 6 | TN | 2.52M | 0 | 43.78 / 0.05 | 81.05 | 128 |
|
||||||
|
| 6 | S3 | 2.23M | 0 | 165.43 / 1.88 | 120.10 | 180 |
|
||||||
|
|
||||||
|
The route-near moved-crossing classifier tagged wall/floor/mouth changes at every floor. Totals across strata (wall, floor, mouth, other) were: c2 (4,806, 2,527, 7,587, 96,946); c3 (3,547, 2,046, 7,343, 81,736); c4 (2,215, 1,371, 7,252, 70,981); c6 (665, 272, 2,461, 33,139). These region labels use nearest-route-chord heuristics. Normal maxima compare index-paired vertices; normal changes in tiles with incompatible vertex/index pairing were unmeasured (183/151/141/112 tiles for c2/c3/c4/c6).
|
||||||
|
|
||||||
|
The source gradient is near distance-like at the median, but has steep outliers. Central differences use a 1-voxel step at source `|d|≤2` crossings outside the approximate passage region:
|
||||||
|
|
||||||
|
| Stratum | Samples | p50 / p90 / max `|∇d|` (vox/vox) |
|
||||||
|
|:---|---:|---:|
|
||||||
|
| S0 | 7,137 | 1.205 / 1.815 / 4.741 |
|
||||||
|
| FI | 1,929 | 1.001 / 511.674 / 893.726 |
|
||||||
|
| TN | 2,142 | 0.993 / 1.047 / 893.726 |
|
||||||
|
| S3 | 3,079 | 0.932 / 1.036 / 444.254 |
|
||||||
|
|
||||||
|
Thus the distance-field hypothesis holds around the median, not across the measured tails. Even c6 still has 65 sign flips overall, up to 165.43 cm displacement, and up to 120.47° paired normal change. S3 has zero flips at every floor but substantial crossing motion, showing that sign preservation alone does not bound the surface change.
|
||||||
|
|
||||||
|
Matched baseline/c6 captures were generated for all four strata at the audit cameras: [S0](../../../../Saved/Linux/l91/captures/s0-c0.png), [FI](../../../../Saved/Linux/l91/captures/fi-c0.png), [TN](../../../../Saved/Linux/l91/captures/tn-c0.png), [S3](../../../../Saved/Linux/l91/captures/s3-c0.png), with corresponding `*-c6.png` files beside them. The views are qualitative and do not resolve the measured local shifts.
|
||||||
|
|
||||||
|
## Census, prototype, readiness
|
||||||
|
|
||||||
|
The L90 census was not rerun at 2 m or 4 m bricks because no acceptable c was found. The compiled evaluator prototype on `passage/1-2/0` and W8/W12 LOD0–2 timing were not run. Passage walkability audits were not run after the effect gate failed. No production clamp was adopted; its diagnostic floor defaults off and is confined to passage composition. Therefore no version bump, hash repin, or fast-tier/same-world adoption run was made. Same-world peers and cross-compiler equality remain unmeasured for the rejected candidate. Existing production hashes/default behavior were not intentionally changed.
|
||||||
|
|
||||||
|
## Runs and evidence
|
||||||
|
|
||||||
|
- Clang 19 standalone build passed; source stamp: `93fac418c7497299b43bd183625ba2117ec8096b2daeb6ea2f74f0171b348597`.
|
||||||
|
- All four clamp audits covered the expected complete near tile sets, with zero generation failures and invalid comparisons. Their exit code 14 marks the threshold failure, not a crash.
|
||||||
|
- All 16 baseline/c6 export and capture steps passed. No process exceeded 30 minutes. All headless runs used `taskset -c 0-11` and `prlimit --as=6442450944`.
|
||||||
|
- The first standalone build launch failed before compiling because its log directory did not exist; after creating it, the Clang build passed. No Unreal build was run because the clamp failed the effect gate before production integration.
|
||||||
|
- Detailed counts/logs: `Saved/Linux/l91/clamp-effects/`; captures/logs: `Saved/Linux/l91/captures/`; census runner remains unexecuted at `RunL91CandidateCensus.py`.
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Rerun the L90 candidate census at a measured source floor and two brick sizes."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
OUT = ROOT / "Saved/Linux/l91/candidate-census"
|
||||||
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||||
|
BINARY = ROOT / "Saved/Linux/l91/bin/VoxelForgeCoreHeadless-l91-clang19"
|
||||||
|
STRATA = {
|
||||||
|
"S0": {"camera": (8.0, 16.0, -372.2626953125), "near": 1408},
|
||||||
|
"FI": {"camera": (25.8369140625, 3.19921875, -737.0), "near": 1216},
|
||||||
|
"TN": {"camera": (19.166015625, -14.2001953125, -753.3740234375), "near": 1344},
|
||||||
|
"S3": {"camera": (-20.0625, -5.068359375, -900.353515625), "near": 1344},
|
||||||
|
}
|
||||||
|
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||||
|
BUILD = re.compile(r"^\[L90PassageCandidateBuild\] (.*)$", re.M)
|
||||||
|
CENSUS = re.compile(r"^\[L90PassageCandidateTile\] (.*)$", re.M)
|
||||||
|
NEAR = re.compile(r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$", re.M)
|
||||||
|
STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M)
|
||||||
|
HISTS = ("carve_hist", "tread_hist", "clearance_hist", "mouth_column_hist")
|
||||||
|
SEMANTICS = tuple(name.removesuffix("_hist") for name in HISTS)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_fields(line: str) -> dict[str, str]:
|
||||||
|
return dict(FIELDS.findall(line))
|
||||||
|
|
||||||
|
|
||||||
|
def histogram(value: str) -> list[int]:
|
||||||
|
items = [int(item) for item in value.split(",")]
|
||||||
|
if len(items) != 17:
|
||||||
|
raise ValueError(f"expected 17 histogram bins, got {len(items)}")
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def percentile(values: list[int], p: float, active: bool = False) -> int:
|
||||||
|
start = 1 if active else 0
|
||||||
|
population = sum(values[start:])
|
||||||
|
target = max(1, int(p * population + 0.999999999))
|
||||||
|
seen = 0
|
||||||
|
for size in range(start, len(values)):
|
||||||
|
seen += values[size]
|
||||||
|
if seen >= target:
|
||||||
|
return size
|
||||||
|
return 16
|
||||||
|
|
||||||
|
|
||||||
|
def run(stratum: str, floor: float, brick: float) -> dict:
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
spec = STRATA[stratum]
|
||||||
|
reach = floor * 0.25 + 0.24
|
||||||
|
camera = ",".join(f"{value:.12f}" for value in spec["camera"]) + ",0,0"
|
||||||
|
log = OUT / f"{stratum.lower()}-c{floor:g}-b{brick:g}m-w8.log"
|
||||||
|
command = [
|
||||||
|
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "env",
|
||||||
|
"VOXELFORGE_L90_PASSAGE_CANDIDATE_CENSUS=1",
|
||||||
|
"VOXELFORGE_L81_PASSAGE_BOUND_PADDING_VOXELS=0",
|
||||||
|
f"VOXELFORGE_L91_PASSAGE_SOURCE_FLOOR_VOXELS={floor:g}",
|
||||||
|
f"VOXELFORGE_L90_PASSAGE_REACH_METRES={reach:.6f}",
|
||||||
|
f"VOXELFORGE_L90_PASSAGE_BRICK_METRES={brick:g}",
|
||||||
|
"timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype",
|
||||||
|
"--stream-benchmark", "--stream-pipeline", "--workers=8", "--clip-radius=3",
|
||||||
|
"--max-clip-level=8", "--max-level=8", f"--camera={camera}",
|
||||||
|
"--profile-lod-work", "--profile-passage-composer",
|
||||||
|
]
|
||||||
|
started = time.monotonic()
|
||||||
|
try:
|
||||||
|
with log.open("w", encoding="utf-8") as stream:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1750)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
result = None
|
||||||
|
content = log.read_text(encoding="utf-8", errors="replace")
|
||||||
|
builds = [parse_fields(match.group(1)) for match in BUILD.finditer(content)]
|
||||||
|
near = NEAR.search(content)
|
||||||
|
rows = []
|
||||||
|
for match in CENSUS.finditer(content):
|
||||||
|
fields = parse_fields(match.group(1))
|
||||||
|
if int(fields["lod"]) > 2:
|
||||||
|
continue
|
||||||
|
rows.append(fields)
|
||||||
|
histograms = {name.removesuffix("_hist"): [0] * 17 for name in HISTS}
|
||||||
|
fallback_ns = query_ns = 0
|
||||||
|
for row in rows:
|
||||||
|
fallback_ns += int(row["fallback_ns"])
|
||||||
|
query_ns += int(row["query_ns"])
|
||||||
|
for name in HISTS:
|
||||||
|
values = histogram(row[name])
|
||||||
|
key = name.removesuffix("_hist")
|
||||||
|
histograms[key] = [a + b for a, b in zip(histograms[key], values)]
|
||||||
|
metrics = {}
|
||||||
|
for name, values in histograms.items():
|
||||||
|
metrics[name] = {
|
||||||
|
"queries": sum(values),
|
||||||
|
"active_p90": percentile(values, 0.90, active=True),
|
||||||
|
"active_p95": percentile(values, 0.95, active=True),
|
||||||
|
"all_p90": percentile(values, 0.90),
|
||||||
|
"histogram_0_to_15_plus": values,
|
||||||
|
}
|
||||||
|
row = {
|
||||||
|
"stratum": stratum, "floor_vox": floor, "reach_m": round(reach, 6),
|
||||||
|
"brick_m": brick, "workers": 8,
|
||||||
|
"exit_code": result.returncode if result is not None else "timeout",
|
||||||
|
"wall_s": round(time.monotonic() - started, 3),
|
||||||
|
"near_tiles": spec["near"],
|
||||||
|
"near_complete": bool(near and int(near.group(1)) == spec["near"]
|
||||||
|
and int(near.group(2)) == spec["near"]),
|
||||||
|
"lod02_ready_s": float(near.group(3)) if near else None,
|
||||||
|
"census_rows": len(rows), "census_queries": sum(v["queries"] for v in metrics.values()) // 4,
|
||||||
|
"fallback_ns": fallback_ns, "query_ns": query_ns,
|
||||||
|
"fallback_share": fallback_ns / query_ns if query_ns else None,
|
||||||
|
"histograms": metrics, "build": builds[-1] if builds else None,
|
||||||
|
"source_stamp": STAMP.search(content).group(1) if STAMP.search(content) else None,
|
||||||
|
"log": str(log.relative_to(ROOT)),
|
||||||
|
}
|
||||||
|
print("[L91CandidateCensusRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def aggregate(rows: list[dict]) -> dict:
|
||||||
|
output = {}
|
||||||
|
for brick in sorted({row["brick_m"] for row in rows}):
|
||||||
|
selected = [row for row in rows if row["brick_m"] == brick]
|
||||||
|
combined = {name: [0] * 17 for name in SEMANTICS}
|
||||||
|
fallback_ns = query_ns = 0
|
||||||
|
for row in selected:
|
||||||
|
fallback_ns += row["fallback_ns"]
|
||||||
|
query_ns += row["query_ns"]
|
||||||
|
for name in SEMANTICS:
|
||||||
|
values = row["histograms"][name]["histogram_0_to_15_plus"]
|
||||||
|
combined[name] = [a + b for a, b in zip(combined[name], values)]
|
||||||
|
distributions = {name: {
|
||||||
|
"queries": sum(values),
|
||||||
|
"all_p90": percentile(values, 0.90),
|
||||||
|
"active_p90": percentile(values, 0.90, active=True),
|
||||||
|
"active_p95": percentile(values, 0.95, active=True),
|
||||||
|
"histogram_0_to_15_plus": values,
|
||||||
|
} for name, values in combined.items()}
|
||||||
|
weighted_fallback = fallback_ns / query_ns if query_ns else 1.0
|
||||||
|
stratum_fallback = {row["stratum"]: row["fallback_share"] for row in selected}
|
||||||
|
p90_ok = distributions["carve"]["active_p90"] <= 6 \
|
||||||
|
and distributions["mouth_column"]["active_p90"] <= 6
|
||||||
|
fallback_ok = weighted_fallback < 0.10 and all(
|
||||||
|
value is not None and value < 0.10 for value in stratum_fallback.values())
|
||||||
|
output[str(brick)] = {
|
||||||
|
"strata": [row["stratum"] for row in selected],
|
||||||
|
"weighted_fallback_share": weighted_fallback,
|
||||||
|
"stratum_fallback_share": stratum_fallback,
|
||||||
|
"weighted_semantics": distributions,
|
||||||
|
"p90_pass": p90_ok, "fallback_pass": fallback_ok,
|
||||||
|
"census_pass": p90_ok and fallback_ok and len(selected) == 4
|
||||||
|
and all(row["near_complete"] and row["exit_code"] == 0 for row in selected),
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--floor", type=float, required=True)
|
||||||
|
parser.add_argument("--bricks", type=float, nargs="+", default=[2.0, 4.0])
|
||||||
|
parser.add_argument("--strata", nargs="+", choices=tuple(STRATA), default=tuple(STRATA))
|
||||||
|
args = parser.parse_args()
|
||||||
|
if not BINARY.is_file() or not DATA.is_file():
|
||||||
|
raise SystemExit(f"missing input: {BINARY} or {DATA}")
|
||||||
|
rows = [run(stratum, args.floor, brick)
|
||||||
|
for brick in args.bricks for stratum in args.strata]
|
||||||
|
payload = {"floor_vox": args.floor, "reach_m": args.floor * 0.25 + 0.24,
|
||||||
|
"runs": rows, "aggregates_by_brick_m": aggregate(rows)}
|
||||||
|
(OUT / "summary.json").write_text(json.dumps(payload, indent=2) + "\n",
|
||||||
|
encoding="utf-8")
|
||||||
|
return 0 if all(value["census_pass"]
|
||||||
|
for value in payload["aggregates_by_brick_m"].values()) else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Measure source-floor effects across one owner stratum's complete near view."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
OUT = ROOT / "Saved/Linux/l91/clamp-effects"
|
||||||
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||||
|
BINARY = ROOT / "Saved/Linux/l91/bin/VoxelForgeCoreHeadless-l91-clang19"
|
||||||
|
STRATA = {
|
||||||
|
"S0": {"camera": (8.0, 16.0, -372.2626953125), "near": 1408},
|
||||||
|
"FI": {"camera": (25.8369140625, 3.19921875, -737.0), "near": 1216},
|
||||||
|
"TN": {"camera": (19.166015625, -14.2001953125, -753.3740234375), "near": 1344},
|
||||||
|
"S3": {"camera": (-20.0625, -5.068359375, -900.353515625), "near": 1344},
|
||||||
|
}
|
||||||
|
STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M)
|
||||||
|
COVERAGE = re.compile(r"^\[L91PassageClampCoverage\] (.*)$", re.M)
|
||||||
|
SUMMARY = re.compile(r"^\[L91PassageClampSummary\] (.*)$", re.M)
|
||||||
|
GRADIENT = re.compile(r"^\[L91PassageSourceGradient\] (.*)$", re.M)
|
||||||
|
AUDIT = re.compile(r"^\[L91PassageClampAudit\] (.*)$", re.M)
|
||||||
|
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||||
|
|
||||||
|
|
||||||
|
def run(stratum: str) -> dict:
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
spec = STRATA[stratum]
|
||||||
|
camera = ",".join(f"{value:.12f}" for value in spec["camera"]) + ",0,0"
|
||||||
|
log = OUT / f"{stratum.lower()}-effects.log"
|
||||||
|
command = [
|
||||||
|
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "env",
|
||||||
|
"VOXELFORGE_L81_PASSAGE_BOUND_PADDING_VOXELS=0", "timeout", "1740s",
|
||||||
|
str(BINARY), str(DATA), "--world-assembler-prototype", "--stream-benchmark",
|
||||||
|
"--stream-pipeline", "--workers=8", "--clip-radius=3", "--max-clip-level=8",
|
||||||
|
"--max-level=2", f"--camera={camera}", "--audit-passage-source-clamp",
|
||||||
|
]
|
||||||
|
started = time.monotonic()
|
||||||
|
with log.open("w", encoding="utf-8") as stream:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1750)
|
||||||
|
content = log.read_text(encoding="utf-8", errors="replace")
|
||||||
|
coverage = COVERAGE.search(content)
|
||||||
|
summaries = [dict(FIELDS.findall(match.group(1))) for match in SUMMARY.finditer(content)]
|
||||||
|
gradient = GRADIENT.search(content)
|
||||||
|
audit = AUDIT.search(content)
|
||||||
|
row = {
|
||||||
|
"stratum": stratum,
|
||||||
|
"exit_code": result.returncode,
|
||||||
|
"wall_s": round(time.monotonic() - started, 3),
|
||||||
|
"expected_near_tiles": spec["near"],
|
||||||
|
"coverage": dict(FIELDS.findall(coverage.group(1))) if coverage else None,
|
||||||
|
"floors": summaries,
|
||||||
|
"source_gradient": dict(FIELDS.findall(gradient.group(1))) if gradient else None,
|
||||||
|
"audit": dict(FIELDS.findall(audit.group(1))) if audit else None,
|
||||||
|
"source_stamp": STAMP.search(content).group(1) if STAMP.search(content) else None,
|
||||||
|
"log": str(log.relative_to(ROOT)),
|
||||||
|
}
|
||||||
|
(OUT / f"{stratum.lower()}-effects.json").write_text(
|
||||||
|
json.dumps(row, indent=2) + "\n", encoding="utf-8")
|
||||||
|
print("[L91ClampEffectsRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--stratum", choices=tuple(STRATA), required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if not BINARY.is_file() or not DATA.is_file():
|
||||||
|
raise SystemExit(f"missing input: {BINARY} or {DATA}")
|
||||||
|
run(args.stratum)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Capture matched baseline and c=6 near-LOD views for each owner stratum."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
OUT = ROOT / "Saved/Linux/l91/captures"
|
||||||
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||||
|
BINARY = ROOT / "Saved/Linux/l91/bin/VoxelForgeCoreHeadless-l91-clang19"
|
||||||
|
CAPTURE = ROOT / "Saved/Linux/l91/bin/VoxelForgeOffscreenCapture-l91-clang19"
|
||||||
|
STRATA = {
|
||||||
|
"S0": (8.0, 16.0, -372.2626953125),
|
||||||
|
"FI": (25.8369140625, 3.19921875, -737.0),
|
||||||
|
"TN": (19.166015625, -14.2001953125, -753.3740234375),
|
||||||
|
"S3": (-20.0625, -5.068359375, -900.353515625),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def export(stratum: str, floor: float) -> dict:
|
||||||
|
name = f"{stratum.lower()}-c{floor:g}"
|
||||||
|
scene = OUT / f"{name}.vfmesh"
|
||||||
|
log = OUT / f"{name}-export.log"
|
||||||
|
camera = ",".join(f"{value:.12f}" for value in STRATA[stratum]) + ",0,0"
|
||||||
|
command = [
|
||||||
|
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "env",
|
||||||
|
"VOXELFORGE_L81_PASSAGE_BOUND_PADDING_VOXELS=0",
|
||||||
|
f"VOXELFORGE_L91_PASSAGE_SOURCE_FLOOR_VOXELS={floor:g}",
|
||||||
|
"timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype",
|
||||||
|
"--stream-benchmark", "--stream-pipeline", "--workers=8", "--clip-radius=3",
|
||||||
|
"--max-clip-level=8", "--max-level=2", f"--camera={camera}",
|
||||||
|
"--capture-skip-walkability", "--mesh-coverage", f"--mesh-export={scene}",
|
||||||
|
]
|
||||||
|
started = time.monotonic()
|
||||||
|
with log.open("w", encoding="utf-8") as stream:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1750)
|
||||||
|
return {"name": name, "stratum": stratum, "floor_vox": floor,
|
||||||
|
"exit_code": result.returncode, "wall_s": round(time.monotonic() - started, 3),
|
||||||
|
"scene": str(scene.relative_to(ROOT)), "log": str(log.relative_to(ROOT)),
|
||||||
|
"scene_bytes": scene.stat().st_size if scene.exists() else 0}
|
||||||
|
|
||||||
|
|
||||||
|
def render(stratum: str, floor: float) -> dict:
|
||||||
|
name = f"{stratum.lower()}-c{floor:g}"
|
||||||
|
scene = OUT / f"{name}.vfmesh"
|
||||||
|
image = OUT / f"{name}.png"
|
||||||
|
log = OUT / f"{name}-capture.log"
|
||||||
|
x, y, z = STRATA[stratum]
|
||||||
|
command = [
|
||||||
|
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "timeout",
|
||||||
|
"1740s", str(CAPTURE), str(scene), str(image), "--size=1600x900",
|
||||||
|
"--fov-deg=90", f"--camera-m={x:.12g},{y:.12g},{z:.12g}",
|
||||||
|
"--yaw-deg=0", "--pitch-deg=0", "--shade=readable", "--height-tint=on",
|
||||||
|
]
|
||||||
|
started = time.monotonic()
|
||||||
|
with log.open("w", encoding="utf-8") as stream:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1750)
|
||||||
|
return {"name": name, "stratum": stratum, "floor_vox": floor,
|
||||||
|
"exit_code": result.returncode, "wall_s": round(time.monotonic() - started, 3),
|
||||||
|
"image": str(image.relative_to(ROOT)), "log": str(log.relative_to(ROOT)),
|
||||||
|
"image_bytes": image.stat().st_size if image.exists() else 0}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
rows = []
|
||||||
|
for stratum in STRATA:
|
||||||
|
for floor in (0.0, 6.0):
|
||||||
|
row = export(stratum, floor)
|
||||||
|
rows.append(row)
|
||||||
|
if row["exit_code"] != 0 or row["scene_bytes"] == 0:
|
||||||
|
break
|
||||||
|
row = render(stratum, floor)
|
||||||
|
rows.append(row)
|
||||||
|
if row["exit_code"] != 0 or row["image_bytes"] == 0:
|
||||||
|
break
|
||||||
|
if rows[-1]["exit_code"] != 0:
|
||||||
|
break
|
||||||
|
(OUT / "summary.json").write_text(json.dumps(rows, indent=2) + "\n",
|
||||||
|
encoding="utf-8")
|
||||||
|
print("[L91CaptureSummary] " + json.dumps(rows, sort_keys=True), flush=True)
|
||||||
|
return 0 if len(rows) == 16 and all(row["exit_code"] == 0 for row in rows) else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -59,6 +59,7 @@ namespace
|
|||||||
int ShapeHelperLimit=8;
|
int ShapeHelperLimit=8;
|
||||||
bool AuditBasePageEquivalence=false;
|
bool AuditBasePageEquivalence=false;
|
||||||
bool AuditRouteParity=false;
|
bool AuditRouteParity=false;
|
||||||
|
bool AuditPassageSourceClamp=false;
|
||||||
bool RegionCrossing=false;
|
bool RegionCrossing=false;
|
||||||
bool AuditTileShapeReadiness=false;
|
bool AuditTileShapeReadiness=false;
|
||||||
int DiagnosticSlowShapeCompileMs=0;
|
int DiagnosticSlowShapeCompileMs=0;
|
||||||
@@ -1460,6 +1461,7 @@ namespace
|
|||||||
" --shape-helper-limit=8|12 (default 8; shape build A/B)\n"
|
" --shape-helper-limit=8|12 (default 8; shape build A/B)\n"
|
||||||
" --audit-base-page-equivalence (hash one tile through both shape routes)\n"
|
" --audit-base-page-equivalence (hash one tile through both shape routes)\n"
|
||||||
" --audit-route-parity (compare page, native-only, exact-query and mesh routes)\n"
|
" --audit-route-parity (compare page, native-only, exact-query and mesh routes)\n"
|
||||||
|
" --audit-passage-source-clamp (compare passage source floors 2,3,4,6 over all near tiles)\n"
|
||||||
" --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n"
|
" --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n"
|
||||||
" --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n"
|
" --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n"
|
||||||
" --render-distance-chunks=N (0 disables the extra far ring)\n"
|
" --render-distance-chunks=N (0 disables the extra far ring)\n"
|
||||||
@@ -1536,6 +1538,7 @@ namespace
|
|||||||
}
|
}
|
||||||
else if(arg=="--audit-base-page-equivalence")options.AuditBasePageEquivalence=true;
|
else if(arg=="--audit-base-page-equivalence")options.AuditBasePageEquivalence=true;
|
||||||
else if(arg=="--audit-route-parity")options.AuditRouteParity=true;
|
else if(arg=="--audit-route-parity")options.AuditRouteParity=true;
|
||||||
|
else if(arg=="--audit-passage-source-clamp")options.AuditPassageSourceClamp=true;
|
||||||
else if(arg=="--region-crossing")options.RegionCrossing=true;
|
else if(arg=="--region-crossing")options.RegionCrossing=true;
|
||||||
else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true;
|
else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true;
|
||||||
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
|
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
|
||||||
@@ -2276,5 +2279,6 @@ int main(int argc,char** argv)
|
|||||||
options.StreamHashAllowUniformSkips,options.Linux77Profile,
|
options.StreamHashAllowUniformSkips,options.Linux77Profile,
|
||||||
options.StreamingSchedulerPolicy,options.MovingCameraTrace,
|
options.StreamingSchedulerPolicy,options.MovingCameraTrace,
|
||||||
options.MovingCameraSpeedMetersPerSecond,options.MovingCameraDurationSeconds,
|
options.MovingCameraSpeedMetersPerSecond,options.MovingCameraDurationSeconds,
|
||||||
options.MovingCameraDwellSeconds,options.ColdWorkerTimeline);
|
options.MovingCameraDwellSeconds,options.ColdWorkerTimeline,
|
||||||
|
options.AuditPassageSourceClamp);
|
||||||
}
|
}
|
||||||
@@ -132,6 +132,426 @@ namespace StandaloneStreamBenchmark
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FPassageClampComparison
|
||||||
|
{
|
||||||
|
std::uint64_t samples=0,changedSamples=0,signFlips=0;
|
||||||
|
std::uint64_t crossingEdgeMismatches=0,sharedCrossingEdges=0,movedCrossingEdges=0;
|
||||||
|
std::uint64_t normalVertices=0,normalPairingFailures=0,changedNormalVertices=0;
|
||||||
|
double maxAbsDensityDelta=0.0,maxSurfaceDisplacementCm=0.0;
|
||||||
|
double sumSurfaceDisplacementCm=0.0,maxNormalAngleDegrees=0.0;
|
||||||
|
double sumNormalAngleDegrees=0.0;
|
||||||
|
std::array<std::uint64_t,4> movedEdgeRegions{},normalVertexRegions{};
|
||||||
|
bool meshChanged=false,valid=false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FPassageRegion
|
||||||
|
{
|
||||||
|
int category=3; // 0 wall, 1 floor, 2 mouth, 3 outside the passage envelope
|
||||||
|
double signedWallDistanceVoxels=std::numeric_limits<double>::infinity();
|
||||||
|
};
|
||||||
|
|
||||||
|
inline FPassageRegion ClassifyPassageRegion(
|
||||||
|
const VoxelForgeCore::ResolvedLayoutSnapshotV3* Layout,
|
||||||
|
const std::array<double,3>& PositionVoxels)
|
||||||
|
{
|
||||||
|
FPassageRegion best;
|
||||||
|
if(!Layout)return best;
|
||||||
|
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
|
double bestAbsoluteWallDistance=std::numeric_limits<double>::infinity();
|
||||||
|
for(const auto& passage:Layout->passages)
|
||||||
|
{
|
||||||
|
if(passage.controlPoints.size()<2)continue;
|
||||||
|
for(std::size_t index=0;index+1<passage.controlPoints.size();++index)
|
||||||
|
{
|
||||||
|
const auto& a=passage.controlPoints[index];
|
||||||
|
const auto& b=passage.controlPoints[index+1];
|
||||||
|
std::array<double,3> delta{},fromA{};
|
||||||
|
double lengthSquared=0.0,dot=0.0;
|
||||||
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
|
{
|
||||||
|
delta[axis]=(static_cast<double>(b.positionSubvoxels[axis])
|
||||||
|
-a.positionSubvoxels[axis])/Q;
|
||||||
|
fromA[axis]=PositionVoxels[axis]
|
||||||
|
-static_cast<double>(a.positionSubvoxels[axis])/Q;
|
||||||
|
lengthSquared+=delta[axis]*delta[axis];
|
||||||
|
dot+=fromA[axis]*delta[axis];
|
||||||
|
}
|
||||||
|
const double t=lengthSquared>0.0
|
||||||
|
?std::clamp(dot/lengthSquared,0.0,1.0):0.0;
|
||||||
|
double distanceSquared=0.0;
|
||||||
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
|
{
|
||||||
|
const double difference=fromA[axis]-t*delta[axis];
|
||||||
|
distanceSquared+=difference*difference;
|
||||||
|
}
|
||||||
|
const double radius=(static_cast<double>(a.radiusSubvoxels)+t*(
|
||||||
|
static_cast<double>(b.radiusSubvoxels)-a.radiusSubvoxels))/Q;
|
||||||
|
const double signedWallDistance=std::sqrt(distanceSquared)-radius;
|
||||||
|
if(std::abs(signedWallDistance)>=bestAbsoluteWallDistance)continue;
|
||||||
|
bestAbsoluteWallDistance=std::abs(signedWallDistance);
|
||||||
|
best.signedWallDistanceVoxels=signedWallDistance;
|
||||||
|
const bool endpointSegment=index<8
|
||||||
|
||index+9>=passage.controlPoints.size();
|
||||||
|
if(endpointSegment)
|
||||||
|
best.category=2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double vertical=fromA[2]-t*delta[2];
|
||||||
|
best.category=radius>0.0&&vertical<-0.55*radius?1:0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(best.signedWallDistanceVoxels>48.0)best.category=3;
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FPassageClampComparison ComparePassageClampMeshes(
|
||||||
|
const VoxelForgeCore::TileMesh& Base,const VoxelForgeCore::TileMesh& Candidate,
|
||||||
|
const VoxelForgeCore::ResolvedLayoutSnapshotV3* Layout,
|
||||||
|
std::uint32_t CoreVoxelSizeMicrons)
|
||||||
|
{
|
||||||
|
FPassageClampComparison result;
|
||||||
|
if(Base.debugDensitySamples.empty()
|
||||||
|
||Base.debugDensitySamples.size()!=Candidate.debugDensitySamples.size())return result;
|
||||||
|
const double root=std::cbrt(static_cast<double>(Base.debugDensitySamples.size()));
|
||||||
|
const std::int32_t dim=static_cast<std::int32_t>(std::llround(root));
|
||||||
|
if(dim<4||static_cast<std::size_t>(dim)*dim*dim!=Base.debugDensitySamples.size())return result;
|
||||||
|
const std::int32_t gridDim=dim-3;
|
||||||
|
const std::int32_t extent=VoxelForgeCore::CoreTileVoxelCount<<Base.key.lod;
|
||||||
|
if(gridDim<=0||extent%gridDim!=0)return result;
|
||||||
|
const std::int32_t step=extent/gridDim;
|
||||||
|
const double voxelSizeCm=static_cast<double>(CoreVoxelSizeMicrons)/10000.0;
|
||||||
|
const std::array<std::int32_t,3> origin={Base.key.coordinate.x*extent,
|
||||||
|
Base.key.coordinate.y*extent,Base.key.coordinate.z*extent};
|
||||||
|
const auto index=[dim](std::int32_t x,std::int32_t y,std::int32_t z)
|
||||||
|
{return (static_cast<std::size_t>(z)*dim+y)*dim+x;};
|
||||||
|
const auto solid=[](float density){return density<0.0f;};
|
||||||
|
for(std::int32_t z=0;z<dim;++z)
|
||||||
|
for(std::int32_t y=0;y<dim;++y)
|
||||||
|
for(std::int32_t x=0;x<dim;++x)
|
||||||
|
{
|
||||||
|
const float a=Base.debugDensitySamples[index(x,y,z)];
|
||||||
|
const float b=Candidate.debugDensitySamples[index(x,y,z)];
|
||||||
|
if(!std::isfinite(a)||!std::isfinite(b))return result;
|
||||||
|
if(a!=b)++result.changedSamples;
|
||||||
|
if(solid(a)!=solid(b))++result.signFlips;
|
||||||
|
result.maxAbsDensityDelta=std::max(result.maxAbsDensityDelta,
|
||||||
|
std::abs(static_cast<double>(a)-b));
|
||||||
|
++result.samples;
|
||||||
|
}
|
||||||
|
const auto inspectEdge=[&](std::int32_t x,std::int32_t y,std::int32_t z,
|
||||||
|
std::int32_t nx,std::int32_t ny,std::int32_t nz)
|
||||||
|
{
|
||||||
|
const float a0=Base.debugDensitySamples[index(x,y,z)];
|
||||||
|
const float a1=Base.debugDensitySamples[index(nx,ny,nz)];
|
||||||
|
const float b0=Candidate.debugDensitySamples[index(x,y,z)];
|
||||||
|
const float b1=Candidate.debugDensitySamples[index(nx,ny,nz)];
|
||||||
|
const bool crossBase=solid(a0)!=solid(a1);
|
||||||
|
const bool crossCandidate=solid(b0)!=solid(b1);
|
||||||
|
if(crossBase!=crossCandidate)++result.crossingEdgeMismatches;
|
||||||
|
if(!crossBase||!crossCandidate)return;
|
||||||
|
const double ta=static_cast<double>(a0)/(static_cast<double>(a0)-a1);
|
||||||
|
const double tb=static_cast<double>(b0)/(static_cast<double>(b0)-b1);
|
||||||
|
const double displacementCm=std::abs(ta-tb)*step*voxelSizeCm;
|
||||||
|
result.maxSurfaceDisplacementCm=std::max(result.maxSurfaceDisplacementCm,
|
||||||
|
displacementCm);
|
||||||
|
result.sumSurfaceDisplacementCm+=displacementCm;
|
||||||
|
++result.sharedCrossingEdges;
|
||||||
|
if(displacementCm<=1.0e-9)return;
|
||||||
|
++result.movedCrossingEdges;
|
||||||
|
std::array<double,3> location={origin[0]+(x-1)*step,
|
||||||
|
origin[1]+(y-1)*step,origin[2]+(z-1)*step};
|
||||||
|
location[0]+=(nx-x)*step*(ta+tb)*0.5;
|
||||||
|
location[1]+=(ny-y)*step*(ta+tb)*0.5;
|
||||||
|
location[2]+=(nz-z)*step*(ta+tb)*0.5;
|
||||||
|
const int region=ClassifyPassageRegion(Layout,location).category;
|
||||||
|
++result.movedEdgeRegions[static_cast<std::size_t>(region)];
|
||||||
|
};
|
||||||
|
for(std::int32_t z=0;z<dim;++z)
|
||||||
|
for(std::int32_t y=0;y<dim;++y)
|
||||||
|
for(std::int32_t x=0;x<dim;++x)
|
||||||
|
{
|
||||||
|
if(x+1<dim)inspectEdge(x,y,z,x+1,y,z);
|
||||||
|
if(y+1<dim)inspectEdge(x,y,z,x,y+1,z);
|
||||||
|
if(z+1<dim)inspectEdge(x,y,z,x,y,z+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Base.vertices.size()!=Candidate.vertices.size()
|
||||||
|
||Base.indices!=Candidate.indices)
|
||||||
|
result.normalPairingFailures=1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr double RadiansToDegrees=180.0/3.14159265358979323846;
|
||||||
|
for(std::size_t vertex=0;vertex<Base.vertices.size();++vertex)
|
||||||
|
{
|
||||||
|
const auto& a=Base.vertices[vertex].normal;
|
||||||
|
const auto& b=Candidate.vertices[vertex].normal;
|
||||||
|
const double lengthA=std::sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
|
||||||
|
const double lengthB=std::sqrt(b.x*b.x+b.y*b.y+b.z*b.z);
|
||||||
|
if(!(lengthA>0.0&&lengthB>0.0))continue;
|
||||||
|
const double cosine=std::clamp((a.x*b.x+a.y*b.y+a.z*b.z)
|
||||||
|
/(lengthA*lengthB),-1.0,1.0);
|
||||||
|
const double angle=std::acos(cosine)*RadiansToDegrees;
|
||||||
|
result.maxNormalAngleDegrees=std::max(result.maxNormalAngleDegrees,angle);
|
||||||
|
result.sumNormalAngleDegrees+=angle;
|
||||||
|
++result.normalVertices;
|
||||||
|
if(angle>1.0e-6)
|
||||||
|
{
|
||||||
|
++result.changedNormalVertices;
|
||||||
|
const double geometryVoxelSizeCm=voxelSizeCm;
|
||||||
|
const auto& position=Candidate.vertices[vertex].position;
|
||||||
|
const std::array<double,3> location={position.x/geometryVoxelSizeCm,
|
||||||
|
position.y/geometryVoxelSizeCm,position.z/geometryVoxelSizeCm};
|
||||||
|
const int region=ClassifyPassageRegion(Layout,location).category;
|
||||||
|
++result.normalVertexRegions[static_cast<std::size_t>(region)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.meshChanged=Base.meshHash!=Candidate.meshHash
|
||||||
|
||Base.vertices.size()!=Candidate.vertices.size()
|
||||||
|
||Base.indices!=Candidate.indices;
|
||||||
|
result.valid=true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FPassageSourceGradientStats
|
||||||
|
{
|
||||||
|
std::uint64_t candidateCrossings=0,sourceNearZeroSamples=0;
|
||||||
|
std::vector<double> gradientMagnitudes;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void GatherPassageSourceGradients(const VoxelForgeCore::World& World,
|
||||||
|
const VoxelForgeCore::TileMesh& Mesh,
|
||||||
|
const VoxelForgeCore::ResolvedLayoutSnapshotV3* Layout,
|
||||||
|
FPassageSourceGradientStats& Stats)
|
||||||
|
{
|
||||||
|
if(Mesh.debugDensitySamples.empty())return;
|
||||||
|
const double root=std::cbrt(static_cast<double>(Mesh.debugDensitySamples.size()));
|
||||||
|
const std::int32_t dim=static_cast<std::int32_t>(std::llround(root));
|
||||||
|
if(dim<4||static_cast<std::size_t>(dim)*dim*dim!=Mesh.debugDensitySamples.size())return;
|
||||||
|
const std::int32_t gridDim=dim-3;
|
||||||
|
const std::int32_t extent=VoxelForgeCore::CoreTileVoxelCount<<Mesh.key.lod;
|
||||||
|
if(gridDim<=0||extent%gridDim!=0)return;
|
||||||
|
const std::int32_t step=extent/gridDim;
|
||||||
|
const std::array<std::int32_t,3> origin={Mesh.key.coordinate.x*extent,
|
||||||
|
Mesh.key.coordinate.y*extent,Mesh.key.coordinate.z*extent};
|
||||||
|
const auto index=[dim](std::int32_t x,std::int32_t y,std::int32_t z)
|
||||||
|
{return (static_cast<std::size_t>(z)*dim+y)*dim+x;};
|
||||||
|
std::uint64_t eligibleCrossings=0;
|
||||||
|
constexpr std::uint64_t SampleStride=32;
|
||||||
|
constexpr double H=1.0;
|
||||||
|
const auto inspect=[&](std::int32_t x,std::int32_t y,std::int32_t z,
|
||||||
|
std::int32_t nx,std::int32_t ny,std::int32_t nz)
|
||||||
|
{
|
||||||
|
const float d0=Mesh.debugDensitySamples[index(x,y,z)];
|
||||||
|
const float d1=Mesh.debugDensitySamples[index(nx,ny,nz)];
|
||||||
|
if((d0<0.0f)==(d1<0.0f))return;
|
||||||
|
const double t=static_cast<double>(d0)/(static_cast<double>(d0)-d1);
|
||||||
|
std::array<double,3> location={origin[0]+(x-1)*step,
|
||||||
|
origin[1]+(y-1)*step,origin[2]+(z-1)*step};
|
||||||
|
location[0]+=(nx-x)*step*t;
|
||||||
|
location[1]+=(ny-y)*step*t;
|
||||||
|
location[2]+=(nz-z)*step*t;
|
||||||
|
if(ClassifyPassageRegion(Layout,location).category!=3)return;
|
||||||
|
++Stats.candidateCrossings;
|
||||||
|
if((eligibleCrossings++%SampleStride)!=0)return;
|
||||||
|
const VoxelForgeCore::Vec3d point{location[0],location[1],location[2]};
|
||||||
|
const double center=World.passageSourceDensityAt(point);
|
||||||
|
if(!std::isfinite(center)||std::abs(center)>2.0)return;
|
||||||
|
++Stats.sourceNearZeroSamples;
|
||||||
|
std::array<double,3> gradient{};
|
||||||
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
|
{
|
||||||
|
auto before=point,after=point;
|
||||||
|
if(axis==0){before.x-=H;after.x+=H;}
|
||||||
|
else if(axis==1){before.y-=H;after.y+=H;}
|
||||||
|
else {before.z-=H;after.z+=H;}
|
||||||
|
gradient[axis]=(World.passageSourceDensityAt(after)
|
||||||
|
-World.passageSourceDensityAt(before))/(2.0*H);
|
||||||
|
}
|
||||||
|
const double magnitude=std::sqrt(gradient[0]*gradient[0]
|
||||||
|
+gradient[1]*gradient[1]+gradient[2]*gradient[2]);
|
||||||
|
if(std::isfinite(magnitude))Stats.gradientMagnitudes.push_back(magnitude);
|
||||||
|
};
|
||||||
|
for(std::int32_t z=0;z<dim;++z)
|
||||||
|
for(std::int32_t y=0;y<dim;++y)
|
||||||
|
for(std::int32_t x=0;x<dim;++x)
|
||||||
|
{
|
||||||
|
if(x+1<dim)inspect(x,y,z,x+1,y,z);
|
||||||
|
if(y+1<dim)inspect(x,y,z,x,y+1,z);
|
||||||
|
if(z+1<dim)inspect(x,y,z,x,y,z+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int AuditPassageSourceClamp(VoxelForgeCore::World& Shape,
|
||||||
|
const FStandaloneDesiredTileSet& Desired,
|
||||||
|
const VoxelForgeCore::ResolvedLayoutSnapshotV3* Layout,
|
||||||
|
std::uint32_t CoreVoxelSizeMicrons)
|
||||||
|
{
|
||||||
|
constexpr std::array<double,4> Floors={2.0,3.0,4.0,6.0};
|
||||||
|
std::vector<VoxelForgeCore::TileKey> keys;
|
||||||
|
std::array<std::uint64_t,3> expectedByLod{};
|
||||||
|
for(const FVoxelTileKey& tile:Desired.Tiles)
|
||||||
|
{
|
||||||
|
if(tile.Level<0||tile.Level>2)continue;
|
||||||
|
keys.push_back({{tile.Coord.X,tile.Coord.Y,tile.Coord.Z},tile.Level});
|
||||||
|
++expectedByLod[static_cast<std::size_t>(tile.Level)];
|
||||||
|
}
|
||||||
|
if(keys.empty())
|
||||||
|
{
|
||||||
|
std::printf("[L91PassageClampAudit] status=FAIL reason=no_lod0_2_tiles\n");
|
||||||
|
return 14;
|
||||||
|
}
|
||||||
|
std::printf("[L91PassageClampCoverage] tiles=%zu lod0=%llu lod1=%llu lod2=%llu mode=full_desired_near_set\n",
|
||||||
|
keys.size(),static_cast<unsigned long long>(expectedByLod[0]),
|
||||||
|
static_cast<unsigned long long>(expectedByLod[1]),
|
||||||
|
static_cast<unsigned long long>(expectedByLod[2]));
|
||||||
|
VoxelForgeCore::TileGenerationOptions baseOptions;
|
||||||
|
baseOptions.hashDensity=true;
|
||||||
|
baseOptions.captureDensitySamples=true;
|
||||||
|
baseOptions.forceFullDensityCapture=true;
|
||||||
|
baseOptions.skipUvAndColors=true;
|
||||||
|
baseOptions.skipMaterialGroups=true;
|
||||||
|
VoxelForgeCore::TileGenerationOptions candidateOptions=baseOptions;
|
||||||
|
candidateOptions.profilePassageComposer=true;
|
||||||
|
std::array<std::uint64_t,4> tileCount{},sampleCount{},changedSamples{},signFlips{},
|
||||||
|
crossingMismatches{},sharedCrossings{},movedCrossings{},changedTiles{},
|
||||||
|
normalVertices{},normalPairingFailures{},changedNormalVertices{};
|
||||||
|
std::array<std::uint64_t,4> movedRegions[4]{},normalRegions[4]{};
|
||||||
|
std::array<double,4> maxDisplacementCm{},sumDisplacementCm{},maxNormalAngle{};
|
||||||
|
std::array<double,4> sumNormalAngle{};
|
||||||
|
FPassageSourceGradientStats gradientStats;
|
||||||
|
std::uint64_t generationFailures=0,invalidComparisons=0;
|
||||||
|
for(const VoxelForgeCore::TileKey& key:keys)
|
||||||
|
{
|
||||||
|
std::string error;
|
||||||
|
const auto base=Shape.generateTile(key,baseOptions,error);
|
||||||
|
if(!base)
|
||||||
|
{
|
||||||
|
++generationFailures;
|
||||||
|
std::printf("[L91PassageClampTileFailure] mode=base key=(%d,%d,%d,lod%d) error=%s\n",
|
||||||
|
key.coordinate.x,key.coordinate.y,key.coordinate.z,key.lod,error.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GatherPassageSourceGradients(Shape,*base,Layout,gradientStats);
|
||||||
|
for(std::size_t floorIndex=0;floorIndex<Floors.size();++floorIndex)
|
||||||
|
{
|
||||||
|
candidateOptions.diagnosticPassageSourceFloorVoxels=Floors[floorIndex];
|
||||||
|
error.clear();
|
||||||
|
const auto candidate=Shape.generateTile(key,candidateOptions,error);
|
||||||
|
if(!candidate)
|
||||||
|
{
|
||||||
|
++generationFailures;
|
||||||
|
std::printf("[L91PassageClampTileFailure] floor_vox=%.0f key=(%d,%d,%d,lod%d) error=%s\n",
|
||||||
|
Floors[floorIndex],key.coordinate.x,key.coordinate.y,key.coordinate.z,
|
||||||
|
key.lod,error.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const FPassageClampComparison comparison=ComparePassageClampMeshes(
|
||||||
|
*base,*candidate,Layout,CoreVoxelSizeMicrons);
|
||||||
|
if(!comparison.valid)
|
||||||
|
{
|
||||||
|
++invalidComparisons;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++tileCount[floorIndex];
|
||||||
|
sampleCount[floorIndex]+=comparison.samples;
|
||||||
|
changedSamples[floorIndex]+=comparison.changedSamples;
|
||||||
|
signFlips[floorIndex]+=comparison.signFlips;
|
||||||
|
crossingMismatches[floorIndex]+=comparison.crossingEdgeMismatches;
|
||||||
|
sharedCrossings[floorIndex]+=comparison.sharedCrossingEdges;
|
||||||
|
movedCrossings[floorIndex]+=comparison.movedCrossingEdges;
|
||||||
|
changedTiles[floorIndex]+=comparison.meshChanged?1u:0u;
|
||||||
|
normalVertices[floorIndex]+=comparison.normalVertices;
|
||||||
|
normalPairingFailures[floorIndex]+=comparison.normalPairingFailures;
|
||||||
|
changedNormalVertices[floorIndex]+=comparison.changedNormalVertices;
|
||||||
|
maxDisplacementCm[floorIndex]=std::max(maxDisplacementCm[floorIndex],
|
||||||
|
comparison.maxSurfaceDisplacementCm);
|
||||||
|
sumDisplacementCm[floorIndex]+=comparison.sumSurfaceDisplacementCm;
|
||||||
|
maxNormalAngle[floorIndex]=std::max(maxNormalAngle[floorIndex],
|
||||||
|
comparison.maxNormalAngleDegrees);
|
||||||
|
sumNormalAngle[floorIndex]+=comparison.sumNormalAngleDegrees;
|
||||||
|
for(std::size_t region=0;region<4;++region)
|
||||||
|
{
|
||||||
|
movedRegions[floorIndex][region]+=comparison.movedEdgeRegions[region];
|
||||||
|
normalRegions[floorIndex][region]+=comparison.normalVertexRegions[region];
|
||||||
|
}
|
||||||
|
std::printf("[L91PassageClampTile] floor_vox=%.0f key=(%d,%d,%d,lod%d) samples=%llu changed=%llu sign_flips=%llu moved_edges=%llu max_displacement_cm=%.6g normal_vertices=%llu max_normal_degrees=%.6g changed_mesh=%d\n",
|
||||||
|
Floors[floorIndex],key.coordinate.x,key.coordinate.y,key.coordinate.z,key.lod,
|
||||||
|
static_cast<unsigned long long>(comparison.samples),
|
||||||
|
static_cast<unsigned long long>(comparison.changedSamples),
|
||||||
|
static_cast<unsigned long long>(comparison.signFlips),
|
||||||
|
static_cast<unsigned long long>(comparison.movedCrossingEdges),
|
||||||
|
comparison.maxSurfaceDisplacementCm,
|
||||||
|
static_cast<unsigned long long>(comparison.normalVertices),
|
||||||
|
comparison.maxNormalAngleDegrees,comparison.meshChanged?1:0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool acceptedAtAllFloors=generationFailures==0&&invalidComparisons==0
|
||||||
|
&&keys.size()>0;
|
||||||
|
for(std::size_t floorIndex=0;floorIndex<Floors.size();++floorIndex)
|
||||||
|
{
|
||||||
|
const double meanDisplacement=sharedCrossings[floorIndex]
|
||||||
|
?sumDisplacementCm[floorIndex]/sharedCrossings[floorIndex]:0.0;
|
||||||
|
const double meanNormal=normalVertices[floorIndex]
|
||||||
|
?sumNormalAngle[floorIndex]/normalVertices[floorIndex]:0.0;
|
||||||
|
const bool accepted=tileCount[floorIndex]==keys.size()
|
||||||
|
&&signFlips[floorIndex]==0&&crossingMismatches[floorIndex]==0
|
||||||
|
&&maxDisplacementCm[floorIndex]<=1.0
|
||||||
|
&&maxNormalAngle[floorIndex]<=2.0
|
||||||
|
&&normalPairingFailures[floorIndex]==0;
|
||||||
|
acceptedAtAllFloors=acceptedAtAllFloors&&accepted;
|
||||||
|
std::printf("[L91PassageClampSummary] floor_vox=%.0f tiles=%llu/%zu samples=%llu changed_samples=%llu sign_flips=%llu edge_crossing_mismatches=%llu shared_crossings=%llu moved_crossings=%llu max_displacement_cm=%.6g mean_displacement_cm=%.6g changed_mesh_tiles=%llu normal_vertices=%llu changed_normal_vertices=%llu max_normal_degrees=%.6g mean_normal_degrees=%.6g normal_pairing_failures=%llu moved_regions=(wall:%llu,floor:%llu,mouth:%llu,other:%llu) normal_regions=(wall:%llu,floor:%llu,mouth:%llu,other:%llu) status=%s\n",
|
||||||
|
Floors[floorIndex],static_cast<unsigned long long>(tileCount[floorIndex]),
|
||||||
|
keys.size(),static_cast<unsigned long long>(sampleCount[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(changedSamples[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(signFlips[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(crossingMismatches[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(sharedCrossings[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(movedCrossings[floorIndex]),
|
||||||
|
maxDisplacementCm[floorIndex],meanDisplacement,
|
||||||
|
static_cast<unsigned long long>(changedTiles[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(normalVertices[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(changedNormalVertices[floorIndex]),
|
||||||
|
maxNormalAngle[floorIndex],meanNormal,
|
||||||
|
static_cast<unsigned long long>(normalPairingFailures[floorIndex]),
|
||||||
|
static_cast<unsigned long long>(movedRegions[floorIndex][0]),
|
||||||
|
static_cast<unsigned long long>(movedRegions[floorIndex][1]),
|
||||||
|
static_cast<unsigned long long>(movedRegions[floorIndex][2]),
|
||||||
|
static_cast<unsigned long long>(movedRegions[floorIndex][3]),
|
||||||
|
static_cast<unsigned long long>(normalRegions[floorIndex][0]),
|
||||||
|
static_cast<unsigned long long>(normalRegions[floorIndex][1]),
|
||||||
|
static_cast<unsigned long long>(normalRegions[floorIndex][2]),
|
||||||
|
static_cast<unsigned long long>(normalRegions[floorIndex][3]),
|
||||||
|
accepted?"PASS":"FAIL");
|
||||||
|
}
|
||||||
|
std::sort(gradientStats.gradientMagnitudes.begin(),
|
||||||
|
gradientStats.gradientMagnitudes.end());
|
||||||
|
const auto percentile=[](const std::vector<double>& values,double p)
|
||||||
|
{
|
||||||
|
if(values.empty())return 0.0;
|
||||||
|
const std::size_t index=std::min(values.size()-1,
|
||||||
|
static_cast<std::size_t>(std::ceil(p*values.size())-1));
|
||||||
|
return values[index];
|
||||||
|
};
|
||||||
|
const double gradientMean=gradientStats.gradientMagnitudes.empty()?0.0:
|
||||||
|
std::accumulate(gradientStats.gradientMagnitudes.begin(),
|
||||||
|
gradientStats.gradientMagnitudes.end(),0.0)
|
||||||
|
/gradientStats.gradientMagnitudes.size();
|
||||||
|
std::printf("[L91PassageSourceGradient] surface_source_crossings=%llu sampled_near_zero=%llu gradient_samples=%zu step_vox=1 source_abs_limit_vox=2 p50=%.6g p90=%.6g max=%.6g mean=%.6g status=%s\n",
|
||||||
|
static_cast<unsigned long long>(gradientStats.candidateCrossings),
|
||||||
|
static_cast<unsigned long long>(gradientStats.sourceNearZeroSamples),
|
||||||
|
gradientStats.gradientMagnitudes.size(),percentile(gradientStats.gradientMagnitudes,0.5),
|
||||||
|
percentile(gradientStats.gradientMagnitudes,0.9),
|
||||||
|
gradientStats.gradientMagnitudes.empty()?0.0:gradientStats.gradientMagnitudes.back(),
|
||||||
|
gradientMean,gradientStats.gradientMagnitudes.size()>=64?"MEASURED":"LOW_SAMPLE");
|
||||||
|
std::printf("[L91PassageClampAudit] tiles=%zu generation_failures=%llu invalid_comparisons=%llu status=%s\n",
|
||||||
|
keys.size(),static_cast<unsigned long long>(generationFailures),
|
||||||
|
static_cast<unsigned long long>(invalidComparisons),
|
||||||
|
acceptedAtAllFloors?"PASS":"FAIL");
|
||||||
|
return acceptedAtAllFloors?0:14;
|
||||||
|
}
|
||||||
|
|
||||||
struct FLandmarkReachabilityResult
|
struct FLandmarkReachabilityResult
|
||||||
{
|
{
|
||||||
std::uint64_t pathSamples=0,capsuleSamples=0,blockedCapsuleSamples=0;
|
std::uint64_t pathSamples=0,capsuleSamples=0,blockedCapsuleSamples=0;
|
||||||
@@ -1885,7 +2305,7 @@ namespace StandaloneStreamBenchmark
|
|||||||
bool bLinux77Profile=false,int32 SchedulerPolicy=-1,
|
bool bLinux77Profile=false,int32 SchedulerPolicy=-1,
|
||||||
bool bMovingCameraTrace=false,double MovingCameraSpeedMetersPerSecond=0.0,
|
bool bMovingCameraTrace=false,double MovingCameraSpeedMetersPerSecond=0.0,
|
||||||
double MovingCameraDurationSeconds=12.0,double MovingCameraDwellSeconds=5.0,
|
double MovingCameraDurationSeconds=12.0,double MovingCameraDwellSeconds=5.0,
|
||||||
bool bColdWorkerTimeline=false)
|
bool bColdWorkerTimeline=false,bool bAuditPassageSourceClamp=false)
|
||||||
{
|
{
|
||||||
using Clock=std::chrono::steady_clock;
|
using Clock=std::chrono::steady_clock;
|
||||||
const std::clock_t ColdCpuOrigin=std::clock();
|
const std::clock_t ColdCpuOrigin=std::clock();
|
||||||
@@ -2054,7 +2474,8 @@ namespace StandaloneStreamBenchmark
|
|||||||
const bool bFarWorldAudit=bAuditNativeCaves||bAuditNativeLattice||bAuditMotifIntervals
|
const bool bFarWorldAudit=bAuditNativeCaves||bAuditNativeLattice||bAuditMotifIntervals
|
||||||
||bAuditOreVeinYield||bAuditLandmarkReachability||bAuditStrateTransitions
|
||bAuditOreVeinYield||bAuditLandmarkReachability||bAuditStrateTransitions
|
||||||
||bAuditResolvedLayoutPassages||bAuditResolvedLayoutBoundaries
|
||bAuditResolvedLayoutPassages||bAuditResolvedLayoutBoundaries
|
||||||
||bAuditTileShapeReadiness||bAuditBasePageEquivalence||bAuditRouteParity;
|
||bAuditTileShapeReadiness||bAuditBasePageEquivalence||bAuditRouteParity
|
||||||
|
||bAuditPassageSourceClamp;
|
||||||
const bool bDeferFarWorld=bIncludeFarWorld&&!bMovingCameraTrace&&!bFarWorldAudit;
|
const bool bDeferFarWorld=bIncludeFarWorld&&!bMovingCameraTrace&&!bFarWorldAudit;
|
||||||
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
|
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
|
||||||
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
|
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
|
||||||
@@ -2134,6 +2555,12 @@ namespace StandaloneStreamBenchmark
|
|||||||
Streamer.Stop();
|
Streamer.Stop();
|
||||||
std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;
|
std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;
|
||||||
}
|
}
|
||||||
|
if(bAuditPassageSourceClamp)
|
||||||
|
{
|
||||||
|
Streamer.Stop();
|
||||||
|
return AuditPassageSourceClamp(Shape,Desired,ResolvedLayout,
|
||||||
|
World.CoreVoxelSizeMicrons);
|
||||||
|
}
|
||||||
if(bAuditNativeCaves)
|
if(bAuditNativeCaves)
|
||||||
{
|
{
|
||||||
Streamer.Stop();
|
Streamer.Stop();
|
||||||
|
|||||||
Reference in new issue
Block a user