perf(review): gate never deadlocks, collision radius, 20x faster digs
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
This commit is contained in:
1 parent
116b57f01e
commit
0bcd67a016
13 files changed
+1114
-104
No files matched your search
@@ -149,6 +149,9 @@ struct FChunkResult
|
||||
// it to UVoxelDensityVolume::IngestTileCapture so the density clipmap reuses the mesher's samples
|
||||
// instead of re-sampling. Moved (not copied) through the MPSC queue. See UVoxelDensityVolume.
|
||||
TArray<uint8> CaptureGrid;
|
||||
// Exact pre-edit level-0 lattice for the bounded local-player dig cache. Sampled on the worker
|
||||
// with the tile's normal generator context and moved through the result queue.
|
||||
FVoxelSharedDensityGrid PreEditDensityGrid;
|
||||
};
|
||||
|
||||
/** One worker-produced mesh identity emitted only by the explicit parity harness. */
|
||||
@@ -550,7 +553,7 @@ private:
|
||||
bool MeasureHeadlessCollisionGateStressTerrain(
|
||||
const FVector& WorldPosition, float CapsuleHalfHeightCm,
|
||||
float& OutFeetDensity, float& OutCenterDensity,
|
||||
float& OutSurfaceLocalVoxelZ, float& OutClearanceCm) const;
|
||||
float& OutSurfaceLocalVoxelZ, float& OutClearanceCm);
|
||||
void AdvanceHeadlessSurfaceFallTest(FVector& InOutPlayerPosition,
|
||||
FVector& InOutPlayerHeading, APawn* PlayerPawn);
|
||||
void InitializeHeadlessStrateCrossingTest();
|
||||
@@ -769,7 +772,9 @@ public:
|
||||
int32 Step, int32 Cells, uint32 Epoch, bool bWantCapture,
|
||||
int32 BandVoxLo, int32 BandVoxHi, int32 BandChunkLo, int32 BandChunkHi,
|
||||
FChunkResult& Result,
|
||||
const std::atomic<bool>* ObsoleteFlag = nullptr);
|
||||
const std::atomic<bool>* ObsoleteFlag = nullptr,
|
||||
bool bWantPreEditDensityGrid = false,
|
||||
const FVoxelSharedDensityGrid* SharedDensityOverride = nullptr);
|
||||
|
||||
/**
|
||||
* Game-thread apply for one gen result (shared by ProcessPendingChunks + SyncRemeshTile):
|
||||
@@ -859,6 +864,7 @@ public:
|
||||
FVoxelTileKey& OutSupportTile) const;
|
||||
|
||||
bool IsTileCollisionReady(const FVoxelTileKey& Tile) const;
|
||||
bool IsTileCollisionDesired(const FVoxelTileKey& Tile) const;
|
||||
bool IsCollisionTileUnavailable(const FVoxelTileKey& Tile,
|
||||
const TCHAR*& OutReason) const;
|
||||
bool IsCollisionReadyFromSupportTile(const FVoxelTileKey& CandidateTile,
|
||||
@@ -872,10 +878,10 @@ public:
|
||||
FVoxelTileKey* OutPendingTile = nullptr) const;
|
||||
void RequestCollisionGateSupportTile(const FVoxelTileKey& SupportTile);
|
||||
|
||||
/** Cancel only downward pawn motion while the tile beneath its feet is unresolved. Horizontal
|
||||
* input and movement remain live. The world tick is installed as the pawn prerequisite in the
|
||||
* implementation (and directly on its movement component) so this check runs before
|
||||
* CharacterMovementComponent physics. */
|
||||
/** Hold vertical character motion in gravity-free MOVE_Flying while a swept pending support tile
|
||||
* intersects the capsule, preserving horizontal movement until collision is ready. Restore the
|
||||
* previous mode, gravity, and downward speed on release. The world tick is a prerequisite of the
|
||||
* pawn and movement component so the gate check runs before movement physics. */
|
||||
void UpdatePawnCollisionGate(APawn* Pawn, const FVector& PlayerPosition, float DeltaTime);
|
||||
void EngagePawnCollisionGate(APawn* Pawn);
|
||||
void ReleasePawnCollisionGate();
|
||||
@@ -951,6 +957,9 @@ public:
|
||||
|
||||
// Player's level-0 tile coord (= chunk coord). The desired set is rebuilt when this changes.
|
||||
FIntVector CurrentCenterChunk = FIntVector::ZeroValue;
|
||||
// Exact unedited L0 lattices retained around the player for same-frame carve remeshes.
|
||||
// The radius helper bounds this to 27 × 35³ floats (4.42 MiB).
|
||||
TMap<FVoxelTileKey, FVoxelSharedDensityGrid> PreEditDensityCache;
|
||||
|
||||
// Non-player streaming anchors (AI now, remote players later — ARCHITECTURE §9.3). BuildDesiredTiles
|
||||
// folds each anchor's small level-0 box into the desired set (same DesiredStamped machinery → the
|
||||
@@ -960,6 +969,7 @@ public:
|
||||
// Adds each anchor's level-0 tiles to DesiredSorted/DesiredStamped (dedup vs the player clipmap)
|
||||
// and records the ones ONLY a CollisionOnly anchor wants in CollisionOnlyTiles.
|
||||
void AddAnchorDesiredTiles();
|
||||
void ReconcileCollisionDesiredTiles();
|
||||
// Forces a desired-set rebuild next Tick even if neither the player nor an anchor crossed a tile
|
||||
// boundary (set by UnregisterStreamingAnchor so a removed anchor's tiles get culled).
|
||||
bool bForceDesiredRebuild = false;
|
||||
@@ -971,6 +981,9 @@ public:
|
||||
// without an O(loaded) scan. Both empty when there are no CollisionOnly anchors → zero cost.
|
||||
TSet<FVoxelTileKey> CollisionOnlyTiles;
|
||||
TSet<FVoxelTileKey> PrevCollisionOnlyTiles;
|
||||
// Independent from DesiredSorted: rendered LOD0 tiles outside the pawn radius remain visible
|
||||
// without a Chaos body. Pawn radius, anchor boxes, and collision-gate support are unioned here.
|
||||
TSet<FVoxelTileKey> CollisionDesiredTiles;
|
||||
// A short collision-only column below an unresolved player support tile. Keeping these keys
|
||||
// stamped prevents a critical request outside the render clipmap from being canceled on rebuild.
|
||||
TSet<FVoxelTileKey> CollisionGateDesiredTiles;
|
||||
@@ -1103,14 +1116,18 @@ public:
|
||||
bool bHeadlessCollisionGateStressTestFailed = false;
|
||||
bool bHeadlessCollisionGateStressTestExitRequested = false;
|
||||
bool bHeadlessCollisionGateStressTestGateWasEngaged = false;
|
||||
bool bHeadlessCollisionGateStressTestHorizontalGateProbeApplied = false;
|
||||
bool bHeadlessCollisionGateStressTestFullStop = false;
|
||||
bool bHeadlessCollisionGateStressTestStartHeightCrossed = false;
|
||||
bool bHeadlessCollisionGateStressTestTerrainViolation = false;
|
||||
bool bHeadlessCollisionGateStressTestTerrainMeasurementMissing = false;
|
||||
bool bHeadlessCollisionGateStressTestLanded = false;
|
||||
bool bHeadlessCollisionGateStressTestLaunchSupportTimingCaptured = false;
|
||||
bool bHeadlessCollisionGateStressTestSettingsReported = false;
|
||||
bool bHeadlessCollisionGateStressDeepDrop = false;
|
||||
bool bHeadlessCollisionGateStressDeepDropPrepared = false;
|
||||
bool bHeadlessCollisionGateStressDeepDropPrewarmReported = false;
|
||||
bool bHeadlessCollisionGateStressDeepDropSurfaceCached = false;
|
||||
float HeadlessCollisionGateStressTestSpeedCmPerSecond = 6000.0f;
|
||||
float HeadlessCollisionGateStressTestSpawnHeightVoxels = 10.0f;
|
||||
float HeadlessCollisionGateStressTestDurationSeconds = 2.0f;
|
||||
@@ -1139,6 +1156,8 @@ public:
|
||||
FVector HeadlessCollisionGateStressTestLastActualPosition = FVector::ZeroVector;
|
||||
FVector HeadlessCollisionGateStressTestStartPosition = FVector::ZeroVector;
|
||||
FVector HeadlessCollisionGateStressTestMinClearancePosition = FVector::ZeroVector;
|
||||
FVector2D HeadlessCollisionGateStressDeepDropSurfaceXYVox = FVector2D::ZeroVector;
|
||||
float HeadlessCollisionGateStressDeepDropSurfaceZVox = 0.0f;
|
||||
FVoxelTileKey HeadlessCollisionGateStressTestLaunchSupportTile;
|
||||
FString HeadlessCollisionGateStressTestFailureReason;
|
||||
|
||||
@@ -1235,6 +1254,9 @@ public:
|
||||
bool bCollisionGateEnabled = true;
|
||||
float SavedCharacterGravityScale = 1.0f;
|
||||
bool bSavedCharacterGravityScale = false;
|
||||
uint8 SavedCharacterMovementMode = 0;
|
||||
uint8 SavedCharacterCustomMovementMode = 0;
|
||||
bool bSavedCharacterMovementMode = false;
|
||||
float SavedGateVerticalVelocity = 0.0f;
|
||||
bool bSavedGateVerticalVelocity = false;
|
||||
bool bPawnCollisionGateEngaged = false;
|
||||
|
||||
Reference in new issue
Block a user