From the outside performance review (items 1-4; item 5 prototyped and reverted).
1. Collision gate: a support request outside the stamped desired set was cancelled by the rebuild
it forced, and the gate held the pawn with gravity 0. Baseline deep-drop (floor at (0,0,-7),
outside the aligned L0 ring): 1 hold of 30.0 s, never released. Fix: the target and 3 tiles
below are retained through rebuilds at CollisionCritical; hold only when the swept capsule is
about to enter pending support; release restores movement mode, gravity and downward speed.
After: 3 holds, 2.21 s total, 112.8 m horizontal progress; gate off still penetrates (-7.4 cm).
2. Suspected cleanup regression (out-of-layout stacks): not real. 44 paired boundary tiles,
30.9 ms vs 32.6 ms at b4ac996, hashes 44/44 identical. No change.
3. PawnCollisionRadiusChunks (new, default 1): L0 tiles outside the collision set stay visible
without Chaos cooks; anchors and the gate's support column are unioned in. Cook requests
~217/min -> ~30/min (-86%). Critical support ready time did NOT improve (9.5 s -> 10.6 s in the
deep-drop fixture; the wait is the cook itself, ~7.4 s cook-to-ready there).
4. Dig: exact pre-edit L0 density cached (one 35^3 grid, 171.5 KB), carve replays current mods on
it. Sync remesh 99.4 ms -> 4.7 ms. 16/16 random carves hash-identical to full regeneration.
5. Parallel grid fill for the critical tile: 16/16 hash parity, but the waited-on tile was already
meshed; the wait was collision cooking. Reverted.
Review G answered: M_Test1 still ray-marches VolTex0 (custom HLSL mini-sun shadow), so the density
volume is live. Known and left alone: outside the strate layout the fallback density can be solid
while the gate treats those tiles as air.
Tests: VoxelForgeCollisionDesiredTilesTest, VoxelForgePreEditDensityCacheTest; no-overlap, edit
ghost, descent corridor pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
111 lines
4.7 KiB
C++
111 lines
4.7 KiB
C++
#if WITH_DEV_AUTOMATION_TESTS
|
|
|
|
#include "Misc/AutomationTest.h"
|
|
#include "VoxelForgeTestFixture.h"
|
|
#include "VoxelMarchingCubesMesher.h"
|
|
#include "VoxelGeometryHash.h"
|
|
#include "VoxelStackSampler.h"
|
|
#include "../VoxelPreEditDensityCache.h"
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
FVoxelForgePreEditDensityCacheParityTest,
|
|
"VoxelForge.Determinism.PreEditDensityCacheCarveParity",
|
|
EAutomationTestFlags_ApplicationContextMask | EAutomationTestFlags::EngineFilter)
|
|
|
|
bool FVoxelForgePreEditDensityCacheParityTest::RunTest(const FString& Parameters)
|
|
{
|
|
using namespace VoxelForgeTest;
|
|
|
|
FTestWorld World;
|
|
World.Build(/*Seed*/1337, /*GapChunks*/2);
|
|
if (!World.IsValid())
|
|
{
|
|
AddError(World.WhyInvalid());
|
|
return false;
|
|
}
|
|
|
|
int32 SlotTop = 0;
|
|
int32 SlotBottom = 0;
|
|
if (!World.GetSlotVoxelZRange(FTestWorld::SlotTunnelNetwork, SlotTop, SlotBottom))
|
|
{
|
|
AddError(TEXT("TunnelNetwork slot range was unavailable."));
|
|
return false;
|
|
}
|
|
const int32 MidVoxelZ = (SlotTop + SlotBottom) / 2;
|
|
const int32 TileZ = FMath::FloorToInt(
|
|
static_cast<float>(MidVoxelZ) / CHUNK_SIZE) * CHUNK_SIZE;
|
|
const FIntVector TileOrigin(0, 0, TileZ);
|
|
TestEqual(TEXT("the runtime pre-edit cache holds only the pawn's current tile"),
|
|
VoxelForgePreEditDensityCache::MaxCachedTiles, 1);
|
|
TestEqual(TEXT("the cache target radius matches its one-tile memory bound"),
|
|
VoxelForgePreEditDensityCache::PawnRadiusChunks, 0);
|
|
|
|
TStrongObjectPtr<UVoxelMarchingCubesMesher> Mesher(
|
|
NewObject<UVoxelMarchingCubesMesher>(GetTransientPackage(), NAME_None, RF_Transient));
|
|
Mesher->SetGenerator(World.Generator.Get());
|
|
|
|
FScopedVoxelStackRegistration StackRegistration(/*InLODLevel*/0);
|
|
FVoxelSharedDensityGrid PreEditGrid;
|
|
int64 BaseDensitySamples = 0;
|
|
Mesher->GenerateMesh(TileOrigin, 1, CHUNK_SIZE, nullptr, INT32_MIN, INT32_MAX,
|
|
&BaseDensitySamples, &PreEditGrid);
|
|
TestEqual(TEXT("the cache captured the complete 35³ lattice"),
|
|
PreEditGrid.Samples.Num(), (CHUNK_SIZE + 3) * (CHUNK_SIZE + 3) * (CHUNK_SIZE + 3));
|
|
TestEqual(TEXT("the cache uses the one-voxel mesh halo"), PreEditGrid.Dim, CHUNK_SIZE + 3);
|
|
TestTrue(TEXT("the initial tile sampled its density lattice"), BaseDensitySamples > 0);
|
|
if (PreEditGrid.Samples.Num() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FRandomStream Random(0x4D17);
|
|
int32 ComparedCarves = 0;
|
|
int32 NonEmptyPairs = 0;
|
|
for (int32 CarveIndex = 0; CarveIndex < 16; ++CarveIndex)
|
|
{
|
|
FVoxelModification Modification;
|
|
Modification.Center = FVector(
|
|
TileOrigin.X + Random.RandRange(5, 27),
|
|
TileOrigin.Y + Random.RandRange(5, 27),
|
|
TileOrigin.Z + Random.RandRange(5, 27));
|
|
Modification.Radius = static_cast<float>(Random.RandRange(3, 7));
|
|
Modification.Strength = -50.0f;
|
|
const TArray<FIntVector> Affected = World.DiffLayer->ApplyModification(Modification);
|
|
TestTrue(FString::Printf(TEXT("random carve %d affected at least one chunk"), CarveIndex),
|
|
Affected.Num() > 0);
|
|
|
|
FVoxelSharedDensityGrid EditedGrid;
|
|
TestTrue(FString::Printf(TEXT("random carve %d replayed over pre-edit samples"), CarveIndex),
|
|
VoxelForgePreEditDensityCache::BuildEditedGrid(
|
|
PreEditGrid, World.DiffLayer.Get(), EditedGrid));
|
|
|
|
const FVoxelMeshData FullRegeneration = Mesher->GenerateMesh(
|
|
TileOrigin, 1, CHUNK_SIZE, nullptr, INT32_MIN, INT32_MAX);
|
|
const FVoxelMeshData CachedRemesh = Mesher->GenerateMesh(
|
|
TileOrigin, 1, CHUNK_SIZE, nullptr, INT32_MIN, INT32_MAX,
|
|
nullptr, nullptr, &EditedGrid);
|
|
const FString FullHash = VoxelForgeGeometryHash::Compute(FullRegeneration);
|
|
const FString CachedHash = VoxelForgeGeometryHash::Compute(CachedRemesh);
|
|
TestEqual(FString::Printf(TEXT("carve %d cached/full tile hash"), CarveIndex),
|
|
CachedHash, FullHash);
|
|
if (CachedHash == FullHash)
|
|
{
|
|
++ComparedCarves;
|
|
}
|
|
if (!FullRegeneration.IsEmpty() && !CachedRemesh.IsEmpty())
|
|
{
|
|
++NonEmptyPairs;
|
|
}
|
|
}
|
|
|
|
TestEqual(TEXT("all random carves matched a full tile regeneration"), ComparedCarves, 16);
|
|
TestTrue(TEXT("the parity set exercised actual carve geometry"), NonEmptyPairs > 0);
|
|
AddInfo(FString::Printf(
|
|
TEXT("pre_edit_density_cache: carves=%d hash_matches=%d nonempty_pairs=%d samples=%d bytes=%d"),
|
|
16, ComparedCarves, NonEmptyPairs, PreEditGrid.Samples.Num(),
|
|
PreEditGrid.Samples.Num() * static_cast<int32>(sizeof(float))));
|
|
return true;
|
|
}
|
|
|
|
#endif // WITH_DEV_AUTOMATION_TESTS
|