wip(step3): 12.5 cm voxels, fall-through fixed, brick evaluator in game, organic tunnels -- speed gate FAILS

Stopped by the owner's decision (in-game lit captures were eating the round); he judges the look in
game instead.
1. Fall-through with the research field: fixed. Deep drop, gate on: 2 holds (0.50 s), min foot
   clearance +43 cm; gate off: penetrates (-278 cm). Stress fixture offsets converted to metres.
2. VOXEL_SIZE 25 -> 12.5 cm. Physical sizes kept in metres (player, steps, gate, insets, research
   field sizes, dig radii, test thresholds); class defaults that count chunks/voxels doubled
   (ClipRadius 6, RenderDistanceChunks 1536, ViewDistance*, StrateViewMargin 6,
   PawnCollisionRadius 2, SkirtCells 4, EdgeSealThickness 128, decoration spacings, density volume
   res 256). Asset values override these defaults: the owner must double his own.
   Ring scale, six workers, idle, step-2f field before the look changes: 64 m cube (519^3) 4.55 s;
   32 m cube (259^3) 0.95 s.
3. In game: tiles go through the brick evaluator (proved by a log marker); profile switch rebuilds
   the loaded world (~5,800 tiles); full-detail fill 12.4 s after spawn in the visible-window test.
4. Look: round winding tunnels, per-column ellipsoid/lattice caches. All step-2f geometry gates pass
   at 12.5 cm (0 crumbs, 1 solid component per profile, solid share 69-87%). 259^3 ring, six workers:
   1.08-2.02 s (worst HyperComplex) -- the 600 ms gate FAILS. Lit captures failed (hidden/off-screen
   window, then blank frames); not pursued.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-01 21:21:45 +02:00
1 parent ca78352e43
commit bc0f9ee791
33 files changed
+2691 -803

No files matched your search

@@ -181,39 +181,75 @@ namespace VoxelForgeRegionEval
TArray<FResearchBrick> Bricks;
const FIntVector Last = OriginVoxels
+ FIntVector(Dimension - 1, Dimension - 1, Dimension - 1);
const int32 ParameterizedBrickSize =
VoxelForgeRedefinedDensityField::ParameterizedBrickSamples;
const FIntVector ProofBrickSize = bParameterized
? FIntVector(4, 4, 4) : FIntVector(8, 8, 8);
? FIntVector(ParameterizedBrickSize, ParameterizedBrickSize, ParameterizedBrickSize)
: FIntVector(8, 8, 8);
// Parameterized tiles begin their lattice at chunkOrigin - 1. Their proof bricks start
// at world coordinates congruent to -1 modulo four; mirror that phase here so skips match
// the in-game tile path, including shared tile seams.
const int32 BrickAlignmentOffset = bParameterized ? -1 : 0;
const FIntVector FirstBrick(
FMath::FloorToInt(static_cast<float>(OriginVoxels.X) / ProofBrickSize.X),
FMath::FloorToInt(static_cast<float>(OriginVoxels.Y) / ProofBrickSize.Y),
FMath::FloorToInt(static_cast<float>(OriginVoxels.Z) / ProofBrickSize.Z));
FMath::FloorToInt(static_cast<float>(OriginVoxels.X - BrickAlignmentOffset) / ProofBrickSize.X),
FMath::FloorToInt(static_cast<float>(OriginVoxels.Y - BrickAlignmentOffset) / ProofBrickSize.Y),
FMath::FloorToInt(static_cast<float>(OriginVoxels.Z - BrickAlignmentOffset) / ProofBrickSize.Z));
const FIntVector LastBrick(
FMath::FloorToInt(static_cast<float>(Last.X) / ProofBrickSize.X),
FMath::FloorToInt(static_cast<float>(Last.Y) / ProofBrickSize.Y),
FMath::FloorToInt(static_cast<float>(Last.Z) / ProofBrickSize.Z));
Bricks.Reserve((LastBrick.X - FirstBrick.X + 1)
* (LastBrick.Y - FirstBrick.Y + 1) * (LastBrick.Z - FirstBrick.Z + 1));
for (int32 BZ = FirstBrick.Z; BZ <= LastBrick.Z; ++BZ)
for (int32 BY = FirstBrick.Y; BY <= LastBrick.Y; ++BY)
for (int32 BX = FirstBrick.X; BX <= LastBrick.X; ++BX)
FMath::FloorToInt(static_cast<float>(Last.X - BrickAlignmentOffset) / ProofBrickSize.X),
FMath::FloorToInt(static_cast<float>(Last.Y - BrickAlignmentOffset) / ProofBrickSize.Y),
FMath::FloorToInt(static_cast<float>(Last.Z - BrickAlignmentOffset) / ProofBrickSize.Z));
const uint64 TotalProofBrickCount = static_cast<uint64>(LastBrick.X - FirstBrick.X + 1)
* static_cast<uint64>(LastBrick.Y - FirstBrick.Y + 1)
* static_cast<uint64>(LastBrick.Z - FirstBrick.Z + 1);
const int32 BrickColumnsX = LastBrick.X - FirstBrick.X + 1;
const int32 BrickColumnsY = LastBrick.Y - FirstBrick.Y + 1;
if (bParameterized)
{
const FIntVector BrickWorldMin(
BX * ProofBrickSize.X, BY * ProofBrickSize.Y, BZ * ProofBrickSize.Z);
FResearchBrick& Brick = Bricks.AddDefaulted_GetRef();
Brick.Origin = FIntVector(
FMath::Max(OriginVoxels.X, BrickWorldMin.X),
FMath::Max(OriginVoxels.Y, BrickWorldMin.Y),
FMath::Max(OriginVoxels.Z, BrickWorldMin.Z));
const FIntVector BrickEnd = BrickWorldMin + ProofBrickSize;
const FIntVector RingEnd = OriginVoxels
+ FIntVector(Dimension, Dimension, Dimension);
const FIntVector End(
FMath::Min(BrickEnd.X, RingEnd.X),
FMath::Min(BrickEnd.Y, RingEnd.Y),
FMath::Min(BrickEnd.Z, RingEnd.Z));
Brick.Size = End - Brick.Origin;
Brick.Lattice = Brick.Origin - OriginVoxels;
Brick.SampleCount = Brick.Size.X * Brick.Size.Y * Brick.Size.Z;
Bricks.Reserve(BrickColumnsX * BrickColumnsY);
for (int32 BY = FirstBrick.Y; BY <= LastBrick.Y; ++BY)
for (int32 BX = FirstBrick.X; BX <= LastBrick.X; ++BX)
{
const int32 BrickWorldMinX = BX * ProofBrickSize.X + BrickAlignmentOffset;
const int32 BrickWorldMinY = BY * ProofBrickSize.Y + BrickAlignmentOffset;
FResearchBrick& Brick = Bricks.AddDefaulted_GetRef();
Brick.Origin = FIntVector(
FMath::Max(OriginVoxels.X, BrickWorldMinX),
FMath::Max(OriginVoxels.Y, BrickWorldMinY), OriginVoxels.Z);
Brick.Size = FIntVector(
FMath::Min(BrickWorldMinX + ProofBrickSize.X, Last.X + 1) - Brick.Origin.X,
FMath::Min(BrickWorldMinY + ProofBrickSize.Y, Last.Y + 1) - Brick.Origin.Y,
Dimension);
Brick.Lattice = Brick.Origin - OriginVoxels;
Brick.SampleCount = Brick.Size.X * Brick.Size.Y * Brick.Size.Z;
}
}
else
{
Bricks.Reserve(BrickColumnsX * BrickColumnsY * (LastBrick.Z - FirstBrick.Z + 1));
for (int32 BZ = FirstBrick.Z; BZ <= LastBrick.Z; ++BZ)
for (int32 BY = FirstBrick.Y; BY <= LastBrick.Y; ++BY)
for (int32 BX = FirstBrick.X; BX <= LastBrick.X; ++BX)
{
const FIntVector BrickWorldMin(
BX * ProofBrickSize.X + BrickAlignmentOffset,
BY * ProofBrickSize.Y + BrickAlignmentOffset,
BZ * ProofBrickSize.Z + BrickAlignmentOffset);
FResearchBrick& Brick = Bricks.AddDefaulted_GetRef();
Brick.Origin = FIntVector(
FMath::Max(OriginVoxels.X, BrickWorldMin.X),
FMath::Max(OriginVoxels.Y, BrickWorldMin.Y),
FMath::Max(OriginVoxels.Z, BrickWorldMin.Z));
const FIntVector BrickEnd = BrickWorldMin + ProofBrickSize;
const FIntVector RingEnd = OriginVoxels
+ FIntVector(Dimension, Dimension, Dimension);
const FIntVector End(
FMath::Min(BrickEnd.X, RingEnd.X),
FMath::Min(BrickEnd.Y, RingEnd.Y),
FMath::Min(BrickEnd.Z, RingEnd.Z));
Brick.Size = End - Brick.Origin;
Brick.Lattice = Brick.Origin - OriginVoxels;
Brick.SampleCount = Brick.Size.X * Brick.Size.Y * Brick.Size.Z;
}
}
TArray<double> WorkerWall;
@@ -253,6 +289,10 @@ namespace VoxelForgeRegionEval
double CpuStart = 0.0;
const bool bHaveCpuStart = GetCurrentThreadCpuSeconds(CpuStart);
TArray<float> BrickDetail;
TArray<float> ParameterizedDetail;
TArray<float> ParameterizedColumnValues;
TArray<float> ParameterizedBrickValues;
TArray<uint8> ParameterizedProofKinds;
VoxelForgeRedefinedDensityField::FBrickEvaluationContext BrickContext;
VoxelForgeRedefinedDensityField::FParameterizedBrickContext ParameterizedBrickContext;
for (;;)
@@ -267,19 +307,147 @@ namespace VoxelForgeRegionEval
for (int32 BrickIndex = BatchBegin; BrickIndex < BatchEnd; ++BrickIndex)
{
const FResearchBrick& Brick = Bricks[BrickIndex];
if (bParameterized)
{
const int32 ProofZCount = FMath::DivideAndRoundUp(
Brick.Size.Z, ParameterizedBrickSize);
ParameterizedProofKinds.SetNumUninitialized(ProofZCount);
for (int32 ProofZ = 0; ProofZ < ProofZCount; ++ProofZ)
{
const int32 Z = ProofZ * ParameterizedBrickSize;
const FIntVector ProofSize(
Brick.Size.X, Brick.Size.Y,
FMath::Min(ParameterizedBrickSize, Brick.Size.Z - Z));
const FIntVector ProofOrigin = Brick.Origin + FIntVector(0, 0, Z);
bool bUniformAir = false;
bool bEvaluatedMacroCentre = false;
VoxelForgeRedefinedDensityField::EBrickFallbackReason FallbackReason =
VoxelForgeRedefinedDensityField::EBrickFallbackReason::UnsupportedState;
bool bCanSkip = false;
if (bEnableBrickSkips)
{
++WorkerMacroChecks[WorkerIndex];
const double ClassifyStart = FPlatformTime::Seconds();
bCanSkip = VoxelForgeRedefinedDensityField::TryClassifyParameterizedBrick(
Generator, ProofOrigin, ProofSize, bUniformAir, DetailScale,
&bEvaluatedMacroCentre, &FallbackReason);
WorkerClassify[WorkerIndex] +=
FPlatformTime::Seconds() - ClassifyStart;
WorkerMacroCentreEvaluations[WorkerIndex] +=
bEvaluatedMacroCentre ? 1u : 0u;
if (!bCanSkip)
{
const int32 ReasonIndex = static_cast<uint8>(FallbackReason);
if (ReasonIndex < 5)
{
++WorkerFallbackReasons[WorkerIndex * 5 + ReasonIndex];
}
}
}
if (bCanSkip)
{
ParameterizedProofKinds[ProofZ] = bUniformAir ? 1 : 2;
++WorkerSkippedBricks[WorkerIndex];
const uint64 ProofSampleCount = static_cast<uint64>(
ProofSize.X * ProofSize.Y * ProofSize.Z);
WorkerSkippedSamples[WorkerIndex] += ProofSampleCount;
const float UniformDensity = bUniformAir
? VoxelForgeRedefinedDensityField::ParameterizedUniformDensity
: -VoxelForgeRedefinedDensityField::ParameterizedUniformDensity;
const double FillStart = FPlatformTime::Seconds();
for (int32 LocalZ = 0; LocalZ < ProofSize.Z; ++LocalZ)
for (int32 Y = 0; Y < ProofSize.Y; ++Y)
for (int32 X = 0; X < ProofSize.X; ++X)
{
const int64 LatticeIndex = LinearIndex(
Brick.Lattice.X + X, Brick.Lattice.Y + Y,
Brick.Lattice.Z + Z + LocalZ, Dimension);
OutDensities[static_cast<int32>(LatticeIndex)] = UniformDensity;
}
WorkerFill[WorkerIndex] += FPlatformTime::Seconds() - FillStart;
}
else
{
ParameterizedProofKinds[ProofZ] = 0;
}
}
for (int32 ProofZ = 0; ProofZ < ProofZCount;)
{
if (ParameterizedProofKinds[ProofZ] != 0)
{
++ProofZ;
continue;
}
const int32 FirstMixedProofZ = ProofZ;
const int32 FirstZ = FirstMixedProofZ * ParameterizedBrickSize;
const int32 FirstWorldZ = Brick.Origin.Z + FirstZ;
const int32 FirstChunkZ = FMath::FloorToInt(
static_cast<float>(FirstWorldZ) / CHUNK_SIZE);
int32 RunProofCount = 1;
int32 RunSampleCount = FMath::Min(
ParameterizedBrickSize, Brick.Size.Z - FirstZ);
while (ProofZ + RunProofCount < ProofZCount
&& ParameterizedProofKinds[ProofZ + RunProofCount] == 0)
{
const int32 CandidateCount = FMath::Min(
(RunProofCount + 1) * ParameterizedBrickSize,
Brick.Size.Z - FirstZ);
const int32 CandidateEndZ = FirstWorldZ + CandidateCount - 1;
const int32 CandidateChunkZ = FMath::FloorToInt(
static_cast<float>(CandidateEndZ) / CHUNK_SIZE);
if (CandidateCount > CHUNK_SIZE
|| CandidateChunkZ != FirstChunkZ)
{
break;
}
++RunProofCount;
RunSampleCount = CandidateCount;
}
if (RunSampleCount > CHUNK_SIZE)
{
RunSampleCount = ParameterizedBrickSize;
RunProofCount = 1;
}
const FIntVector RunSize(
Brick.Size.X, Brick.Size.Y, RunSampleCount);
const FIntVector RunOrigin = Brick.Origin + FIntVector(0, 0, FirstZ);
const double EvaluationStart = FPlatformTime::Seconds();
VoxelForgeRedefinedDensityField::EvaluateParameterizedDensityBrick(
Generator, RunOrigin, RunSize, DetailScale,
ParameterizedBrickContext, ParameterizedDetail,
ParameterizedColumnValues, ParameterizedBrickValues);
for (int32 Z = 0; Z < RunSize.Z; ++Z)
for (int32 Y = 0; Y < RunSize.Y; ++Y)
{
const int64 LatticeIndex = LinearIndex(
Brick.Lattice.X, Brick.Lattice.Y + Y,
Brick.Lattice.Z + FirstZ + Z, Dimension);
const int32 LocalIndex = (Z * RunSize.Y + Y) * RunSize.X;
FMemory::Memcpy(OutDensities.GetData() + LatticeIndex,
ParameterizedBrickValues.GetData() + LocalIndex,
static_cast<SIZE_T>(RunSize.X) * sizeof(float));
}
WorkerEvaluated[WorkerIndex] += static_cast<uint64>(RunSize.X)
* RunSize.Y * RunSize.Z;
WorkerEvaluate[WorkerIndex] += FPlatformTime::Seconds() - EvaluationStart;
ProofZ += RunProofCount;
}
continue;
}
bool bUniformAir = false;
bool bEvaluatedMacroCentre = false;
VoxelForgeRedefinedDensityField::EBrickFallbackReason FallbackReason =
VoxelForgeRedefinedDensityField::EBrickFallbackReason::UnsupportedState;
++WorkerMacroChecks[WorkerIndex];
const double ClassifyStart = FPlatformTime::Seconds();
const bool bCanSkip = bEnableBrickSkips && (bParameterized
? VoxelForgeRedefinedDensityField::TryClassifyParameterizedBrick(
const bool bCanSkip = bEnableBrickSkips
&& VoxelForgeRedefinedDensityField::TryClassifyBrick(
Generator, Brick.Origin, Brick.Size, bUniformAir, DetailScale,
&bEvaluatedMacroCentre, &FallbackReason)
: VoxelForgeRedefinedDensityField::TryClassifyBrick(
Generator, Brick.Origin, Brick.Size, bUniformAir, DetailScale,
&bEvaluatedMacroCentre, &FallbackReason));
&bEvaluatedMacroCentre, &FallbackReason);
WorkerClassify[WorkerIndex] += FPlatformTime::Seconds() - ClassifyStart;
WorkerMacroCentreEvaluations[WorkerIndex] += bEvaluatedMacroCentre ? 1u : 0u;
if (bEnableBrickSkips && !bCanSkip)
@@ -312,68 +480,25 @@ namespace VoxelForgeRegionEval
const double EvaluationStart = FPlatformTime::Seconds();
VoxelForgeRedefinedDensityField::BuildDetailBrick(
Generator, Brick.Origin, Brick.Size, DetailScale, BrickDetail,
bParameterized ? nullptr : &BrickContext, bParameterized);
if (bParameterized)
&BrickContext, /*bParameterized=*/false);
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
for (int32 X = 0; X < Brick.Size.X; ++X)
{
VoxelForgeRedefinedDensityField::BuildParameterizedBrickContext(
Generator, Brick.Origin, Brick.Size, ParameterizedBrickContext);
}
if (bParameterized)
{
const int32 DetailStride = Brick.Size.X * Brick.Size.Y;
float ColumnValues[8] = {};
float ParameterizedBrickValues[8 * 8 * 8];
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
for (int32 X = 0; X < Brick.Size.X; ++X)
{
const int32 DetailBase = Y * Brick.Size.X + X;
VoxelForgeRedefinedDensityField::EvaluateParameterizedColumnWithDetailValues(
Generator, static_cast<float>(Brick.Origin.X + X),
static_cast<float>(Brick.Origin.Y + Y),
static_cast<float>(Brick.Origin.Z),
BrickDetail.GetData() + DetailBase, DetailStride,
Brick.Size.Z, ColumnValues,
&ParameterizedBrickContext, DetailScale);
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
{
ParameterizedBrickValues[(Z * Brick.Size.Y + Y)
* Brick.Size.X + X] = ColumnValues[Z];
}
}
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
{
const int64 LatticeIndex = LinearIndex(
Brick.Lattice.X, Brick.Lattice.Y + Y,
Brick.Lattice.Z + Z, Dimension);
const int32 LocalIndex = (Z * Brick.Size.Y + Y) * Brick.Size.X;
FMemory::Memcpy(OutDensities.GetData() + LatticeIndex,
ParameterizedBrickValues + LocalIndex,
static_cast<SIZE_T>(Brick.Size.X) * sizeof(float));
}
WorkerEvaluated[WorkerIndex] += static_cast<uint64>(Brick.SampleCount);
}
else
{
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
for (int32 X = 0; X < Brick.Size.X; ++X)
{
const int32 WorldX = Brick.Origin.X + X;
const int32 WorldY = Brick.Origin.Y + Y;
const int32 WorldZ = Brick.Origin.Z + Z;
const int64 LatticeIndex = LinearIndex(
Brick.Lattice.X + X, Brick.Lattice.Y + Y,
Brick.Lattice.Z + Z, Dimension);
const float DetailValue = BrickDetail[
(Z * Brick.Size.Y + Y) * Brick.Size.X + X];
OutDensities[static_cast<int32>(LatticeIndex)] =
VoxelForgeRedefinedDensityField::EvaluateWithDetailValue(
Generator, static_cast<float>(WorldX), static_cast<float>(WorldY),
static_cast<float>(WorldZ), DetailValue,
nullptr, DetailScale, &BrickContext);
++WorkerEvaluated[WorkerIndex];
}
const int32 WorldX = Brick.Origin.X + X;
const int32 WorldY = Brick.Origin.Y + Y;
const int32 WorldZ = Brick.Origin.Z + Z;
const int64 LatticeIndex = LinearIndex(
Brick.Lattice.X + X, Brick.Lattice.Y + Y,
Brick.Lattice.Z + Z, Dimension);
const float DetailValue = BrickDetail[
(Z * Brick.Size.Y + Y) * Brick.Size.X + X];
OutDensities[static_cast<int32>(LatticeIndex)] =
VoxelForgeRedefinedDensityField::EvaluateWithDetailValue(
Generator, static_cast<float>(WorldX), static_cast<float>(WorldY),
static_cast<float>(WorldZ), DetailValue,
nullptr, DetailScale, &BrickContext);
++WorkerEvaluated[WorkerIndex];
}
WorkerEvaluate[WorkerIndex] += FPlatformTime::Seconds() - EvaluationStart;
}
@@ -392,7 +517,8 @@ namespace VoxelForgeRegionEval
OutTiming.WallSeconds = FPlatformTime::Seconds() - StartSeconds;
OutTiming.bRegionProgram = true;
OutTiming.BrickCount = static_cast<uint64>(Bricks.Num());
OutTiming.BrickCount = bParameterized
? TotalProofBrickCount : static_cast<uint64>(Bricks.Num());
OutTiming.ObservedWorkerThreads = 0;
for (int32 Worker = 0; Worker < NumWorkers; ++Worker)
{