perf(gen): interval propagation -- blocks can finally be PROVEN empty. 1.55s -> 1.21s

Task 4 ran 11 hours and was killed by system memory pressure before it could file a
report. The work survived, builds clean (0 errors), and is verified faster with
byte-identical output. This commit is my verification, not its summary -- it never
got to write one.

THE STRUCTURAL FIX
0e9df9e established why no block could ever be skipped: OriginSpineOp,
PassageCarveOp and the active seals Lerp/Min/Max against the CURRENT density, so
with an unknown incoming density their supremum is genuinely unbounded. Not a
missing bound -- the operator semantics.

The answer is to propagate a density INTERVAL through the stack, and that is what
landed: FVoxelBoxSdfInterval + PropagateSdfOverBox on the operator interface, an
interval fold through every converter and modifier, interval arithmetic down into
the noise primitives themselves (gradient corners, warp, worm frequencies), and a
BlockSkip lattice the mesher consults per 8^3 block.

Its own guiding comment, which is the right default:
  "no finite interval is a proof. Unknown costs the skip and protects the geometry."

  128^3 TunnelNetwork seed 1337 slot 1, freshly built binary, 3 runs each:
    before  1.515 / 1.554 / 1.569 s
    after   1.213 / 1.258 / 1.171 s     -22.5%, 1.28x -- clears the 17% floor

  Geometry SHA-256 98eaad61..d3c4f IDENTICAL to 0e9df9e. 153,740 triangles either
  way. It skips only provably-empty work; nothing about the world changed.

It also fixed one cause of the 5.6 s empty tiles found in 0e9df9e: an LOD4 tile
legitimately spans 19^3 = 6,859 chunk keys and was rebuilding per-chunk state
thousands of times within a single tile. A shared cache removed that failure mode;
remaining slow empties were LOD0 and are a separate fast-classifier bail, still open.

Partially landed, unfinished when killed: RequestStartCycles on FChunkResult, to
report request-to-ready latency rather than worker generation time. Harmless as is.

⚠️ WHAT KILLED IT, AND IT IS OURS
A single UnrealEditor-Cmd commandlet grew to 19.5 GB, leaving 1.3 GB free on a
32 GB machine, and the OS killed the agent. Freeing it restored 21.6 GB. The owner
said twice that his machine should not be under memory pressure and he was right
both times: first the 411 MiB worker caches, now a 19.5 GB commandlet. A generation
run must not need 19.5 GB. Next task.

Cumulative on this region: 342.2 -> 16.2 -> 2.62 -> 1.49 -> 1.21 s  (~283x).
3,374 insertions / 342 deletions across 12 files. Build 0 errors. Nothing outside
Plugins/VoxelForge; RealtimeMeshComponent untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb
This commit is contained in:
Fr0zkaandClaude Opus 5 committed 2026-09-09 21:11:13 +02:00
1 parent 0e9df9e5a7
commit d38d4cabef
12 files changed
+3375 -343

No files matched your search

@@ -2157,6 +2157,444 @@ bool UVoxelStrateManager::AnyPassageLandingFloorNearBox(
return false;
}
namespace
{
static bool VF_LatticeAxisRange(
float Min, float Max, float Origin, int32 Step,
int32& OutFirst, int32& OutLast)
{
if (Step <= 0 || !FMath::IsFinite(Min) || !FMath::IsFinite(Max)
|| !FMath::IsFinite(Origin) || Min > Max)
{
return false;
}
const float InvStep = 1.0f / static_cast<float>(Step);
OutFirst = FMath::CeilToInt((Min - Origin) * InvStep - 1.0e-4f);
OutLast = FMath::FloorToInt((Max - Origin) * InvStep + 1.0e-4f);
return OutFirst <= OutLast;
}
static bool VF_LatticeAxisNearestDistance(
float Min, float Max, float Origin, int32 Step, float Target, float& OutDistance)
{
int32 First = 0, Last = -1;
if (!VF_LatticeAxisRange(Min, Max, Origin, Step, First, Last))
{
return false;
}
const int32 Nearest = FMath::Clamp(
FMath::RoundToInt((Target - Origin) / static_cast<float>(Step)), First, Last);
OutDistance = FMath::Abs(
Origin + static_cast<float>(Nearest * Step) - Target);
return true;
}
static bool VF_LatticeBoxTouchesSphere(
const FBox& Box, const FIntVector& Origin, int32 Step,
const FVector& Center, float Radius)
{
float DX = 0.0f, DY = 0.0f, DZ = 0.0f;
if (!VF_LatticeAxisNearestDistance(
(float)Box.Min.X, (float)Box.Max.X, (float)Origin.X,
Step, (float)Center.X, DX)
|| !VF_LatticeAxisNearestDistance(
(float)Box.Min.Y, (float)Box.Max.Y, (float)Origin.Y,
Step, (float)Center.Y, DY)
|| !VF_LatticeAxisNearestDistance(
(float)Box.Min.Z, (float)Box.Max.Z, (float)Origin.Z,
Step, (float)Center.Z, DZ))
{
return false;
}
return DX * DX + DY * DY + DZ * DZ <= FMath::Square(Radius);
}
static bool VF_AnyPassageBoundTouchesLattice(
const TArray<FVoxelPassage>& Passages,
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step)
{
if (Step <= 0 || !VoxelBox.IsValid)
{
// An invalid query must never manufacture an identity proof.
return true;
}
for (const FVoxelPassage& Passage : Passages)
{
const float Reach = Passage.BoundRadius + 4.0f;
if (!FMath::IsFinite(Reach) || Reach < 0.0f)
{
// Invalid generated geometry is an unknown, not an empty passage set.
return true;
}
if (VF_LatticeBoxTouchesSphere(
VoxelBox, LatticeOrigin, Step, Passage.BoundCenter, Reach))
{
return true;
}
}
return false;
}
// MaxPassageCarveFactorNearLattice is queried once for the root and once for every refined
// child. The child lattice is a strict subset of the root lattice, so retaining the exact
// carve factor at each root point is a sound memo: a child reads the same values the old
// implementation would have recomputed, in the same deterministic order. The cache is
// worker-local because classifier calls can run concurrently and no mutable state may be
// published through the immutable strate manager.
struct FPassageLatticeBoundCache
{
const UVoxelStrateManager* Owner = nullptr;
uint64 OwnerLifetimeId = 0;
uint32 Version = 0xFFFFFFFFu;
FIntVector Origin = FIntVector::ZeroValue;
int32 Step = 0;
int32 FirstX = 0, LastX = -1;
int32 FirstY = 0, LastY = -1;
int32 FirstZ = 0, LastZ = -1;
bool bValid = false;
bool bNoCandidate = false;
TArray<float> Factors;
void Reset()
{
Owner = nullptr;
OwnerLifetimeId = 0;
Version = 0xFFFFFFFFu;
Origin = FIntVector::ZeroValue;
Step = 0;
FirstX = 0; LastX = -1;
FirstY = 0; LastY = -1;
FirstZ = 0; LastZ = -1;
bValid = false;
bNoCandidate = false;
Factors.Reset();
}
void Begin(const UVoxelStrateManager* InOwner, uint64 InLifetimeId,
uint32 InVersion, const FIntVector& InOrigin, int32 InStep,
int32 InFirstX, int32 InLastX,
int32 InFirstY, int32 InLastY,
int32 InFirstZ, int32 InLastZ,
bool bInNoCandidate)
{
Owner = InOwner;
OwnerLifetimeId = InLifetimeId;
Version = InVersion;
Origin = InOrigin;
Step = InStep;
FirstX = InFirstX; LastX = InLastX;
FirstY = InFirstY; LastY = InLastY;
FirstZ = InFirstZ; LastZ = InLastZ;
bValid = true;
bNoCandidate = bInNoCandidate;
Factors.Reset();
}
bool Contains(const UVoxelStrateManager* InOwner, uint64 InLifetimeId,
uint32 InVersion, const FIntVector& InOrigin, int32 InStep,
int32 InFirstX, int32 InLastX,
int32 InFirstY, int32 InLastY,
int32 InFirstZ, int32 InLastZ) const
{
return bValid && Owner == InOwner && OwnerLifetimeId == InLifetimeId
&& Version == InVersion && Origin == InOrigin && Step == InStep
&& InFirstX >= FirstX && InLastX <= LastX
&& InFirstY >= FirstY && InLastY <= LastY
&& InFirstZ >= FirstZ && InLastZ <= LastZ;
}
int32 Index(int32 IX, int32 IY, int32 IZ) const
{
const int32 DimX = LastX - FirstX + 1;
const int32 DimY = LastY - FirstY + 1;
return ((IZ - FirstZ) * DimY + (IY - FirstY)) * DimX + (IX - FirstX);
}
float MaxIn(const int32 InFirstX, const int32 InLastX,
const int32 InFirstY, const int32 InLastY,
const int32 InFirstZ, const int32 InLastZ) const
{
if (bNoCandidate) { return 0.0f; }
float Result = 0.0f;
for (int32 IZ = InFirstZ; IZ <= InLastZ; ++IZ)
{
for (int32 IY = InFirstY; IY <= InLastY; ++IY)
{
for (int32 IX = InFirstX; IX <= InLastX; ++IX)
{
Result = FMath::Max(Result, Factors[Index(IX, IY, IZ)]);
if (Result >= 1.0f)
{
return Result;
}
}
}
}
return Result;
}
};
FPassageLatticeBoundCache& VF_GetPassageLatticeBoundCache()
{
thread_local FPassageLatticeBoundCache Cache;
return Cache;
}
static bool VF_LatticeBoxTouchesAABB(
const FBox& Box, const FIntVector& Origin, int32 Step,
float MinX, float MaxX, float MinY, float MaxY, float MinZ, float MaxZ)
{
return VoxelPassageGeometry::LatticeAxisHasSampleInInterval(
FMath::Max((float)Box.Min.X, MinX),
FMath::Min((float)Box.Max.X, MaxX),
(float)Origin.X, Step)
&& VoxelPassageGeometry::LatticeAxisHasSampleInInterval(
FMath::Max((float)Box.Min.Y, MinY),
FMath::Min((float)Box.Max.Y, MaxY),
(float)Origin.Y, Step)
&& VoxelPassageGeometry::LatticeAxisHasSampleInInterval(
FMath::Max((float)Box.Min.Z, MinZ),
FMath::Min((float)Box.Max.Z, MaxZ),
(float)Origin.Z, Step);
}
}
bool UVoxelStrateManager::AnyPassageNearLattice(
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step) const
{
// This is deliberately only the conservative spatial candidate test. The old implementation
// evaluated the complete modifier SDF here and then evaluated it a second time in
// MaxPassageCarveFactorNearLattice during the same fold. A bound hit is sufficient to keep
// the carve hypothesis alive; MaxPassageCarveFactorNearLattice supplies the exact lattice
// amplitude before the fold can preserve AllSolid.
return VF_AnyPassageBoundTouchesLattice(
Passages, VoxelBox, LatticeOrigin, Step);
}
float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step) const
{
// The passage bound is only a cheap candidate test. It encloses an entire multi-segment
// passage, so using it as the final lattice proof turns a long tunnel into a false positive
// for every tile inside its enclosing sphere. That is particularly damaging at LOD0: the
// classifier then falls through to a full density grid even when every sampled point is rock.
//
// Once a bound reaches this lattice, ask the same exact modifier SDF used by
// ApplyPassageCarvingOnly at the actual MC samples. This is still a proof, not a sampling
// shortcut: the operator is evaluated at precisely the points the mesher will evaluate, and
// a non-finite result remains conservative. The common no-candidate path stays O(P), while a
// false-positive bound pays one exact lattice walk and can then be classified as Identity.
if (Step <= 0 || !VoxelBox.IsValid)
{
return 1.0f;
}
int32 FirstX = 0, LastX = -1;
int32 FirstY = 0, LastY = -1;
int32 FirstZ = 0, LastZ = -1;
if (!VF_LatticeAxisRange(
VoxelBox.Min.X, VoxelBox.Max.X, (float)LatticeOrigin.X, Step, FirstX, LastX)
|| !VF_LatticeAxisRange(
VoxelBox.Min.Y, VoxelBox.Max.Y, (float)LatticeOrigin.Y, Step, FirstY, LastY)
|| !VF_LatticeAxisRange(
VoxelBox.Min.Z, VoxelBox.Max.Z, (float)LatticeOrigin.Z, Step, FirstZ, LastZ))
{
return 1.0f;
}
FPassageLatticeBoundCache& Cache = VF_GetPassageLatticeBoundCache();
const uint64 LifetimeId = GetCacheLifetimeId();
const uint32 Version = GetLayoutVersion();
if (Cache.Contains(
this, LifetimeId, Version, LatticeOrigin, Step,
FirstX, LastX, FirstY, LastY, FirstZ, LastZ))
{
return Cache.MaxIn(FirstX, LastX, FirstY, LastY, FirstZ, LastZ);
}
if (!VF_AnyPassageBoundTouchesLattice(
Passages, VoxelBox, LatticeOrigin, Step))
{
Cache.Begin(
this, LifetimeId, Version, LatticeOrigin, Step,
FirstX, LastX, FirstY, LastY, FirstZ, LastZ,
/*bInNoCandidate*/ true);
return 0.0f;
}
constexpr float PassageCarveThreshold = 4.0f;
auto CarveFactorFromSDF = [](float ModifierSDF)
{
if (!(ModifierSDF < PassageCarveThreshold))
{
return 0.0f;
}
float CarveFactor = FMath::Clamp(
(PassageCarveThreshold - ModifierSDF)
/ (PassageCarveThreshold * 2.0f),
0.0f, 1.0f);
return SmoothStep01(CarveFactor);
};
const int64 DimX = static_cast<int64>(LastX) - FirstX + 1;
const int64 DimY = static_cast<int64>(LastY) - FirstY + 1;
const int64 DimZ = static_cast<int64>(LastZ) - FirstZ + 1;
const int64 SampleCount = DimX * DimY * DimZ;
constexpr int64 MaxCachedLatticeSamples = 65536;
if (SampleCount > 0 && SampleCount <= MaxCachedLatticeSamples)
{
Cache.Begin(
this, LifetimeId, Version, LatticeOrigin, Step,
FirstX, LastX, FirstY, LastY, FirstZ, LastZ,
/*bInNoCandidate*/ false);
Cache.Factors.SetNumUninitialized(static_cast<int32>(SampleCount));
float MaxCarveFactor = 0.0f;
for (int32 IZ = FirstZ; IZ <= LastZ; ++IZ)
{
const float Z = (float)LatticeOrigin.Z + (float)(IZ * Step);
for (int32 IY = FirstY; IY <= LastY; ++IY)
{
const float Y = (float)LatticeOrigin.Y + (float)(IY * Step);
for (int32 IX = FirstX; IX <= LastX; ++IX)
{
const float X = (float)LatticeOrigin.X + (float)(IX * Step);
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
const float CarveFactor = FMath::IsFinite(ModifierSDF)
? CarveFactorFromSDF(ModifierSDF) : 1.0f;
Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor;
MaxCarveFactor = FMath::Max(MaxCarveFactor, CarveFactor);
if (MaxCarveFactor >= 1.0f)
{
// The remaining values are still filled below. Descendant queries need
// the complete exact lattice, not merely this query's maximum.
for (int32 RemainingZ = IZ; RemainingZ <= LastZ; ++RemainingZ)
{
const float RemainingWorldZ =
(float)LatticeOrigin.Z + (float)(RemainingZ * Step);
const int32 StartY = RemainingZ == IZ ? IY : FirstY;
for (int32 RemainingY = StartY; RemainingY <= LastY; ++RemainingY)
{
const float RemainingWorldY =
(float)LatticeOrigin.Y + (float)(RemainingY * Step);
const int32 StartX =
(RemainingZ == IZ && RemainingY == IY) ? IX + 1 : FirstX;
for (int32 RemainingX = StartX; RemainingX <= LastX; ++RemainingX)
{
const float RemainingWorldX =
(float)LatticeOrigin.X + (float)(RemainingX * Step);
const float RemainingSDF = EvaluateModifierSDF(
RemainingWorldX, RemainingWorldY, RemainingWorldZ);
Cache.Factors[Cache.Index(RemainingX, RemainingY, RemainingZ)] =
FMath::IsFinite(RemainingSDF)
? CarveFactorFromSDF(RemainingSDF) : 1.0f;
}
}
}
return MaxCarveFactor;
}
}
}
}
return MaxCarveFactor;
}
// Very large or unusual external queries do not enter the bounded worker memo. Keep the
// original exact walk for them; refusing the cache must never change the proof.
Cache.Reset();
float MaxCarveFactor = 0.0f;
for (int32 IZ = FirstZ; IZ <= LastZ; ++IZ)
{
const float Z = (float)LatticeOrigin.Z + (float)(IZ * Step);
for (int32 IY = FirstY; IY <= LastY; ++IY)
{
const float Y = (float)LatticeOrigin.Y + (float)(IY * Step);
for (int32 IX = FirstX; IX <= LastX; ++IX)
{
const float X = (float)LatticeOrigin.X + (float)(IX * Step);
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
if (!FMath::IsFinite(ModifierSDF))
{
return 1.0f;
}
MaxCarveFactor = FMath::Max(
MaxCarveFactor, CarveFactorFromSDF(ModifierSDF));
if (MaxCarveFactor >= 1.0f)
{
return MaxCarveFactor;
}
}
}
}
return MaxCarveFactor;
}
bool UVoxelStrateManager::AnyPassageLandingFloorNearLattice(
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step) const
{
for (const FVoxelPassage& Passage : Passages)
{
const FVoxelPassageLanding* Landings[] = {
&Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings)
{
if (Landing->HalfWidth <= 0.0f || Landing->FloorThickness <= 0.0f)
{
continue;
}
constexpr float Pad = 1.0f;
if (VF_LatticeBoxTouchesAABB(
VoxelBox, LatticeOrigin, Step,
Landing->StandingPoint.X - Landing->HalfWidth - Pad,
Landing->StandingPoint.X + Landing->HalfWidth + Pad,
Landing->StandingPoint.Y - Landing->HalfWidth - Pad,
Landing->StandingPoint.Y + Landing->HalfWidth + Pad,
Landing->FloorZ - Landing->FloorThickness - Pad,
Landing->FloorZ + Pad))
{
return true;
}
}
if (Passage.bWalkableTunnelContract
&& Passage.ControlPoints.Num() >= 2
&& Passage.ControlRadii.Num() == Passage.ControlPoints.Num())
{
constexpr float Pad = 1.0f;
for (int32 SegmentIndex = 0;
SegmentIndex + 1 < Passage.ControlPoints.Num(); ++SegmentIndex)
{
const FVector& A = Passage.ControlPoints[SegmentIndex];
const FVector& B = Passage.ControlPoints[SegmentIndex + 1];
const float SupportRadius = FMath::Max(
FMath::Min(
FMath::Abs(Passage.ControlRadii[SegmentIndex]),
FMath::Abs(Passage.ControlRadii[SegmentIndex + 1])) - 0.5f,
VoxelPassageGeometry::PlayerRadiusVoxels);
const float FloorA = VoxelPassageGeometry::TunnelFloorZ(
A, Passage.ControlRadii[SegmentIndex]);
const float FloorB = VoxelPassageGeometry::TunnelFloorZ(
B, Passage.ControlRadii[SegmentIndex + 1]);
if (VF_LatticeBoxTouchesAABB(
VoxelBox, LatticeOrigin, Step,
FMath::Min(A.X, B.X) - SupportRadius - Pad,
FMath::Max(A.X, B.X) + SupportRadius + Pad,
FMath::Min(A.Y, B.Y) - SupportRadius - Pad,
FMath::Max(A.Y, B.Y) + SupportRadius + Pad,
FMath::Min(FloorA, FloorB)
- VoxelPassageGeometry::LandingFloorThicknessVoxels - Pad,
FMath::Max(FloorA, FloorB) + Pad))
{
return true;
}
}
}
}
return false;
}
bool UVoxelStrateManager::AnyOriginLandingNearBox(
const FVector& MinVoxel, const FVector& MaxVoxel) const
{
@@ -2199,6 +2637,44 @@ bool UVoxelStrateManager::AnyOriginLandingFloorNearBox(
return false;
}
bool UVoxelStrateManager::AnyOriginLandingNearLattice(
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step) const
{
if (OriginSpineRadius <= 0.0f) return false;
for (const FStrateSlot& Slot : StrateLayout)
{
if (Slot.Definition == nullptr) continue;
const float TopZ = (static_cast<float>(Slot.TopChunkZ) + 1.0f) * CHUNK_SIZE;
const float BottomZ = static_cast<float>(Slot.BottomChunkZ) * CHUNK_SIZE;
const float Seal = VF_BoundarySealThicknessForDefinition(*Slot.Definition);
if (VoxelPassageGeometry::OriginLandingRoomTouchesLattice(
VoxelBox, LatticeOrigin, Step, TopZ, BottomZ, Seal, OriginSpineRadius))
{
return true;
}
}
return false;
}
bool UVoxelStrateManager::AnyOriginLandingFloorNearLattice(
const FBox& VoxelBox, const FIntVector& LatticeOrigin, int32 Step) const
{
if (OriginSpineRadius <= 0.0f) return false;
for (const FStrateSlot& Slot : StrateLayout)
{
if (Slot.Definition == nullptr) continue;
const float TopZ = (static_cast<float>(Slot.TopChunkZ) + 1.0f) * CHUNK_SIZE;
const float BottomZ = static_cast<float>(Slot.BottomChunkZ) * CHUNK_SIZE;
const float Seal = VF_BoundarySealThicknessForDefinition(*Slot.Definition);
if (VoxelPassageGeometry::OriginLandingFloorTouchesLattice(
VoxelBox, LatticeOrigin, Step, TopZ, BottomZ, Seal, OriginSpineRadius))
{
return true;
}
}
return false;
}
//=============================================================================
// QUERIES
//=============================================================================