passages: swept tube evaluates the exact route on in-bound cache misses (L100, v216)
L99 treated a missing exact-grid sweep sample as "no route here", so off-grid queries exposed the FI/TN boundary band inside passage 1-2 (flat ceiling/floor). In-bound misses now evaluate the exact route; a conservative route-feature bound still skips out-of-extent misses. Composition order unchanged (graph -> bands -> passage -> stamps -> floor caps). Comparison now counts added/removed crossings and triangles: 0/0 crossings on all four strates (FI +56 triangles). 1-2 mid-tunnel: L98->L100 changes 32k px (L99 changed 1.14M). Near-ready @W12 (L98/L99/L100): FI 2.62/1.78/2.05, TN 2.36/1.55/1.80, SW 1.17/0.95/1.04, VS 1.16/1.03/1.08 s. All walk audits pass; 24/24 Clang/GCC W1/W8/W12 determinism; fast tier PASS. 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
fa6363b31a
commit
2d5822cdf7
47 files changed
+1433
-22
No files matched your search
@@ -476,7 +476,7 @@ namespace VoxelForgeCore
|
||||
// Version 210 keeps bulk native-cave sampling on the scalar field path at strata edges.
|
||||
// Version 211 makes coordinate biasing in the shared cell hash unsigned, removing signed-overflow UB.
|
||||
// Version 212 balances generated entry routes against existing walk lanes and preserves their shared treads.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 215;
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 216;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
|
||||
@@ -279,6 +279,7 @@ public:
|
||||
double signedDistance=std::numeric_limits<double>::infinity();
|
||||
double t=0.0;
|
||||
std::uint32_t segmentIndex=std::numeric_limits<std::uint32_t>::max();
|
||||
std::uint8_t scanPhase=std::numeric_limits<std::uint8_t>::max();
|
||||
float wallRelief=0.0f,mouthSurfaceRelief=0.0f,mouthTreadFieldRelief=0.0f;
|
||||
bool valid=false,hasWallRelief=false,hasMouthSurfaceRelief=false,
|
||||
hasMouthTreadFieldRelief=false;
|
||||
@@ -634,6 +635,28 @@ public:
|
||||
const auto& candidates=columnFeature?passageColumns_:passageRoutes_;
|
||||
return passageIndex<candidates.size()&&candidates[passageIndex]!=0;
|
||||
}
|
||||
bool hasUpperMouthSupport(std::size_t passageIndex) const
|
||||
{
|
||||
return std::find(upperMouthSupportPassages_.begin(),
|
||||
upperMouthSupportPassages_.end(),passageIndex)
|
||||
!=upperMouthSupportPassages_.end();
|
||||
}
|
||||
bool routeFeatureMayAffect(std::size_t passageIndex,double qx,double qy,
|
||||
double qz) const
|
||||
{
|
||||
if(passageIndex>=passageRouteSegments_.size())return false;
|
||||
for(const FCandidateSegment& candidate:passageRouteSegments_[passageIndex])
|
||||
{
|
||||
if(qx<candidate.minimumSubvoxels[0]
|
||||
||qx>candidate.maximumSubvoxels[0]
|
||||
||qy<candidate.minimumSubvoxels[1]
|
||||
||qy>candidate.maximumSubvoxels[1]
|
||||
||qz<candidate.minimumSubvoxels[2]
|
||||
||qz>candidate.maximumSubvoxels[2])continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const std::vector<FCandidateSegment>& mouthSupportSegments(std::size_t passageIndex) const
|
||||
{
|
||||
static const std::vector<FCandidateSegment> Empty;
|
||||
@@ -1910,14 +1933,28 @@ public:
|
||||
if(l90CandidateProfiled)recordColumnProof(columnDistance,composed);
|
||||
composed=std::min(composed,static_cast<float>(columnDistance/Q));
|
||||
}
|
||||
const bool usePreparedPassageSweep=passageTileScopeMatches
|
||||
&&passageCarveReachEnabled&&passageTileQueries->hasSweptTubeBase();
|
||||
const auto* preparedSweepSample=usePreparedPassageSweep
|
||||
const bool preparedPassageSweepRequested=passageTileScopeMatches
|
||||
&&passageCarveReachEnabled
|
||||
&&passageTileQueries->hasSweptTubeBase();
|
||||
const auto* preparedSweepSample=preparedPassageSweepRequested
|
||||
?passageTileQueries->sweptSample(passageIndex,qx,qy,qz):nullptr;
|
||||
// The tile sweep has already visited every segment whose bounded route or
|
||||
// support envelope reaches this lattice point. No route query can affect it.
|
||||
if(usePreparedPassageSweep&&(!preparedSweepSample
|
||||
||preparedSweepSample->signedDistance>passageCarveReachQ))continue;
|
||||
// The sweep is indexed at the tile's exact lattice points. Mesher and seam
|
||||
// queries can also arrive at interpolated off-grid positions; a cache miss
|
||||
// at those points says nothing about route influence, so use the exact direct
|
||||
// route search instead of dropping the carve.
|
||||
const bool usePreparedPassageSweep=preparedSweepSample!=nullptr;
|
||||
// Candidate route bounds include the carve reach, tread/clearance extents,
|
||||
// and conservative padding. A missing lattice sample outside every route
|
||||
// bound cannot affect this query; keep direct evaluation for all in-bound
|
||||
// misses and for the separate column and mouth-support paths.
|
||||
if(preparedPassageSweepRequested&&!preparedSweepSample
|
||||
&&!passageTileQueries->hasFeature(passageIndex,true)
|
||||
&&!passageTileQueries->hasMouthSupport(passageIndex)
|
||||
&&!passageTileQueries->hasUpperMouthSupport(passageIndex)
|
||||
&&!passageTileQueries->routeFeatureMayAffect(passageIndex,qx,qy,qz))
|
||||
continue;
|
||||
if(usePreparedPassageSweep
|
||||
&&preparedSweepSample->signedDistance>passageCarveReachQ)continue;
|
||||
const bool tilePassageFree=passageTileScopeMatches
|
||||
&&!ActivePassageTileQueries->hasFeature(passageIndex,false);
|
||||
if(composed>=0.0f&&tilePassageFree)
|
||||
@@ -2111,7 +2148,7 @@ public:
|
||||
bestSignedDistance=preparedSweepSample->signedDistance;
|
||||
bestT=preparedSweepSample->t;
|
||||
bestIndex=static_cast<std::ptrdiff_t>(preparedSweepSample->segmentIndex);
|
||||
bestScanPhase=0;
|
||||
bestScanPhase=preparedSweepSample->scanPhase;
|
||||
bestScanIndex=bestIndex;
|
||||
}
|
||||
else if(passageTileScopeMatches)
|
||||
@@ -14092,6 +14129,46 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
auto& passageSamples=sweep->passages.emplace_back();
|
||||
passageSamples.passageIndex=passageIndex;
|
||||
passageSamples.samples.resize(gridSampleCount);
|
||||
const auto& constants=shape_->PassageComposerConstants[passageIndex];
|
||||
struct FCarveWindow
|
||||
{
|
||||
std::ptrdiff_t begin=1,end=0;
|
||||
};
|
||||
std::vector<FCarveWindow> carveWindows(static_cast<std::size_t>(sweep->dimension));
|
||||
const auto& floorProfileQ=constants.controlFloorProfileQ;
|
||||
const std::ptrdiff_t lowerMouthIndex=constants.lowerMouthIndex;
|
||||
if(lowerMouthIndex>=0
|
||||
&&static_cast<std::size_t>(lowerMouthIndex)<floorProfileQ.size())
|
||||
{
|
||||
const auto compareFloorProfile=[](double floorProfile,double value)
|
||||
{return floorProfile>value;};
|
||||
const auto profileBegin=floorProfileQ.begin();
|
||||
const auto profileEnd=profileBegin+lowerMouthIndex+1;
|
||||
for(std::int32_t gz=0;gz<sweep->dimension;++gz)
|
||||
{
|
||||
const double qz=static_cast<double>(sweep->gridMinimumSubvoxels[2]
|
||||
+static_cast<std::int64_t>(gz)*sweep->stepSubvoxels);
|
||||
const auto carveHigh=std::lower_bound(profileBegin,profileEnd,
|
||||
qz+constants.carveSearchMargin,compareFloorProfile);
|
||||
const auto carveLow=std::lower_bound(profileBegin,profileEnd,
|
||||
qz-constants.carveSearchMargin,compareFloorProfile);
|
||||
auto& window=carveWindows[static_cast<std::size_t>(gz)];
|
||||
window.begin=std::max<std::ptrdiff_t>(0,
|
||||
(carveHigh-profileBegin)-1);
|
||||
window.end=std::min<std::ptrdiff_t>(lowerMouthIndex-1,
|
||||
(carveLow-profileBegin)+1);
|
||||
}
|
||||
}
|
||||
const auto scanPhaseForSegment=[&](std::ptrdiff_t segmentIndex,
|
||||
const FCarveWindow& window)
|
||||
{
|
||||
if(segmentIndex>=window.begin&&segmentIndex<=window.end)return 0;
|
||||
if(segmentIndex<std::min<std::ptrdiff_t>(8,lowerMouthIndex))return 1;
|
||||
if(segmentIndex>=constants.mouthSearchBegin
|
||||
&&segmentIndex<constants.mouthSearchEnd)return 2;
|
||||
if(segmentIndex>=lowerMouthIndex&&segmentIndex<constants.lastIndex)return 3;
|
||||
return -1;
|
||||
};
|
||||
for(const auto& candidate:candidates)
|
||||
{
|
||||
if(candidate.segmentIndex>=shape_->PassageSegmentData[passageIndex].size())continue;
|
||||
@@ -14101,7 +14178,6 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
candidate.sweepMaximumSubvoxels[axis],first[axis],last[axis]);
|
||||
if(first[0]>last[0]||first[1]>last[1]||first[2]>last[2])continue;
|
||||
|
||||
const auto& constants=shape_->PassageComposerConstants[passageIndex];
|
||||
const auto& segment=shape_->PassageSegmentData[passageIndex][candidate.segmentIndex];
|
||||
if(segment.lengthSq<=0.0)continue;
|
||||
const std::ptrdiff_t segmentIndex=static_cast<std::ptrdiff_t>(candidate.segmentIndex);
|
||||
@@ -14112,9 +14188,13 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
&&!shape_->IsPassageShortSpanSegment(passageIndex,candidate.segmentIndex)
|
||||
&&!shape_->IsPassageShortSpanSegment(passageIndex,candidate.segmentIndex+1);
|
||||
for(std::int32_t gz=first[2];gz<=last[2];++gz)
|
||||
for(std::int32_t gy=first[1];gy<=last[1];++gy)
|
||||
for(std::int32_t gx=first[0];gx<=last[0];++gx)
|
||||
{
|
||||
const int scanPhase=scanPhaseForSegment(segmentIndex,
|
||||
carveWindows[static_cast<std::size_t>(gz)]);
|
||||
if(scanPhase<0)continue;
|
||||
for(std::int32_t gy=first[1];gy<=last[1];++gy)
|
||||
for(std::int32_t gx=first[0];gx<=last[0];++gx)
|
||||
{
|
||||
const double qx=static_cast<double>(sweep->gridMinimumSubvoxels[0]
|
||||
+static_cast<std::int64_t>(gx)*sweep->stepSubvoxels);
|
||||
const double qy=static_cast<double>(sweep->gridMinimumSubvoxels[1]
|
||||
@@ -14162,17 +14242,21 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
if(!sample.valid||signedDistance<sample.signedDistance
|
||||
||(signedDistance==sample.signedDistance
|
||||
&&candidate.segmentIndex<sample.segmentIndex))
|
||||
&&(scanPhase<sample.scanPhase
|
||||
||(scanPhase==sample.scanPhase
|
||||
&&candidate.segmentIndex<sample.segmentIndex))))
|
||||
{
|
||||
sample.signedDistance=signedDistance;
|
||||
sample.t=t;
|
||||
sample.segmentIndex=static_cast<std::uint32_t>(candidate.segmentIndex);
|
||||
sample.scanPhase=static_cast<std::uint8_t>(scanPhase);
|
||||
sample.valid=true;
|
||||
sample.hasWallRelief=false;
|
||||
sample.hasMouthSurfaceRelief=false;
|
||||
sample.hasMouthTreadFieldRelief=false;
|
||||
if(profile)++profileStats_->passageSweepMinimumUpdates;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user