perf(tunnels): memoise the room mouth -- room ownership now cheaper than before the change
The room-wins rule cost +55% static / +36% moving worker CPU because every sample re-answered the room-mouth question. A bounded exact memo around BuildRoomMouth (4096 sets x 4 ways, 7.49 MiB, keyed on every geometry-affecting room/tunnel input) removes that: hit rate 99.91% static / 99.89% moving, and VF_FindRoomFloorCrossingWorld (19.5%/17.1% inclusive), VF_FindRoomMouthBoundary (16.0%/14.0%) and VF_EvaluateRoomLandingDensity leave the sampler's top 30 entirely.
vs the tip DLL (bf9384a runtime), same staged owner map: worker sum 29.003 s vs 30.749 s static (-5.7%), 57.232 s vs 60.923 s moving (-6.1%), request p95 -3.3% / -8.4%. Geometry unchanged by construction: canonical hash 86A99075, 64/64 tile hashes, OBJ SHA 7E0D8109..C543, identical across a repeat run and with -voxel.CrtFma3=0. Walk Connected 42,870 / 17,413; tunnel-attributed solid inside rooms 0; mouth amplitude 1.4903 cm; TilePostReachProof and DetSinCos pass. The crossing test was not rerun (the memo returns the same values; its PASS stands at 248.43 m / 26.584 s).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
76bc8bce97
commit
1c642fd182
5 files changed
+890
-71
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -3747,6 +3747,8 @@ namespace
|
|||||||
FTunnelCoreWorldEvaluation LastTunnelCoreWorldEvaluation;
|
FTunnelCoreWorldEvaluation LastTunnelCoreWorldEvaluation;
|
||||||
FVector LastTunnelCoreEvaluationPosition = FVector::ZeroVector;
|
FVector LastTunnelCoreEvaluationPosition = FVector::ZeroVector;
|
||||||
bool bLastTunnelCoreWorldEvaluationValid = false;
|
bool bLastTunnelCoreWorldEvaluationValid = false;
|
||||||
|
bool bLastRoomOwnsBottom = false;
|
||||||
|
bool bLastRoomOwnsBottomValid = false;
|
||||||
|
|
||||||
/** ÉTAPE C1 — les params de la strate avec l'op de CETTE salle appliqué par-dessus.
|
/** ÉTAPE C1 — les params de la strate avec l'op de CETTE salle appliqué par-dessus.
|
||||||
* Mémo par voxel : invalidé au début de chaque `Eval`, calculé au PREMIER modificateur
|
* Mémo par voxel : invalidé au début de chaque `Eval`, calculé au PREMIER modificateur
|
||||||
@@ -3800,6 +3802,7 @@ namespace
|
|||||||
S.ActiveCache = Sample.RoomCache;
|
S.ActiveCache = Sample.RoomCache;
|
||||||
S.NearestRoom = Sample.NearestRoomIndex;
|
S.NearestRoom = Sample.NearestRoomIndex;
|
||||||
S.bLocalParamsValid = false;
|
S.bLocalParamsValid = false;
|
||||||
|
S.bLastRoomOwnsBottomValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryGetLastTunnelCoreWorldEvaluation(
|
bool TryGetLastTunnelCoreWorldEvaluation(
|
||||||
@@ -3827,7 +3830,8 @@ namespace
|
|||||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
Position.X, Position.Y, Position.Z, GetCache(), nullptr,
|
Position.X, Position.Y, Position.Z, GetCache(), nullptr,
|
||||||
VoxelGenLOD::ShouldUseSpatialIndex(false),
|
VoxelGenLOD::ShouldUseSpatialIndex(false),
|
||||||
&S.LastWarpedPosition);
|
&S.LastWarpedPosition,
|
||||||
|
S.bLastRoomOwnsBottomValid ? &S.bLastRoomOwnsBottom : nullptr);
|
||||||
S.LastTunnelCoreEvaluationPosition = Position;
|
S.LastTunnelCoreEvaluationPosition = Position;
|
||||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||||
}
|
}
|
||||||
@@ -3922,6 +3926,7 @@ namespace
|
|||||||
FState& S = State();
|
FState& S = State();
|
||||||
S.LastWorldPosition = FVector(WorldX, WorldY, WorldZ);
|
S.LastWorldPosition = FVector(WorldX, WorldY, WorldZ);
|
||||||
S.bLastTunnelCoreWorldEvaluationValid = false;
|
S.bLastTunnelCoreWorldEvaluationValid = false;
|
||||||
|
S.bLastRoomOwnsBottomValid = false;
|
||||||
|
|
||||||
// ⚠️ REMIS À -1 INCONDITIONNELLEMENT, ce que l'original ne fait pas : chez lui
|
// ⚠️ REMIS À -1 INCONDITIONNELLEMENT, ce que l'original ne fait pas : chez lui
|
||||||
// `NearestRoomIdx` est un `thread_local` qui, quand `RoomDensity <= 0`, garde la valeur
|
// `NearestRoomIdx` est un `thread_local` qui, quand `RoomDensity <= 0`, garde la valeur
|
||||||
@@ -4184,7 +4189,9 @@ namespace
|
|||||||
const FVector WorldTunnelPosition(WorldX, WorldY, WorldZ);
|
const FVector WorldTunnelPosition(WorldX, WorldY, WorldZ);
|
||||||
float CaveSDF = VoxelCaveMorphology::EvaluateSDFCached(
|
float CaveSDF = VoxelCaveMorphology::EvaluateSDFCached(
|
||||||
WarpedX, WarpedY, WarpedZ, GetCache(), P.SDFBlendRadius,
|
WarpedX, WarpedY, WarpedZ, GetCache(), P.SDFBlendRadius,
|
||||||
&S.NearestRoom, bUseSpatialIndex, &WorldTunnelPosition);
|
&S.NearestRoom, bUseSpatialIndex, &WorldTunnelPosition,
|
||||||
|
&S.bLastRoomOwnsBottom);
|
||||||
|
S.bLastRoomOwnsBottomValid = true;
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// PITS & CHEMINÉES — coordonnées RÉELLES, SmoothMin dans le même canal SDF
|
// PITS & CHEMINÉES — coordonnées RÉELLES, SmoothMin dans le même canal SDF
|
||||||
@@ -4275,7 +4282,8 @@ namespace
|
|||||||
{
|
{
|
||||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
WorldX, WorldY, WorldZ, GetCache(), nullptr,
|
WorldX, WorldY, WorldZ, GetCache(), nullptr,
|
||||||
bUseSpatialIndex, &S.LastWarpedPosition);
|
bUseSpatialIndex, &S.LastWarpedPosition,
|
||||||
|
&S.bLastRoomOwnsBottom);
|
||||||
S.LastTunnelCoreEvaluationPosition = S.LastWorldPosition;
|
S.LastTunnelCoreEvaluationPosition = S.LastWorldPosition;
|
||||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||||
|
|
||||||
|
|||||||
@@ -3294,6 +3294,10 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
float BlockTunnelCoreSweptFloorRadius = 0.0f;
|
float BlockTunnelCoreSweptFloorRadius = 0.0f;
|
||||||
bool bUsedFusedEvaluator = false;
|
bool bUsedFusedEvaluator = false;
|
||||||
FTunnelCoreWorldEvaluation FusedTunnelCore;
|
FTunnelCoreWorldEvaluation FusedTunnelCore;
|
||||||
|
bool bRoomOwnsBottom = false;
|
||||||
|
bool bRoomOwnsBottomValid = false;
|
||||||
|
FVector NativeWarpedPosition = FVector::ZeroVector;
|
||||||
|
bool bNativeWarpedPositionValid = false;
|
||||||
|
|
||||||
// Le seul point d'entrée de la pile dans le chemin de production. Elle rend la convention
|
// Le seul point d'entrée de la pile dans le chemin de production. Elle rend la convention
|
||||||
// MC (négatif = solide) comme les fonctions d'archétype, donc les disturbances et la couche
|
// MC (négatif = solide) comme les fonctions d'archétype, donc les disturbances et la couche
|
||||||
@@ -3322,7 +3326,9 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
WorldX, WorldY, WorldZ, CP_Tunnel, CP_TunnelFP, LayoutVersion,
|
WorldX, WorldY, WorldZ, CP_Tunnel, CP_TunnelFP, LayoutVersion,
|
||||||
/*bApplyLegacyStructuralPosts=*/false,
|
/*bApplyLegacyStructuralPosts=*/false,
|
||||||
&FusedTunnelCore,
|
&FusedTunnelCore,
|
||||||
/*bCollectFusedDiagnostics=*/true);
|
/*bCollectFusedDiagnostics=*/true,
|
||||||
|
&bRoomOwnsBottom);
|
||||||
|
bRoomOwnsBottomValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool bIntegerLatticePoint =
|
const bool bIntegerLatticePoint =
|
||||||
@@ -3434,7 +3440,12 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
// Underwater shares tunnel rock (water table is a render-side overlay).
|
// Underwater shares tunnel rock (water table is a render-side overlay).
|
||||||
Result = GetDensityWithParams(WorldX, WorldY, WorldZ, CP_Tunnel,
|
Result = GetDensityWithParams(WorldX, WorldY, WorldZ, CP_Tunnel,
|
||||||
CP_TunnelFP, LayoutVersion,
|
CP_TunnelFP, LayoutVersion,
|
||||||
/*bApplyLegacyStructuralPosts=*/false); break;
|
/*bApplyLegacyStructuralPosts=*/false,
|
||||||
|
nullptr, false, &bRoomOwnsBottom,
|
||||||
|
&NativeWarpedPosition);
|
||||||
|
bRoomOwnsBottomValid = true;
|
||||||
|
bNativeWarpedPositionValid = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
DensityCoreTimer.End();
|
DensityCoreTimer.End();
|
||||||
|
|
||||||
@@ -3475,18 +3486,27 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
{
|
{
|
||||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||||
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
||||||
FVector RoomQueryPosition(WorldX, WorldY, WorldZ);
|
FVector RoomQueryPosition;
|
||||||
|
if (bNativeWarpedPositionValid)
|
||||||
|
{
|
||||||
|
RoomQueryPosition = NativeWarpedPosition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RoomQueryPosition = FVector(WorldX, WorldY, WorldZ);
|
||||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||||
{
|
{
|
||||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||||
}
|
}
|
||||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||||
|
}
|
||||||
PreDisturbanceTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
PreDisturbanceTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache, nullptr,
|
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache, nullptr,
|
||||||
VoxelGenLOD::ShouldUseSpatialIndex(
|
VoxelGenLOD::ShouldUseSpatialIndex(
|
||||||
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
||||||
&RoomQueryPosition);
|
&RoomQueryPosition,
|
||||||
|
bRoomOwnsBottomValid ? &bRoomOwnsBottom : nullptr);
|
||||||
bHavePreDisturbanceTunnelCore = true;
|
bHavePreDisturbanceTunnelCore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3679,19 +3699,28 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
{
|
{
|
||||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||||
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
||||||
FVector RoomQueryPosition(WorldX, WorldY, WorldZ);
|
FVector RoomQueryPosition;
|
||||||
|
if (bNativeWarpedPositionValid)
|
||||||
|
{
|
||||||
|
RoomQueryPosition = NativeWarpedPosition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RoomQueryPosition = FVector(WorldX, WorldY, WorldZ);
|
||||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||||
{
|
{
|
||||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||||
}
|
}
|
||||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||||
|
}
|
||||||
TunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
TunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache,
|
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache,
|
||||||
nullptr,
|
nullptr,
|
||||||
VoxelGenLOD::ShouldUseSpatialIndex(
|
VoxelGenLOD::ShouldUseSpatialIndex(
|
||||||
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
||||||
&RoomQueryPosition);
|
&RoomQueryPosition,
|
||||||
|
bRoomOwnsBottomValid ? &bRoomOwnsBottom : nullptr);
|
||||||
bHaveTunnelCore = true;
|
bHaveTunnelCore = true;
|
||||||
}
|
}
|
||||||
if (bHaveTunnelCore)
|
if (bHaveTunnelCore)
|
||||||
@@ -3828,7 +3857,9 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
|||||||
uint32 ParamsFingerprint, uint32 LayoutVersion,
|
uint32 ParamsFingerprint, uint32 LayoutVersion,
|
||||||
bool bApplyLegacyStructuralPosts,
|
bool bApplyLegacyStructuralPosts,
|
||||||
FTunnelCoreWorldEvaluation* OutTunnelCore,
|
FTunnelCoreWorldEvaluation* OutTunnelCore,
|
||||||
bool bCollectFusedDiagnostics) const
|
bool bCollectFusedDiagnostics,
|
||||||
|
bool* OutRoomOwnsBottom,
|
||||||
|
FVector* OutWarpedPosition) const
|
||||||
{
|
{
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// STRATE DENSITY FUNCTION (Morphology Pipeline)
|
// STRATE DENSITY FUNCTION (Morphology Pipeline)
|
||||||
@@ -3859,6 +3890,14 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
|||||||
{
|
{
|
||||||
*OutTunnelCore = FTunnelCoreWorldEvaluation();
|
*OutTunnelCore = FTunnelCoreWorldEvaluation();
|
||||||
}
|
}
|
||||||
|
if (OutRoomOwnsBottom != nullptr)
|
||||||
|
{
|
||||||
|
*OutRoomOwnsBottom = false;
|
||||||
|
}
|
||||||
|
if (OutWarpedPosition != nullptr)
|
||||||
|
{
|
||||||
|
*OutWarpedPosition = FVector::ZeroVector;
|
||||||
|
}
|
||||||
if (bCollectFusedDiagnostics && VoxelDensityProfile::AreCountersEnabled())
|
if (bCollectFusedDiagnostics && VoxelDensityProfile::AreCountersEnabled())
|
||||||
{
|
{
|
||||||
VoxelDensityProfile::AddCounter(
|
VoxelDensityProfile::AddCounter(
|
||||||
@@ -3930,6 +3969,10 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
|||||||
WarpedY += WarpY * VOXEL_NOISE_SCALE * WS;
|
WarpedY += WarpY * VOXEL_NOISE_SCALE * WS;
|
||||||
WarpedZ += WarpZ * VOXEL_NOISE_SCALE * WS;
|
WarpedZ += WarpZ * VOXEL_NOISE_SCALE * WS;
|
||||||
}
|
}
|
||||||
|
if (OutWarpedPosition != nullptr)
|
||||||
|
{
|
||||||
|
*OutWarpedPosition = FVector(WarpedX, WarpedY, WarpedZ);
|
||||||
|
}
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// STEP 4: SDF MORPHOLOGY (rooms + tunnels) — CACHED PER CHUNK
|
// STEP 4: SDF MORPHOLOGY (rooms + tunnels) — CACHED PER CHUNK
|
||||||
@@ -4187,7 +4230,8 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
|||||||
SDFCache, Params.SDFBlendRadius,
|
SDFCache, Params.SDFBlendRadius,
|
||||||
&NearestRoomIdx,
|
&NearestRoomIdx,
|
||||||
bUseSpatialIndex,
|
bUseSpatialIndex,
|
||||||
&WorldTunnelPosition
|
&WorldTunnelPosition,
|
||||||
|
OutRoomOwnsBottom
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── PIT & CHIMNEY SDF INTEGRATION ──
|
// ── PIT & CHIMNEY SDF INTEGRATION ──
|
||||||
@@ -4307,7 +4351,7 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
|||||||
const FVector RoomQueryPosition(WarpedX, WarpedY, WarpedZ);
|
const FVector RoomQueryPosition(WarpedX, WarpedY, WarpedZ);
|
||||||
*OutTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
*OutTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
WorldX, WorldY, WorldZ, SDFCache, nullptr, bUseSpatialIndex,
|
WorldX, WorldY, WorldZ, SDFCache, nullptr, bUseSpatialIndex,
|
||||||
&RoomQueryPosition);
|
&RoomQueryPosition, OutRoomOwnsBottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|||||||
@@ -1049,6 +1049,10 @@ namespace VoxelCaveMorphology
|
|||||||
// supplied, rooms remain at the query position but the tunnel
|
// supplied, rooms remain at the query position but the tunnel
|
||||||
// uses its authored world chain. Null preserves the legacy
|
// uses its authored world chain. Null preserves the legacy
|
||||||
// all-query behavior.
|
// all-query behavior.
|
||||||
|
// @param OutRoomOwnsBottom — optional out: true when the query position is inside any
|
||||||
|
// cached room's raw authored shape. When the caller evaluates
|
||||||
|
// the tunnel core for this same sample, pass this result back
|
||||||
|
// to EvaluateTunnelCoreWorld to avoid a second room query.
|
||||||
// (Room shape variety is baked into FCachedRoom by BuildChunkCache — no per-voxel roll.)
|
// (Room shape variety is baked into FCachedRoom by BuildChunkCache — no per-voxel roll.)
|
||||||
// @return negative = inside cave, positive = solid rock
|
// @return negative = inside cave, positive = solid rock
|
||||||
VOXELFORGE_API float EvaluateSDFCached(
|
VOXELFORGE_API float EvaluateSDFCached(
|
||||||
@@ -1057,7 +1061,8 @@ namespace VoxelCaveMorphology
|
|||||||
float SDFBlendRadius,
|
float SDFBlendRadius,
|
||||||
int32* OutNearestRoomIdx = nullptr,
|
int32* OutNearestRoomIdx = nullptr,
|
||||||
bool bUseSpatialIndex = true,
|
bool bUseSpatialIndex = true,
|
||||||
const FVector* WorldTunnelPosition = nullptr
|
const FVector* WorldTunnelPosition = nullptr,
|
||||||
|
bool* OutRoomOwnsBottom = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate the raw union of cached graph-tunnel capsules. This is intentionally separate from
|
// Evaluate the raw union of cached graph-tunnel capsules. This is intentionally separate from
|
||||||
@@ -1087,7 +1092,10 @@ namespace VoxelCaveMorphology
|
|||||||
// The room graph is evaluated in warped coordinates while the tunnel core is evaluated in
|
// The room graph is evaluated in warped coordinates while the tunnel core is evaluated in
|
||||||
// the authored world frame. Pass the former when available so room ownership is tested in
|
// the authored world frame. Pass the former when available so room ownership is tested in
|
||||||
// the same domain as the generic room field.
|
// the same domain as the generic room field.
|
||||||
const FVector* RoomQueryPosition = nullptr
|
const FVector* RoomQueryPosition = nullptr,
|
||||||
|
// Optional result from EvaluateSDFCached for this exact sample. When supplied, it avoids
|
||||||
|
// repeating the room-shape containment query; null preserves standalone-call behavior.
|
||||||
|
const bool* CachedRoomOwnsBottom = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
// Per-tile broad reach for the world-space core/floor post. The bound includes the swept
|
// Per-tile broad reach for the world-space core/floor post. The bound includes the swept
|
||||||
|
|||||||
@@ -240,7 +240,14 @@ public:
|
|||||||
FTunnelCoreWorldEvaluation* OutTunnelCore = nullptr,
|
FTunnelCoreWorldEvaluation* OutTunnelCore = nullptr,
|
||||||
// Diagnostics are opt-in so ordinary/reference calls do not pay
|
// Diagnostics are opt-in so ordinary/reference calls do not pay
|
||||||
// for fused-path counters.
|
// for fused-path counters.
|
||||||
bool bCollectFusedDiagnostics = false) const;
|
bool bCollectFusedDiagnostics = false,
|
||||||
|
// Optional same-sample hand-off from EvaluateSDFCached. This is
|
||||||
|
// only a room-shape ownership bit; it does not alter the scalar
|
||||||
|
// result and avoids a duplicate room-index query in native paths.
|
||||||
|
bool* OutRoomOwnsBottom = nullptr,
|
||||||
|
// Optional same-sample warped position. Native GetDensityAt uses
|
||||||
|
// this to feed the core post without applying the cave warp twice.
|
||||||
|
FVector* OutWarpedPosition = nullptr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Densité pour une strate Slab (FlatPlain / CrystalChamber).
|
* Densité pour une strate Slab (FlatPlain / CrystalChamber).
|
||||||
|
|||||||
Reference in new issue
Block a user