passages: exact relief skip + per-tile BVH node masks (L82); FI/TN LOD0-2 -12%

- Wall relief noise is skipped when its hard-bounded contribution cannot change the final max;
  mouth surface/tread noise only on paths that use it.
- Exact active BVH-node masks cached per tile/passage/segment range; no per-sample lower_bound.
- Full-view audit imports the exported Core plan (not the stale 26-point root route): 21,425/21,425
  walkability samples pass.
Cold (L80 protocol, medians) LOD0-2: SW 1.16->1.11, FI 2.86->2.51, TN 2.88->2.54, VS 1.23->1.22 s.
Passage share FI 64.6->58.7%, TN 65.4->58.4%. Hashes identical (v214). TN "slowdown" from L81
not reproduced (5 pairs, 3.08 -> 2.75 s). Fast tier PASS; Linux UE host builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-27 23:46:15 +01:00
1 parent 9cb5e53b17
commit f572108dc4
10 files changed
+665 -41

No files matched your search

+165 -38
View File
@@ -179,6 +179,11 @@ public:
std::size_t segmentIndex=0;
std::array<std::int64_t,3> minimumSubvoxels{},maximumSubvoxels{};
};
struct FSegmentRangeCache
{
std::ptrdiff_t first=-1,end=-1;
std::vector<std::uint8_t> activeNodes;
};
FScopedPassageTileQueries(const FStandaloneShapeWorld& shape,
const std::array<std::int64_t,3>& minimumSubvoxels,
@@ -201,6 +206,7 @@ public:
passageColumns_=passageRoutes_;
passageMouthSupports_=passageRoutes_;
passageMouthSupportSegments_.resize(passageRoutes_.size());
passageSegmentRangeCaches_.resize(passageRoutes_.size());
if(shape.ResolvedLayout&&!shape.ResolvedLayout->passages.empty())
{
constexpr double Q=static_cast<double>(
@@ -281,6 +287,22 @@ public:
return passageIndex<passageMouthSupportSegments_.size()
?passageMouthSupportSegments_[passageIndex]:Empty;
}
const std::vector<std::uint8_t>* segmentRangeNodeMask(std::size_t passageIndex,
std::ptrdiff_t first,std::ptrdiff_t end,int priority) const
{
if(passageIndex>=passageSegmentRangeCaches_.size()
||priority<0||priority>=4)return nullptr;
FSegmentRangeCache& cache=passageSegmentRangeCaches_[passageIndex][
static_cast<std::size_t>(priority)];
if(cache.first!=first||cache.end!=end)
{
cache.first=first;
cache.end=end;
cache.activeNodes=shape_->BuildPassageSegmentRangeNodeMask(
passageIndex,first,end);
}
return &cache.activeNodes;
}
bool hasMouthSupport(std::size_t passageIndex) const
{return passageIndex<passageMouthSupports_.size()&&passageMouthSupports_[passageIndex]!=0;}
bool hasAnyMouthSupport() const
@@ -317,6 +339,7 @@ public:
std::vector<std::uint32_t> cavernFeatureIndices_;
std::vector<std::uint8_t> passageRoutes_,passageColumns_,passageMouthSupports_;
std::vector<std::vector<FCandidateSegment>> passageMouthSupportSegments_;
mutable std::vector<std::array<FSegmentRangeCache,4>> passageSegmentRangeCaches_;
std::vector<std::size_t> upperMouthSupportPassages_;
std::size_t routeSegmentCandidateCount_=0;
bool routeFeatureOverlap_=false,columnZOverlap_=false;
@@ -1513,17 +1536,46 @@ public:
?std::clamp(-(qz-(nearestA.positionSubvoxels[2]+bestT*(
static_cast<double>(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2])))
/distanceToCenter,0.0,1.0):0.0;
const float relief=VF_FieldPassageWallRelief(static_cast<float>(X),
static_cast<float>(Y),static_cast<float>(Z),
static_cast<std::uint32_t>(Owner?Owner->Seed:0));
const float mouthSurfaceRelief=VF_FieldSurfaceRelief(static_cast<float>(X)*1.5f,
static_cast<float>(Y)*1.5f,static_cast<float>(Z)*1.5f,
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x4D4F5554u);
const float mouthTerrainRelief=mouthSurfaceRelief;
const float mouthTreadFieldRelief=VF_FieldSurfaceRelief(static_cast<float>(X)*0.75f,
static_cast<float>(Y)*0.75f,static_cast<float>(Z)*0.75f,
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x54485244u);
if(passageProfile)passageProfile->passageReliefFieldCalls+=3;
const std::uint32_t passageReliefSeed=static_cast<std::uint32_t>(Owner?Owner->Seed:0);
float cachedWallRelief=0.0f,cachedMouthSurfaceRelief=0.0f,
cachedMouthTreadFieldRelief=0.0f;
bool hasCachedWallRelief=false,hasCachedMouthSurfaceRelief=false,
hasCachedMouthTreadFieldRelief=false;
const auto getWallRelief=[&]()
{
if(!hasCachedWallRelief)
{
cachedWallRelief=VF_FieldPassageWallRelief(static_cast<float>(X),
static_cast<float>(Y),static_cast<float>(Z),passageReliefSeed);
hasCachedWallRelief=true;
if(passageProfile)++passageProfile->passageReliefFieldCalls;
}
return cachedWallRelief;
};
const auto getMouthSurfaceRelief=[&]()
{
if(!hasCachedMouthSurfaceRelief)
{
cachedMouthSurfaceRelief=VF_FieldSurfaceRelief(
static_cast<float>(X)*1.5f,static_cast<float>(Y)*1.5f,
static_cast<float>(Z)*1.5f,passageReliefSeed^0x4D4F5554u);
hasCachedMouthSurfaceRelief=true;
if(passageProfile)++passageProfile->passageReliefFieldCalls;
}
return cachedMouthSurfaceRelief;
};
const auto getMouthTreadFieldRelief=[&]()
{
if(!hasCachedMouthTreadFieldRelief)
{
cachedMouthTreadFieldRelief=VF_FieldSurfaceRelief(
static_cast<float>(X)*0.75f,static_cast<float>(Y)*0.75f,
static_cast<float>(Z)*0.75f,passageReliefSeed^0x54485244u);
hasCachedMouthTreadFieldRelief=true;
if(passageProfile)++passageProfile->passageReliefFieldCalls;
}
return cachedMouthTreadFieldRelief;
};
const auto routeSegmentLengthMetres=[&](std::ptrdiff_t routeIndex)
{
const auto& before=passage.controlPoints[static_cast<std::size_t>(routeIndex)];
@@ -1639,21 +1691,33 @@ public:
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
const double floorReliefWeight=floorReliefT*floorReliefT
*(3.0-2.0*floorReliefT);
const double wallOpening=1.0-verticalWallAlignment;
const double wallReliefWeight=0.05+0.95*wallOpening;
const bool shortSpanCarve=IsPassageShortSpanSegment(passageIndex,
static_cast<std::size_t>(bestIndex));
float carveInputAfterBridge=composed;
if(shortSpanCarve)
carveInputAfterBridge=std::min(composed,static_cast<float>(
PassageBridgeSignedDistance(passageIndex,
static_cast<std::size_t>(bestIndex),X,Y,Z)/Q));
const double maximumWallReliefOffset=0.21*qPerMetre*wallReliefWeight;
const double maximumMouthFloorReliefOffset=upperMouthFloorFade
?0.20*qPerMetre*mouthFloorBlend*floorReliefWeight:0.0;
const double maximumCarvedDensity=-(bestSignedDistance
-maximumWallReliefOffset-maximumMouthFloorReliefOffset)/Q;
const bool wallReliefCanChangeCarve=!std::isfinite(maximumCarvedDensity)
||maximumCarvedDensity>static_cast<double>(carveInputAfterBridge);
const float relief=wallReliefCanChangeCarve?getWallRelief():0.0f;
const float mouthTerrainRelief=upperMouthFloorFade
?getMouthSurfaceRelief():0.0f;
const double floorReliefOffset=std::clamp(
static_cast<double>(mouthTerrainRelief),-1.0,1.0)
*0.20*qPerMetre*mouthFloorBlend*floorReliefWeight
*(upperMouthFloorFade?1.0:0.0);
const double wallOpening=1.0-verticalWallAlignment;
const double wallReliefWeight=0.05+0.95*wallOpening;
const double roughSignedDistance=bestSignedDistance
+static_cast<double>(std::clamp(relief,-1.0f,1.0f))*0.21*qPerMetre*wallReliefWeight
+floorReliefOffset;
if(IsPassageShortSpanSegment(passageIndex,static_cast<std::size_t>(bestIndex)))
{
const double bridgeDistance=PassageBridgeSignedDistance(passageIndex,
static_cast<std::size_t>(bestIndex),X,Y,Z);
composed=std::min(composed,static_cast<float>(bridgeDistance/Q));
}
if(shortSpanCarve)composed=carveInputAfterBridge;
// Leave native crater ground at the lip. The bore opens through the walls
// immediately, while its floor cut eases in along the passage centerline.
double mouthCarveFade=1.0;
@@ -1894,7 +1958,7 @@ public:
double supportHalfWidth=std::min(radius,
supportHalfWidthMetres*qPerMetre);
const double shoulderWarp=mouthTread
?std::clamp(static_cast<double>(mouthSurfaceRelief),-1.0,1.0)
?std::clamp(static_cast<double>(getMouthSurfaceRelief()),-1.0,1.0)
*0.12*qPerMetre:0.0;
supportHalfWidth=mouthTread
?std::clamp(supportHalfWidth+shoulderWarp,
@@ -1950,7 +2014,7 @@ public:
-0.80*qPerMetre,0.80*qPerMetre);
const double floorQ=baseFloorQ
+(mouthTread?std::clamp(nativeTreadOffset
+std::clamp(static_cast<double>(mouthTreadFieldRelief),-1.0,1.0)
+std::clamp(static_cast<double>(getMouthTreadFieldRelief()),-1.0,1.0)
*0.40*qPerMetre,-0.80*qPerMetre,0.0):0.0);
const double floorVoxels=floorQ/Q;
const bool signedDistanceSupport=sparseRouteSupport||mouthTread;
@@ -2073,7 +2137,7 @@ public:
if(nativeRestoreCapsuleClear)
{
const double nativeSurfaceDetail=std::clamp(
static_cast<double>(mouthTerrainRelief),-1.0,1.0)
static_cast<double>(getMouthSurfaceRelief()),-1.0,1.0)
*0.18*qPerMetre/Q;
const float nativeGroundWithRelief=static_cast<float>(
(supportNeedsDeferral?std::max(-1.0f,density):density)
@@ -4836,6 +4900,42 @@ private:
return nodeIndex;
}
std::vector<std::uint8_t> BuildPassageSegmentRangeNodeMask(
std::size_t passageIndex,std::ptrdiff_t first,std::ptrdiff_t end) const
{
std::vector<std::uint8_t> active;
if(first>=end||passageIndex>=PassageNearestNodes.size()
||PassageNearestNodes[passageIndex].empty())return active;
const auto& nodes=PassageNearestNodes[passageIndex];
active.assign(nodes.size(),0);
const auto visit=[&](auto&& self,int nodeIndex)->bool
{
if(nodeIndex<0)return false;
const std::size_t index=static_cast<std::size_t>(nodeIndex);
const auto& node=nodes[index];
if(static_cast<std::ptrdiff_t>(node.maximumSegment)<first
||static_cast<std::ptrdiff_t>(node.minimumSegment)>=end)return false;
bool hasCandidate=false;
if(node.left<0)
{
for(const std::size_t segment:node.segments)
hasCandidate=hasCandidate
||(static_cast<std::ptrdiff_t>(segment)>=first
&&static_cast<std::ptrdiff_t>(segment)<end);
}
else
{
const bool leftHasCandidate=self(self,node.left);
const bool rightHasCandidate=self(self,node.right);
hasCandidate=leftHasCandidate||rightHasCandidate;
}
active[index]=static_cast<std::uint8_t>(hasCandidate);
return hasCandidate;
};
visit(visit,0);
return active;
}
int BuildPassageProofNode(std::size_t first,std::size_t end)
{
FPassageProofNode node;node.first=first;node.end=end;
@@ -5410,35 +5510,53 @@ private:
template<typename FVisit>
void VisitNearestPassageSpatialNode(std::size_t passageIndex,int nodeIndex,
std::size_t first,std::size_t end,double qx,double qy,double qz,int priority,
double& bestDistance,FVisit& visit) const
const std::vector<std::uint8_t>* activeNodes,double& bestDistance,
FVisit& visit) const
{
if(passageIndex>=PassageNearestNodes.size()||nodeIndex<0)return;
const auto& nodes=PassageNearestNodes[passageIndex];
const auto& node=nodes[static_cast<std::size_t>(nodeIndex)];
if(node.maximumSegment<first||node.minimumSegment>=end)return;
const bool allSegmentsInRange=first<=node.minimumSegment
&&node.maximumSegment<end;
const auto candidate=allSegmentsInRange?node.segments.begin()
:std::lower_bound(node.segments.begin(),node.segments.end(),first);
if(candidate==node.segments.end()||*candidate>=end)return;
const std::size_t nodeOffset=static_cast<std::size_t>(nodeIndex);
if(activeNodes&&(nodeOffset>=activeNodes->size()||!(*activeNodes)[nodeOffset]))return;
const auto& node=nodes[nodeOffset];
if(!activeNodes&&(node.maximumSegment<first||node.minimumSegment>=end))return;
auto candidate=node.segments.begin();
if(!activeNodes)
{
const bool allSegmentsInRange=first<=node.minimumSegment
&&node.maximumSegment<end;
if(!allSegmentsInRange)
candidate=std::lower_bound(node.segments.begin(),node.segments.end(),first);
if(candidate==node.segments.end()||*candidate>=end)return;
}
const double lowerBound=PassageNearestNodeLowerBound(node,qx,qy,qz);
if(lowerBound>bestDistance)return;
if(node.left<0)
{
for(auto it=candidate;it!=node.segments.end()&&*it<end;++it)
for(auto it=candidate;it!=node.segments.end();++it)
{
if(*it<first||*it>=end)continue;
visit(*it,priority);
}
return;
}
const double leftBound=PassageNearestNodeLowerBound(
nodes[static_cast<std::size_t>(node.left)],qx,qy,qz);
const double rightBound=PassageNearestNodeLowerBound(
nodes[static_cast<std::size_t>(node.right)],qx,qy,qz);
const bool leftActive=!activeNodes
||(static_cast<std::size_t>(node.left)<activeNodes->size()
&&(*activeNodes)[static_cast<std::size_t>(node.left)]);
const bool rightActive=!activeNodes
||(static_cast<std::size_t>(node.right)<activeNodes->size()
&&(*activeNodes)[static_cast<std::size_t>(node.right)]);
const double leftBound=leftActive?PassageNearestNodeLowerBound(
nodes[static_cast<std::size_t>(node.left)],qx,qy,qz)
:std::numeric_limits<double>::infinity();
const double rightBound=rightActive?PassageNearestNodeLowerBound(
nodes[static_cast<std::size_t>(node.right)],qx,qy,qz)
:std::numeric_limits<double>::infinity();
const int nearChild=leftBound<=rightBound?node.left:node.right;
const int farChild=leftBound<=rightBound?node.right:node.left;
VisitNearestPassageSpatialNode(passageIndex,nearChild,first,end,qx,qy,qz,
priority,bestDistance,visit);
priority,activeNodes,bestDistance,visit);
VisitNearestPassageSpatialNode(passageIndex,farChild,first,end,qx,qy,qz,
priority,bestDistance,visit);
priority,activeNodes,bestDistance,visit);
}
template<typename FVisit>
@@ -5449,8 +5567,12 @@ private:
if(first>last||passageIndex>=PassageNearestNodes.size()
||PassageNearestNodes[passageIndex].empty())return;
auto callback=std::forward<FVisit>(visit);
const auto* tileQueries=ActivePassageTileQueries;
const auto* activeNodes=tileQueries&&tileQueries->matches(*this)
?tileQueries->segmentRangeNodeMask(passageIndex,first,last+1,priority):nullptr;
VisitNearestPassageSpatialNode(passageIndex,0,static_cast<std::size_t>(first),
static_cast<std::size_t>(last+1),qx,qy,qz,priority,bestDistance,callback);
static_cast<std::size_t>(last+1),qx,qy,qz,priority,activeNodes,
bestDistance,callback);
}
bool PassagePotentialWithinNode(std::size_t passageIndex,int nodeIndex,
@@ -12312,6 +12434,11 @@ private:
static_cast<unsigned long long>(Stats.WalkSamples));
return Stats.WalkFailures==0;
}
// An imported Unreal-resolved layout is the canonical route source. An empty
// passage list is meaningful for blocked controls, so never fall back to the
// regenerated legacy owner route in that case. Recipe overrides without an
// exported Core plan retain their generated owner route audit.
if(Owner&&Owner->bHasUnrealResolvedCorePlan&&ResolvedLayout)return true;
constexpr double SampleStep=0.5;
uint32 PassageIndex=0;
for(const FVoxelPassage& P:Owner->Manager->GetPassages())