measure(perf): per-component ablation of the TunnelNetwork path; exact worms restored
Round (Codex; reviewed by me against PERF-SAMPLED.md). Revert: voxel.WormNoiseMode / voxel.WormLatticeStep, their storage and their switches are REMOVED. VoxelWormField has one path again, exact Perlin with the N1 short circuit. Kept: bEnableWorms (asset), WormsForceOff (measurement only), the exact block skip (default 0). Ablation instrument: 14 development-only, world-changing force-off bits (voxel.TunnelAblate*), applied on the fused, op-stack/classifier, cached SDF/core and modifier/floor paths. They resolve once per process, are hashed into the generation fingerprint, and are compiled to zero in UE_BUILD_SHIPPING (VoxelDensityAblation.cpp). They are a measurement instrument, never a gameplay or multiplayer switch. Defaults exact: canonical export OBJ b3e5f4c3..9b377, worms-region 311CA42C / 75,482 triangles, capability 20,830 / 10,909, and 841/841 keyed tiles identical to NextHeadStaticTrace_20260913. Static worker seconds saved by removing ONE component (two off runs vs the interleaved all-on 33.06 s; baseline noise 0.27%): tunnel SDF 11.4%, cave warp 10.3%, passage carving 10.1%, landing posts 9.9%, passage structural posts 5.6%, worms 2.4%, native floor 2.2%, origin spine 1.6%, room SDF 1.6%, everything else <= 1.1% Moving (2+2 runs each) confirms the top five at 6.0-11.6%. Tunnel SDF off cuts LOD0 generation p95 104 -> 83 ms: it owns the slow tail. The positive savings sum to 58% of the static total; the other 42% is shared. The rows are not additive. Unexplained: tunnel-core OFF made the static total 2.9x SLOWER (95.5 s) while LOD0 generation got faster (p50 64.7 -> 60.6 ms) and triangles fell. The report blames the changed field, which does not fit; more likely a slow fallback path in coarse tiles. That row is not a cost measurement. Ledger: every Unreal process exited 0 and verified the loaded DLL; two PowerShell parser errors happened before any process started. No crashes or retries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
1 parent
c132243b30
commit
6ccf3718ff
12 files changed
+833
-695
No files matched your search
@@ -22,6 +22,7 @@
|
||||
#include "VoxelStrateComposer.h"
|
||||
|
||||
#include "VoxelDensityPrimitives.h" // VF_ApplyOriginSpine / seals / PassageCarving
|
||||
#include "VoxelDensityAblation.h" // fingerprinted development-only stage measurements
|
||||
#include "VoxelCaveMorphology.h" // VoxelSDF::Capsule, VoxelHash
|
||||
#include "VoxelGenerator.h" // VoxelGenLOD::Eff
|
||||
#include "VoxelHeightOp.h" // FVoxelHeightStack — SurfaceWorld's two height stacks
|
||||
@@ -1933,6 +1934,10 @@ namespace
|
||||
EVoxelOpEffect EffectOverBox(const FBox& VoxelBox,
|
||||
const FVoxelOpContext& Ctx) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsOriginSpineOff())
|
||||
{
|
||||
return EVoxelOpEffect::Identity;
|
||||
}
|
||||
const bool bRoomTouches = Ctx.bUseLatticeProof
|
||||
? VoxelPassageGeometry::OriginLandingRoomTouchesLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step,
|
||||
@@ -2018,6 +2023,10 @@ namespace
|
||||
*/
|
||||
EVoxelTileClass ClassifyBox(const FBox& VoxelBox, const FVoxelOpContext&) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsBoundarySealOff())
|
||||
{
|
||||
return EVoxelTileClass::Mixed;
|
||||
}
|
||||
if (Thickness <= 0.0f || Base <= 0.0f) { return EVoxelTileClass::Mixed; }
|
||||
|
||||
constexpr float SafetyMargin = 1.0f;
|
||||
@@ -2039,6 +2048,10 @@ namespace
|
||||
// Hors de sa bande, le seal ne fait rien du tout ; à cheval, il ne peut qu'ajouter du solide.
|
||||
EVoxelOpEffect EffectOverBox(const FBox& VoxelBox, const FVoxelOpContext&) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsBoundarySealOff())
|
||||
{
|
||||
return EVoxelOpEffect::Identity;
|
||||
}
|
||||
if (Thickness <= 0.0f) { return EVoxelOpEffect::Identity; }
|
||||
const bool bTouchesTopBand = ((float)VoxelBox.Max.Z >= TopZ - Thickness) && ((float)VoxelBox.Min.Z <= TopZ);
|
||||
const bool bTouchesBotBand = ((float)VoxelBox.Min.Z <= BotZ + Thickness) && ((float)VoxelBox.Max.Z >= BotZ);
|
||||
@@ -2100,6 +2113,10 @@ namespace
|
||||
*/
|
||||
EVoxelTileClass ClassifyBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsXYEdgeSealOff())
|
||||
{
|
||||
return EVoxelTileClass::Mixed;
|
||||
}
|
||||
return VF_XYEdgeSealBoxIsForcedSolid(
|
||||
VoxelBox, Ctx.WorldRadiusVoxels, Ctx.EdgeSealThickness, Base)
|
||||
? EVoxelTileClass::AllSolid : EVoxelTileClass::Mixed;
|
||||
@@ -2114,6 +2131,10 @@ namespace
|
||||
// In the inner world it is Identity; a box that reaches the radial band can only gain rock.
|
||||
EVoxelOpEffect EffectOverBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsXYEdgeSealOff())
|
||||
{
|
||||
return EVoxelOpEffect::Identity;
|
||||
}
|
||||
return VF_XYEdgeSealBoxTouchesBand(
|
||||
VoxelBox, Ctx.WorldRadiusVoxels, Ctx.EdgeSealThickness)
|
||||
? EVoxelOpEffect::FillOnly : EVoxelOpEffect::Identity;
|
||||
@@ -2177,29 +2198,39 @@ namespace
|
||||
EVoxelOpEffect EffectOverBox(const FBox& VoxelBox,
|
||||
const FVoxelOpContext& Ctx) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsPassageCarvingOff()
|
||||
&& VoxelDensityAblation::IsLandingPostsOff()
|
||||
&& VoxelDensityAblation::IsPassageStructuralPostsOff()
|
||||
&& VoxelDensityAblation::IsOriginSpineOff())
|
||||
{
|
||||
return EVoxelOpEffect::Identity;
|
||||
}
|
||||
const UVoxelStrateManager* LiveManager = Manager.Get();
|
||||
if (!LiveManager) { return EVoxelOpEffect::Identity; }
|
||||
const bool bOriginFloor = Ctx.bUseLatticeProof
|
||||
? VoxelPassageGeometry::OriginLandingFloorTouchesLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step,
|
||||
TopZ, BotZ, Seal, SpineRadius)
|
||||
: VoxelPassageGeometry::OriginLandingFloorTouchesBox(
|
||||
VoxelBox, TopZ, BotZ, Seal, SpineRadius);
|
||||
const bool bPassageFloor = Ctx.bUseLatticeProof
|
||||
? LiveManager->AnyPassageLandingFloorNearLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step)
|
||||
: LiveManager->AnyPassageLandingFloorNearBox(
|
||||
VoxelBox.Min, VoxelBox.Max);
|
||||
const bool bOriginFloor = !VoxelDensityAblation::IsLandingPostsOff()
|
||||
&& (Ctx.bUseLatticeProof
|
||||
? VoxelPassageGeometry::OriginLandingFloorTouchesLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step,
|
||||
TopZ, BotZ, Seal, SpineRadius)
|
||||
: VoxelPassageGeometry::OriginLandingFloorTouchesBox(
|
||||
VoxelBox, TopZ, BotZ, Seal, SpineRadius));
|
||||
const bool bPassageFloor = !VoxelDensityAblation::IsLandingPostsOff()
|
||||
&& (Ctx.bUseLatticeProof
|
||||
? LiveManager->AnyPassageLandingFloorNearLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step)
|
||||
: LiveManager->AnyPassageLandingFloorNearBox(
|
||||
VoxelBox.Min, VoxelBox.Max));
|
||||
if (bOriginFloor || bPassageFloor)
|
||||
{
|
||||
// The room carves air, while its support slab force-writes solid. Both
|
||||
// hypotheses must therefore be killed for a box touching that slab.
|
||||
return EVoxelOpEffect::Both;
|
||||
}
|
||||
const bool bPassageCarve = Ctx.bUseLatticeProof
|
||||
? LiveManager->AnyPassageNearLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step)
|
||||
: LiveManager->AnyPassageNearBox(VoxelBox.Min, VoxelBox.Max);
|
||||
const bool bPassageCarve = !VoxelDensityAblation::IsPassageCarvingOff()
|
||||
&& (Ctx.bUseLatticeProof
|
||||
? LiveManager->AnyPassageNearLattice(
|
||||
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step)
|
||||
: LiveManager->AnyPassageNearBox(VoxelBox.Min, VoxelBox.Max));
|
||||
return bPassageCarve
|
||||
? EVoxelOpEffect::CarveOnly : EVoxelOpEffect::Identity;
|
||||
}
|
||||
@@ -2212,6 +2243,10 @@ namespace
|
||||
float MaxCarveOverBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx,
|
||||
const FVoxelBoxHypotheses& H) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsPassageCarvingOff())
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
const UVoxelStrateManager* LiveManager = Manager.Get();
|
||||
if (!LiveManager) { return 0.0f; }
|
||||
if (!Ctx.bUseLatticeProof)
|
||||
@@ -3917,6 +3952,10 @@ namespace
|
||||
bool TryGetLastTunnelCoreWorldEvaluation(
|
||||
FTunnelCoreWorldEvaluation& OutEvaluation) const override
|
||||
{
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FState& S = State();
|
||||
if (!S.bLastTunnelCoreWorldEvaluationValid
|
||||
|| S.LastTunnelCoreEvaluationPosition != S.LastWorldPosition)
|
||||
@@ -4078,7 +4117,7 @@ namespace
|
||||
// un « frame » : sa portée est exactement UN opérateur, donc elle appartient à cet
|
||||
// opérateur.
|
||||
float WarpedX = WorldX, WarpedY = WorldY, WarpedZ = EffectiveZ;
|
||||
if (P.CaveWarpStrength > 0.0f)
|
||||
if (!VoxelDensityAblation::IsCaveWarpOff() && P.CaveWarpStrength > 0.0f)
|
||||
{
|
||||
const float WF = P.CaveWarpFrequency;
|
||||
const float WS = P.CaveWarpStrength;
|
||||
@@ -4308,68 +4347,77 @@ namespace
|
||||
// mais à des coordonnées NON warpées. Sous un modèle de frames il aurait fallu les sortir
|
||||
// du frame tout en gardant le canal — exprimable, mais tordu. Dans un opérateur unique la
|
||||
// difficulté disparaît : le warp est une variable locale, pas un contexte hérité.
|
||||
auto EvaluatePit = [&](int32 PitIndex)
|
||||
if (!VoxelDensityAblation::IsPitChimneySDFOff())
|
||||
{
|
||||
const FCachedPit& Pit = GetCache().Pits[PitIndex];
|
||||
const float DZ = WorldZ - Pit.TopZ;
|
||||
if (DZ >= Pit.BlendK) { return; }
|
||||
if (-DZ > Pit.Depth + Pit.BlendK) { return; }
|
||||
|
||||
const float DX = WorldX - Pit.CenterX;
|
||||
const float DY = WorldY - Pit.CenterY;
|
||||
const float XYDistSq = DX * DX + DY * DY;
|
||||
if (XYDistSq > Pit.BoundXYRadiusSq) { return; }
|
||||
|
||||
float PitSDF;
|
||||
if (DZ <= 0.0f)
|
||||
auto EvaluatePit = [&](int32 PitIndex)
|
||||
{
|
||||
const float DepthBelow = -DZ;
|
||||
float FlareFactor = FMath::Clamp(1.0f - DepthBelow / Pit.FlareDist, 0.0f, 1.0f);
|
||||
FlareFactor = FlareFactor * FlareFactor;
|
||||
const float EffRadius = Pit.Radius + Pit.FlareExtra * FlareFactor;
|
||||
PitSDF = FMath::Sqrt(XYDistSq) - EffRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
PitSDF = FMath::Sqrt(XYDistSq) - (Pit.Radius + Pit.FlareExtra);
|
||||
}
|
||||
const FCachedPit& Pit = GetCache().Pits[PitIndex];
|
||||
const float DZ = WorldZ - Pit.TopZ;
|
||||
if (DZ >= Pit.BlendK) { return; }
|
||||
if (-DZ > Pit.Depth + Pit.BlendK) { return; }
|
||||
|
||||
CaveSDF = VoxelSDF::SmoothMin(CaveSDF, PitSDF, Pit.BlendK);
|
||||
};
|
||||
VF_ForEachChunkSDFSpatialCandidate(
|
||||
GetCache().PitSpatialIndex, GetCache().Pits.Num(),
|
||||
WorldX, WorldY, EvaluatePit, bUseSpatialIndex);
|
||||
const float DX = WorldX - Pit.CenterX;
|
||||
const float DY = WorldY - Pit.CenterY;
|
||||
const float XYDistSq = DX * DX + DY * DY;
|
||||
if (XYDistSq > Pit.BoundXYRadiusSq) { return; }
|
||||
|
||||
auto EvaluateChimney = [&](int32 ChimneyIndex)
|
||||
float PitSDF;
|
||||
if (DZ <= 0.0f)
|
||||
{
|
||||
const float DepthBelow = -DZ;
|
||||
float FlareFactor = FMath::Clamp(1.0f - DepthBelow / Pit.FlareDist, 0.0f, 1.0f);
|
||||
FlareFactor = FlareFactor * FlareFactor;
|
||||
const float EffRadius = Pit.Radius + Pit.FlareExtra * FlareFactor;
|
||||
PitSDF = FMath::Sqrt(XYDistSq) - EffRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
PitSDF = FMath::Sqrt(XYDistSq) - (Pit.Radius + Pit.FlareExtra);
|
||||
}
|
||||
|
||||
CaveSDF = VoxelSDF::SmoothMin(CaveSDF, PitSDF, Pit.BlendK);
|
||||
};
|
||||
if (!VoxelDensityAblation::IsPitChimneySDFOff())
|
||||
{
|
||||
const FCachedChimney& Chim = GetCache().Chimneys[ChimneyIndex];
|
||||
const float DZ = WorldZ - Chim.BottomZ;
|
||||
if (-DZ >= Chim.BlendK) { return; }
|
||||
if (DZ > Chim.Height + Chim.BlendK) { return; }
|
||||
VF_ForEachChunkSDFSpatialCandidate(
|
||||
GetCache().PitSpatialIndex, GetCache().Pits.Num(),
|
||||
WorldX, WorldY, EvaluatePit, bUseSpatialIndex);
|
||||
}
|
||||
|
||||
const float DX = WorldX - Chim.CenterX;
|
||||
const float DY = WorldY - Chim.CenterY;
|
||||
const float XYDistSq = DX * DX + DY * DY;
|
||||
if (XYDistSq > Chim.BoundXYRadiusSq) { return; }
|
||||
|
||||
float ChmSDF;
|
||||
if (DZ >= 0.0f)
|
||||
auto EvaluateChimney = [&](int32 ChimneyIndex)
|
||||
{
|
||||
float FlareFactor = FMath::Clamp(1.0f - DZ / Chim.FlareDist, 0.0f, 1.0f);
|
||||
FlareFactor = FlareFactor * FlareFactor;
|
||||
const float EffRadius = Chim.Radius + Chim.FlareExtra * FlareFactor;
|
||||
ChmSDF = FMath::Sqrt(XYDistSq) - EffRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChmSDF = FMath::Sqrt(XYDistSq) - (Chim.Radius + Chim.FlareExtra);
|
||||
}
|
||||
const FCachedChimney& Chim = GetCache().Chimneys[ChimneyIndex];
|
||||
const float DZ = WorldZ - Chim.BottomZ;
|
||||
if (-DZ >= Chim.BlendK) { return; }
|
||||
if (DZ > Chim.Height + Chim.BlendK) { return; }
|
||||
|
||||
CaveSDF = VoxelSDF::SmoothMin(CaveSDF, ChmSDF, Chim.BlendK);
|
||||
};
|
||||
VF_ForEachChunkSDFSpatialCandidate(
|
||||
GetCache().ChimneySpatialIndex, GetCache().Chimneys.Num(),
|
||||
WorldX, WorldY, EvaluateChimney, bUseSpatialIndex);
|
||||
const float DX = WorldX - Chim.CenterX;
|
||||
const float DY = WorldY - Chim.CenterY;
|
||||
const float XYDistSq = DX * DX + DY * DY;
|
||||
if (XYDistSq > Chim.BoundXYRadiusSq) { return; }
|
||||
|
||||
float ChmSDF;
|
||||
if (DZ >= 0.0f)
|
||||
{
|
||||
float FlareFactor = FMath::Clamp(1.0f - DZ / Chim.FlareDist, 0.0f, 1.0f);
|
||||
FlareFactor = FlareFactor * FlareFactor;
|
||||
const float EffRadius = Chim.Radius + Chim.FlareExtra * FlareFactor;
|
||||
ChmSDF = FMath::Sqrt(XYDistSq) - EffRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChmSDF = FMath::Sqrt(XYDistSq) - (Chim.Radius + Chim.FlareExtra);
|
||||
}
|
||||
|
||||
CaveSDF = VoxelSDF::SmoothMin(CaveSDF, ChmSDF, Chim.BlendK);
|
||||
};
|
||||
if (!VoxelDensityAblation::IsPitChimneySDFOff())
|
||||
{
|
||||
VF_ForEachChunkSDFSpatialCandidate(
|
||||
GetCache().ChimneySpatialIndex, GetCache().Chimneys.Num(),
|
||||
WorldX, WorldY, EvaluateChimney, bUseSpatialIndex);
|
||||
}
|
||||
}
|
||||
|
||||
InOut.Sdf = CaveSDF;
|
||||
|
||||
@@ -4378,40 +4426,46 @@ namespace
|
||||
// build-time ownership now so the stack can preserve the authored support through its
|
||||
// remaining modifiers without a second floor-writing pass. TryGet... below reuses the
|
||||
// exact same cached result for the generator's post-disturbance hand-off.
|
||||
const FTunnelSupportFloorColumn* SupportColumn = GetSupportColumn(
|
||||
S.LastWorldPosition);
|
||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, GetCache(), SupportColumn,
|
||||
bUseSpatialIndex);
|
||||
S.LastTunnelCoreEvaluationPosition = S.LastWorldPosition;
|
||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||
if (S.LastTunnelCoreWorldEvaluation.bSupportFloor
|
||||
|| S.LastTunnelCoreWorldEvaluation.bRoomFloor)
|
||||
if (!VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
const float StructuralFloorMinimumDensity =
|
||||
FMath::Max(P.BaseDensity * 2.0f, 1.0f);
|
||||
if (VoxelMath::IsFinite(StructuralFloorMinimumDensity)
|
||||
&& StructuralFloorMinimumDensity > 0.0f)
|
||||
const FTunnelSupportFloorColumn* SupportColumn = GetSupportColumn(
|
||||
S.LastWorldPosition);
|
||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, GetCache(), SupportColumn,
|
||||
bUseSpatialIndex);
|
||||
S.LastTunnelCoreEvaluationPosition = S.LastWorldPosition;
|
||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||
if (S.LastTunnelCoreWorldEvaluation.bSupportFloor
|
||||
|| S.LastTunnelCoreWorldEvaluation.bRoomFloor)
|
||||
{
|
||||
InOut.bProtectedStructuralFloor = true;
|
||||
InOut.StructuralFloorMinimumDensity = StructuralFloorMinimumDensity;
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
const float StructuralFloorMinimumDensity =
|
||||
FMath::Max(P.BaseDensity * 2.0f, 1.0f);
|
||||
if (VoxelMath::IsFinite(StructuralFloorMinimumDensity)
|
||||
&& StructuralFloorMinimumDensity > 0.0f)
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelAuthoredFloorSamples);
|
||||
InOut.bProtectedStructuralFloor = true;
|
||||
InOut.StructuralFloorMinimumDensity = StructuralFloorMinimumDensity;
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelAuthoredFloorSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These are the per-sample hand-offs needed by an op-major block. The scalar path
|
||||
// continues to use FState directly; publishing them here only makes the dependency
|
||||
// explicit for a later modifier and does not alter Density/Sdf.
|
||||
InOut.bHasTunnelCoreWorldEvaluation = true;
|
||||
InOut.TunnelCoreWorldSDF = S.LastTunnelCoreWorldEvaluation.SDF;
|
||||
InOut.bTunnelCoreSupportFloor = S.LastTunnelCoreWorldEvaluation.bSupportFloor;
|
||||
InOut.bTunnelCoreRoomFloor = S.LastTunnelCoreWorldEvaluation.bRoomFloor;
|
||||
}
|
||||
|
||||
// These are the per-sample hand-offs needed by an op-major block. The scalar path
|
||||
// continues to use FState directly; publishing them here only makes the dependency
|
||||
// explicit for a later modifier and does not alter Density/Sdf.
|
||||
// These cache hand-offs remain valid when tunnel core is off; detail operators still
|
||||
// need the room graph and nearest-room ownership.
|
||||
InOut.RoomCache = &GetCache();
|
||||
InOut.NearestRoomIndex = S.NearestRoom;
|
||||
InOut.bHasTunnelCoreWorldEvaluation = true;
|
||||
InOut.TunnelCoreWorldSDF = S.LastTunnelCoreWorldEvaluation.SDF;
|
||||
InOut.bTunnelCoreSupportFloor = S.LastTunnelCoreWorldEvaluation.bSupportFloor;
|
||||
InOut.bTunnelCoreRoomFloor = S.LastTunnelCoreWorldEvaluation.bRoomFloor;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
@@ -5418,7 +5472,7 @@ namespace
|
||||
&& P.VerticalScale != 1.0f)
|
||||
? WorldZ / P.VerticalScale : WorldZ;
|
||||
FVector Query(WorldX, WorldY, EffectiveZ);
|
||||
if (P.CaveWarpStrength > 0.0f)
|
||||
if (!VoxelDensityAblation::IsCaveWarpOff() && P.CaveWarpStrength > 0.0f)
|
||||
{
|
||||
const float Frequency = P.CaveWarpFrequency;
|
||||
Query.X += VoxelNoise::Perlin3D(
|
||||
@@ -8543,9 +8597,6 @@ namespace
|
||||
FWormFieldSource(const FStrateGenerationParams& InP, int32 Seed)
|
||||
: P(InP)
|
||||
, SeedU((uint32)Seed)
|
||||
, WormLatticeStep(
|
||||
InP.WormStrength > 0.0f && InP.WormThreshold > 0.0f
|
||||
? VoxelWormField::GetLatticeStep() : 0)
|
||||
{}
|
||||
|
||||
EVoxelOpRole GetRole() const override { return EVoxelOpRole::FieldSource; }
|
||||
@@ -8585,7 +8636,7 @@ namespace
|
||||
SeedU};
|
||||
const float WormValue = VoxelWormField::Evaluate(
|
||||
WorldX, WorldY, WorldZ, P.WormThreshold,
|
||||
WormParameters, WormLatticeStep);
|
||||
WormParameters);
|
||||
if (WormValue < P.WormThreshold)
|
||||
{
|
||||
const float t = 1.0f - (WormValue / P.WormThreshold);
|
||||
@@ -8656,9 +8707,7 @@ namespace
|
||||
// explicit count cap keeps this check bounded. The network mask still uses the SDF
|
||||
// interval's worst case, so this never assumes a room value that the preceding source
|
||||
// did not prove.
|
||||
if (VoxelWormField::GetNoiseMode() == 0
|
||||
&& WormLatticeStep <= 1
|
||||
&& Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
|
||||
if (Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
|
||||
&& VoxelMath::IsFinite(P.WormFrequency)
|
||||
&& VoxelMath::IsFinite(P.WormHorizontalBias)
|
||||
&& VoxelMath::IsFinite(P.WormThreshold)
|
||||
@@ -8778,7 +8827,6 @@ namespace
|
||||
private:
|
||||
FStrateGenerationParams P;
|
||||
uint32 SeedU;
|
||||
int32 WormLatticeStep = 0;
|
||||
};
|
||||
|
||||
#if WITH_EDITOR
|
||||
@@ -9722,6 +9770,8 @@ namespace VoxelDensityOps
|
||||
// `Sdf < SDFBlendRadius·3` via VF_NearCaveSurface. Voir la note de l'étape B5 là-bas.
|
||||
// L'ORDRE EST CELUI DE L'ORIGINAL et il compte : chacun lit la densité que le précédent
|
||||
// a laissée (le biais de sol est un ajout indépendant appliqué à cette accumulation).
|
||||
if (!VoxelDensityAblation::IsDetailOpsOff())
|
||||
{
|
||||
OutStack.Add(MakeUnique<FCaveRoughnessMod>(P, Seed)); // 4b
|
||||
OutStack.Add(MakeUnique<FCaveTerraceMod>(P, Seed, RoomPtr)); // 4c — terrasses
|
||||
OutStack.Add(MakeUnique<FLayerLineMod>(P, RoomPtr)); // 4c — lignes de strates
|
||||
@@ -9734,6 +9784,7 @@ namespace VoxelDensityOps
|
||||
OutStack.Add(MakeUnique<FDomeMod>(P, RoomPtr)); // 4g — dômes
|
||||
OutStack.Add(MakeUnique<FPinchMod>(P, RoomPtr)); // 4h — pincement
|
||||
OutStack.Add(MakeUnique<FFloorBiasMod>(P, RoomPtr)); // fin 4h — biais de sol
|
||||
}
|
||||
if (P.WormStrength > 0.0f && P.WormThreshold > 0.0f)
|
||||
{
|
||||
OutStack.Add(MakeUnique<FWormFieldSource>(P, Seed));
|
||||
|
||||
Reference in new issue
Block a user