perf(generation): exact reach gating for the tunnel core (per tile) and passage carving (per 8^3 block)
Applies ce4d878's decide-once-then-prove pattern to the two largest exact targets from the re-rank
(tunnel core 20.8%, passage carving 9.1%). Codex; reviewed by me.
Measured first, where the time is:
core world: far 223,860 vs near 35,515,979 cycles -> tile gate only; the core is
near-dominated (~99%)
core tail: far 363,440 vs near 20,110,219
passage, tile: far 7,315,426 vs near 30,168,796 -> refined to an 8^3 block gate
passage, 8^3: far 11,233,384 vs near 26,250,838
The core already uses the tunnel spatial index. An exact skip cannot remove its cost: that cost is
in tiles near tunnels. The remaining lever there is the field-changing SDF/core merge (next).
- Core reach per tile, from lattice plus halo: swept capsule reach, floor band, floor-profile
deviation, relief bound, room-mouth ownership. The GetDensityAt tail is identity unless
bSupportFloor, bRoomFloor or CoreSDF < -inset.
- Passage carving per 8^3 block: capsule-chain and landing-room domains, the carve threshold and
the SmoothMin K/6 margin. Malformed descriptors stay candidates (conservative).
- voxel.TileReachCostDiagnostics (default 0) for the far/near cost split.
Soundness: the final-field debug comparison ran 130,285,889 comparisons with 0 differences; shrunk
reach (0.5) produced 140,035 differences (60,098 in the final field) and failed as required.
Field exact: canonical 07C14005 / b3e5f4c3..9b377, 64/64 per-tile ledger identical, capability
20,830 / 10,909, strate-crossing and sealed-proof tests pass.
Final DEFAULT build vs the committed-tip DLL (same command line, two interleaved runs each):
static worker 28.84 -> 28.10 s (-2.6%) LOD0 p50 53.3 -> 51.5 ms p95 94.4 -> 93.1 ms
moving worker 61.39 -> 60.61 s (-1.3%) LOD0 p50 50.9 -> 49.7 ms p95 92.21 -> 92.27 ms (flat,
+0.06%, within noise)
Maintenance note: these reach proofs must track tunnel/passage geometry. The next round adds an
automation test for the final-field comparison so a geometry change cannot silently break them.
Ledger: 15 builds (one C2065 fixed, one access-denied path retry); rejected TileOnly/BlockLookup
variants were slower; one hung diagnostic (a non-owner PID) was stopped; wrapper quoting failures
launched no editor. No crash folders.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
1 parent
0208e93606
commit
a668833ef5
8 files changed
+1062
-30
No files matched your search
@@ -7914,10 +7914,20 @@ FTunnelCoreWorldEvaluation VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
const FTunnelSupportFloorColumn* SupportColumn,
|
||||
bool bUseSpatialIndex)
|
||||
{
|
||||
VoxelGenLOD::FScopedReachCost ReachCost(
|
||||
VoxelGenLOD::ETileReachCostKind::TunnelCoreWorld);
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
return FTunnelCoreWorldEvaluation();
|
||||
}
|
||||
// GenerateMesh installs the exact tile/block reach mask after building the complete tile
|
||||
// cache. Point queries retain the canonical all-reachable TLS default; debug proof calls set
|
||||
// the bypass bit so the same sample can be evaluated as the reference field.
|
||||
if (!VoxelGenLOD::IsTilePostReachBypassActive()
|
||||
&& !VoxelGenLOD::IsTunnelCoreReachable())
|
||||
{
|
||||
return FTunnelCoreWorldEvaluation();
|
||||
}
|
||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||
VoxelDensityProfile::EBucket::TunnelCoreWorld);
|
||||
const FVector Pos(WorldX, WorldY, WorldZ);
|
||||
@@ -8042,6 +8052,318 @@ FTunnelCoreWorldEvaluation VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool VoxelCaveMorphology::AnyTunnelCoreWorldNearLattice(
|
||||
const FChunkSDFCache& Cache,
|
||||
const FBox& VoxelBox,
|
||||
float ReachScale)
|
||||
{
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!VoxelBox.IsValid
|
||||
|| !VoxelMath::IsFinite(ReachScale) || ReachScale <= 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto TouchesSphere = [&VoxelBox](const FVector& Center, float Radius) -> bool
|
||||
{
|
||||
if (!VoxelMath::IsFinite(Center.X)
|
||||
|| !VoxelMath::IsFinite(Center.Y)
|
||||
|| !VoxelMath::IsFinite(Center.Z)
|
||||
|| !VoxelMath::IsFinite(Radius) || Radius < 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const FVector Closest(
|
||||
FMath::Clamp(Center.X, (float)VoxelBox.Min.X, (float)VoxelBox.Max.X),
|
||||
FMath::Clamp(Center.Y, (float)VoxelBox.Min.Y, (float)VoxelBox.Max.Y),
|
||||
FMath::Clamp(Center.Z, (float)VoxelBox.Min.Z, (float)VoxelBox.Max.Z));
|
||||
return FVector::DistSquared(Closest, Center) <= Radius * Radius;
|
||||
};
|
||||
|
||||
const auto TouchesExpandedAabb = [&VoxelBox](
|
||||
const FVector& Min, const FVector& Max, float Pad) -> bool
|
||||
{
|
||||
if (!VoxelMath::IsFinite(Min.X) || !VoxelMath::IsFinite(Min.Y)
|
||||
|| !VoxelMath::IsFinite(Min.Z) || !VoxelMath::IsFinite(Max.X)
|
||||
|| !VoxelMath::IsFinite(Max.Y) || !VoxelMath::IsFinite(Max.Z)
|
||||
|| !VoxelMath::IsFinite(Pad) || Pad < 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const float DX = FMath::Max3(
|
||||
static_cast<float>(VoxelBox.Min.X) - static_cast<float>(Max.X),
|
||||
static_cast<float>(Min.X) - static_cast<float>(VoxelBox.Max.X), 0.0f);
|
||||
const float DY = FMath::Max3(
|
||||
static_cast<float>(VoxelBox.Min.Y) - static_cast<float>(Max.Y),
|
||||
static_cast<float>(Min.Y) - static_cast<float>(VoxelBox.Max.Y), 0.0f);
|
||||
const float DZ = FMath::Max3(
|
||||
static_cast<float>(VoxelBox.Min.Z) - static_cast<float>(Max.Z),
|
||||
static_cast<float>(Min.Z) - static_cast<float>(VoxelBox.Max.Z), 0.0f);
|
||||
return DX <= Pad && DY <= Pad && DZ <= Pad;
|
||||
};
|
||||
|
||||
const float Fade = FMath::Max(Cache.SDFBlendRadius, 0.0f) * 0.35f;
|
||||
if (!VoxelMath::IsFinite(Fade))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const FCachedTunnel& Tunnel : Cache.Tunnels)
|
||||
{
|
||||
const bool bHasWorldChain = Tunnel.WorldControlPoints.Num() >= 2
|
||||
&& Tunnel.WorldControlRadii.Num() == Tunnel.WorldControlPoints.Num();
|
||||
const FVector& BoundCenter = bHasWorldChain
|
||||
? Tunnel.WorldBoundCenter : Tunnel.BoundCenter;
|
||||
const float BoundRadiusSq = bHasWorldChain
|
||||
? Tunnel.WorldBoundRadiusSq : Tunnel.BoundRadiusSq;
|
||||
const float InfluenceRadius = bHasWorldChain
|
||||
? Tunnel.WorldInfluenceRadius : Tunnel.SDFInfluenceRadius;
|
||||
const FVector& CenterlineMin = bHasWorldChain
|
||||
? Tunnel.WorldCenterlineMin : Tunnel.SDFCenterlineMin;
|
||||
const FVector& CenterlineMax = bHasWorldChain
|
||||
? Tunnel.WorldCenterlineMax : Tunnel.SDFCenterlineMax;
|
||||
|
||||
if (!VoxelMath::IsFinite(BoundCenter.X)
|
||||
|| !VoxelMath::IsFinite(BoundCenter.Y)
|
||||
|| !VoxelMath::IsFinite(BoundCenter.Z)
|
||||
|| !VoxelMath::IsFinite(BoundRadiusSq) || BoundRadiusSq < 0.0f
|
||||
|| !VoxelMath::IsFinite(InfluenceRadius) || InfluenceRadius < 0.0f
|
||||
|| !VoxelMath::IsFinite(CenterlineMin.X)
|
||||
|| !VoxelMath::IsFinite(CenterlineMin.Y)
|
||||
|| !VoxelMath::IsFinite(CenterlineMin.Z)
|
||||
|| !VoxelMath::IsFinite(CenterlineMax.X)
|
||||
|| !VoxelMath::IsFinite(CenterlineMax.Y)
|
||||
|| !VoxelMath::IsFinite(CenterlineMax.Z))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (bHasWorldChain)
|
||||
{
|
||||
for (int32 Index = 0; Index < Tunnel.WorldControlPoints.Num(); ++Index)
|
||||
{
|
||||
const FVector& Point = Tunnel.WorldControlPoints[Index];
|
||||
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|
||||
|| !VoxelMath::IsFinite(Point.Z)
|
||||
|| !VoxelMath::IsFinite(Tunnel.WorldControlRadii[Index]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VF_TunnelFloorRelief uses the same bounded noise as the floor profile. Use the
|
||||
// profile-independent maximum scale (1.0) here: the normal authored scale is <= .20,
|
||||
// but this remains sound for an old or malformed profile that bypassed that clamp.
|
||||
float ReliefBound = 0.0f;
|
||||
if (Tunnel.FloorReliefStrength > 0.0f)
|
||||
{
|
||||
if (!VoxelMath::IsFinite(Tunnel.FloorReliefStrength)
|
||||
|| !VoxelMath::IsFinite(Tunnel.FloorReliefFrequency))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ReliefBound = FMath::Abs(Tunnel.FloorReliefStrength)
|
||||
* VOXEL_NOISE_SCALE * 1.01f;
|
||||
if (!VoxelMath::IsFinite(ReliefBound))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float MouthReach = 0.0f;
|
||||
float MouthFloorDelta = 0.0f;
|
||||
if (bHasWorldChain && Tunnel.bHasFloorRoomOwnership)
|
||||
{
|
||||
MouthReach = FMath::Max(
|
||||
FMath::Max(Tunnel.WorldMouthBlendRadiusA, Tunnel.WorldMouthBlendRadiusB),
|
||||
0.0f) + Fade + 1.0f;
|
||||
if (!VoxelMath::IsFinite(MouthReach))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const float NaturalA = static_cast<float>(Tunnel.WorldControlPoints[0].Z)
|
||||
- FMath::Abs(Tunnel.WorldControlRadii[0]);
|
||||
const int32 Last = Tunnel.WorldControlPoints.Num() - 1;
|
||||
const float NaturalB = static_cast<float>(Tunnel.WorldControlPoints[Last].Z)
|
||||
- FMath::Abs(Tunnel.WorldControlRadii[Last]);
|
||||
if (!VoxelMath::IsFinite(NaturalA) || !VoxelMath::IsFinite(NaturalB))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Tunnel.WorldMouthFloorZA > -FLT_MAX
|
||||
&& !VoxelMath::IsFinite(Tunnel.WorldMouthFloorZA))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Tunnel.WorldMouthFloorZB > -FLT_MAX
|
||||
&& !VoxelMath::IsFinite(Tunnel.WorldMouthFloorZB))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Tunnel.WorldMouthFloorZA > -FLT_MAX)
|
||||
{
|
||||
MouthFloorDelta = FMath::Max(
|
||||
MouthFloorDelta, FMath::Abs(Tunnel.WorldMouthFloorZA - NaturalA));
|
||||
}
|
||||
if (Tunnel.WorldMouthFloorZB > -FLT_MAX)
|
||||
{
|
||||
MouthFloorDelta = FMath::Max(
|
||||
MouthFloorDelta, FMath::Abs(Tunnel.WorldMouthFloorZB - NaturalB));
|
||||
}
|
||||
}
|
||||
|
||||
// Tighten the construction sphere to the actual swept chain before falling back to the
|
||||
// legacy bound. The evaluator tests a capsule segment, not the sphere around the whole
|
||||
// wandering chain; using segment AABBs removes the long-chain false near result while
|
||||
// retaining a conservative pad for radius, floor band, relief, and SmoothMax blend.
|
||||
const TArray<FVector>& ChainPoints = bHasWorldChain
|
||||
? Tunnel.WorldControlPoints : Tunnel.ControlPoints;
|
||||
const TArray<float>& ChainRadii = bHasWorldChain
|
||||
? Tunnel.WorldControlRadii : Tunnel.ControlRadii;
|
||||
bool bHasTightChain = ChainPoints.Num() >= 2
|
||||
&& ChainRadii.Num() == ChainPoints.Num();
|
||||
bool bTightTouch = false;
|
||||
if (bHasTightChain)
|
||||
{
|
||||
float MaxRadius = 0.0f;
|
||||
for (int32 Index = 0; Index < ChainPoints.Num(); ++Index)
|
||||
{
|
||||
const FVector& Point = ChainPoints[Index];
|
||||
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|
||||
|| !VoxelMath::IsFinite(Point.Z)
|
||||
|| !VoxelMath::IsFinite(ChainRadii[Index]))
|
||||
{
|
||||
bHasTightChain = false;
|
||||
break;
|
||||
}
|
||||
MaxRadius = FMath::Max(MaxRadius, FMath::Abs(ChainRadii[Index]));
|
||||
}
|
||||
if (bHasTightChain)
|
||||
{
|
||||
float ProfileFloorDelta = 0.0f;
|
||||
const TArray<FTunnelFloorSegmentProfile>& Profiles = bHasWorldChain
|
||||
? Tunnel.WorldFloorProfiles : Tunnel.FloorProfiles;
|
||||
if (Tunnel.bTunnelFloorEnabled
|
||||
&& Profiles.Num() == ChainPoints.Num() - 1)
|
||||
{
|
||||
for (int32 SegmentIndex = 0;
|
||||
SegmentIndex < Profiles.Num(); ++SegmentIndex)
|
||||
{
|
||||
const FTunnelFloorSegmentProfile& Profile = Profiles[SegmentIndex];
|
||||
if (!VoxelMath::IsFinite(Profile.StartFloorZ)
|
||||
|| !VoxelMath::IsFinite(Profile.EndFloorZ))
|
||||
{
|
||||
bHasTightChain = false;
|
||||
break;
|
||||
}
|
||||
const float NaturalA = static_cast<float>(
|
||||
ChainPoints[SegmentIndex].Z)
|
||||
- FMath::Abs(ChainRadii[SegmentIndex]);
|
||||
const float NaturalB = static_cast<float>(
|
||||
ChainPoints[SegmentIndex + 1].Z)
|
||||
- FMath::Abs(ChainRadii[SegmentIndex + 1]);
|
||||
ProfileFloorDelta = FMath::Max(
|
||||
ProfileFloorDelta,
|
||||
FMath::Max(
|
||||
FMath::Abs(Profile.StartFloorZ - NaturalA),
|
||||
FMath::Abs(Profile.EndFloorZ - NaturalB)));
|
||||
}
|
||||
}
|
||||
if (bHasTightChain)
|
||||
{
|
||||
const float FloorPad = Tunnel.bTunnelFloorEnabled
|
||||
? FMath::Max(
|
||||
VoxelPassageGeometry::LandingFloorThicknessVoxels,
|
||||
FMath::Max(Cache.SDFBlendRadius, 0.0f) * 0.35f)
|
||||
: 0.0f;
|
||||
const float SegmentPad = MaxRadius + FloorPad
|
||||
+ ProfileFloorDelta + ReliefBound;
|
||||
if (!VoxelMath::IsFinite(SegmentPad))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for (int32 SegmentIndex = 0;
|
||||
SegmentIndex + 1 < ChainPoints.Num(); ++SegmentIndex)
|
||||
{
|
||||
const FVector Min(
|
||||
FMath::Min(ChainPoints[SegmentIndex].X,
|
||||
ChainPoints[SegmentIndex + 1].X),
|
||||
FMath::Min(ChainPoints[SegmentIndex].Y,
|
||||
ChainPoints[SegmentIndex + 1].Y),
|
||||
FMath::Min(ChainPoints[SegmentIndex].Z,
|
||||
ChainPoints[SegmentIndex + 1].Z));
|
||||
const FVector Max(
|
||||
FMath::Max(ChainPoints[SegmentIndex].X,
|
||||
ChainPoints[SegmentIndex + 1].X),
|
||||
FMath::Max(ChainPoints[SegmentIndex].Y,
|
||||
ChainPoints[SegmentIndex + 1].Y),
|
||||
FMath::Max(ChainPoints[SegmentIndex].Z,
|
||||
ChainPoints[SegmentIndex + 1].Z));
|
||||
if (TouchesExpandedAabb(Min, Max, SegmentPad * ReachScale))
|
||||
{
|
||||
bTightTouch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bTightTouch && Tunnel.bTunnelFloorEnabled
|
||||
&& bHasWorldChain && Tunnel.bHasFloorRoomOwnership)
|
||||
{
|
||||
const float MouthHorizontal = MouthReach;
|
||||
const float MouthVertical = FMath::Max(
|
||||
MaxRadius + VoxelPassageGeometry::LandingFloorThicknessVoxels
|
||||
+ ReliefBound,
|
||||
MouthFloorDelta + VoxelPassageGeometry::LandingFloorThicknessVoxels
|
||||
+ ReliefBound);
|
||||
const float ScaledHorizontal = MouthHorizontal * ReachScale;
|
||||
const float ScaledVertical = MouthVertical * ReachScale;
|
||||
for (int32 Endpoint : {0, ChainPoints.Num() - 1})
|
||||
{
|
||||
const FVector& Point = ChainPoints[Endpoint];
|
||||
if (TouchesExpandedAabb(
|
||||
FVector(
|
||||
static_cast<float>(Point.X) - ScaledHorizontal,
|
||||
static_cast<float>(Point.Y) - ScaledHorizontal,
|
||||
static_cast<float>(Point.Z) - ScaledVertical),
|
||||
FVector(
|
||||
static_cast<float>(Point.X) + ScaledHorizontal,
|
||||
static_cast<float>(Point.Y) + ScaledHorizontal,
|
||||
static_cast<float>(Point.Z) + ScaledVertical),
|
||||
0.0f))
|
||||
{
|
||||
bTightTouch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bHasTightChain && !bTightTouch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// The broad sphere already encloses the swept radius and finite floor band. Add the
|
||||
// vertical relief and room-mouth ownership envelopes before asking whether the lattice
|
||||
// box can touch it. A miss is therefore an identity proof for the core evaluator and
|
||||
// its support/room-floor tail; its only field writes are bSupportFloor, bRoomFloor, or
|
||||
// CoreSDF < -inset, all of which are inside this envelope.
|
||||
const float Reach = (
|
||||
FMath::Sqrt(FMath::Max(BoundRadiusSq, 0.0f))
|
||||
+ ReliefBound + MouthReach + MouthFloorDelta) * ReachScale;
|
||||
if (!VoxelMath::IsFinite(Reach)
|
||||
|| TouchesSphere(BoundCenter, Reach))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float VoxelCaveMorphology::EvaluateTunnelCoreWorldSDF(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
|
||||
Reference in new issue
Block a user