feat(worms): asset-owned worm off switch; offline stack symboliser -- cheap-worm default to be reverted
Worms round (Codex; reviewed by me against its report and PERF-SAMPLED.md).
Part 1, a real off switch: UVoxelStrateDefinition::bEnableWorms (default true, so existing assets
are unchanged). It is deliberately not in FStrateGenerationParams, so the 83-field memo-key guard
is untouched. It resolves after composer candidates, season vectors and boundary blending, is
included in the generation fingerprint, and clamps composer overrides, so a roll cannot re-enable
it. With strength 0 the fused path skips the worm block, the op-stack builder omits the worm
source, and the interval/classifier paths do no worm work. Proof: disabled == hand-zeroed control
byte for byte (70D310A4, 74,672 triangles), capability 20,856 / 10,917, connected, zero worm rows
in the symbolised sampler. voxel.WormsForceOff is a dev-only, world-changing measurement
override, included in the fingerprint.
Part 0: the sampler writes a module map (733 modules, identity checked), and a post-exit
offline symboliser (VoxelStackOfflineSymbolizer, editor module) rebuilds the all-LOD / LOD0 /
LOD1+ exclusive / inclusive / source-line tables. A planted cost was found (5 named rows) and then
removed. DbgHelp still never runs in the measured process.
Part 2, "cheap worms": FAILED to deliver, and the default is wrong. No candidate was faster:
lattice-2/4 gave no gain, and value noise was within noise static and ~2.1% WORSE in moving worker
seconds. Yet this commit carries voxel.WormNoiseMode=1 (value noise) as the default, a field change
(29/64 test tiles) with no benefit, selected after value-noise variants were tried until one
passed capability (three were rejected at 20,821-20,828). The next round reverts the default to
exact Perlin (mode 0) and removes the no-gain world-changing experiment modes.
The finding that matters: disabling worms entirely (WormsForceOff A/B, two interleaved runs each)
saves only ~2.5% static and ~3.4% moving worker time. The sampler's "worm line
VoxelGenerator.cpp:3985 = 19.4% of LOD0" was a misattribution of inlined noise code to one PDB
line. Line-level attribution of inlined code must be confirmed by ablation before a round targets
it. That is why the worm block skip (26b3476) found nothing.
Runs: the full ledger is in PERF-SAMPLED.md. Failures: one moving wrapper hit the graceful-close
timeout and was rerun; the first offline-symboliser commandlet hit the DDC no-writable-nodes fatal
(crash folder UECC-...CE75ACD5, 08:01) and was retried with the writable Saved\DDC.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
1 parent
11f0c1335b
commit
c132243b30
15 files changed
+2406
-552
No files matched your search
@@ -26,6 +26,7 @@
|
||||
#include "VoxelGenerator.h" // VoxelGenLOD::Eff
|
||||
#include "VoxelHeightOp.h" // FVoxelHeightStack — SurfaceWorld's two height stacks
|
||||
#include "VoxelNoise.h" // VoxelNoise::FBM
|
||||
#include "VoxelWormField.h"
|
||||
#include "VoxelStrateDefinition.h" // TerrainOperations — le pool que BuildChunkCache tire par salle
|
||||
#include "VoxelTerrainOpDefinition.h" // ApplyTo — l'override d'op PAR SALLE (étape C1)
|
||||
#include "VoxelStrateManager.h" // EvaluateModifierSDF / AnyPassageNearBox
|
||||
@@ -8540,7 +8541,12 @@ namespace
|
||||
{
|
||||
public:
|
||||
FWormFieldSource(const FStrateGenerationParams& InP, int32 Seed)
|
||||
: P(InP), SeedU((uint32)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; }
|
||||
EVoxelOpChannelMask ChannelReads() const override
|
||||
@@ -8555,8 +8561,6 @@ namespace
|
||||
{
|
||||
if (!(P.WormStrength > 0.0f && P.WormThreshold > 0.0f)) { return; }
|
||||
|
||||
const float EffectiveZ = (P.VerticalScale != 1.0f && P.VerticalScale > 0.0f)
|
||||
? (WorldZ / P.VerticalScale) : WorldZ;
|
||||
const float CaveSDF = InOut.Sdf;
|
||||
|
||||
float NetworkMask = 1.0f;
|
||||
@@ -8574,25 +8578,14 @@ namespace
|
||||
|
||||
if (NetworkMask <= 0.0f) { return; }
|
||||
|
||||
const float WormZFreq = P.WormFrequency * P.WormHorizontalBias;
|
||||
|
||||
const float N1 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
|
||||
WorldX * P.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.0f),
|
||||
WorldY * P.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.7f),
|
||||
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(SeedU, 2.3f)
|
||||
)) * VOXEL_NOISE_SCALE);
|
||||
|
||||
// N2 ≥ 0, donc si N1 dépasse déjà le seuil la somme ne peut plus creuser — on saute le
|
||||
// second Perlin (le cas courant ; sortie bit-identique). Transcrit tel quel.
|
||||
if (N1 >= P.WormThreshold) { return; }
|
||||
|
||||
const float N2 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
|
||||
WorldX * P.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.0f) + 137.0f,
|
||||
WorldY * P.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.7f) + 259.0f,
|
||||
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(SeedU, 2.3f) + 431.0f
|
||||
)) * VOXEL_NOISE_SCALE);
|
||||
|
||||
const float WormValue = N1 + N2;
|
||||
const VoxelWormField::FParameters WormParameters{
|
||||
P.WormFrequency,
|
||||
P.WormHorizontalBias,
|
||||
P.VerticalScale,
|
||||
SeedU};
|
||||
const float WormValue = VoxelWormField::Evaluate(
|
||||
WorldX, WorldY, WorldZ, P.WormThreshold,
|
||||
WormParameters, WormLatticeStep);
|
||||
if (WormValue < P.WormThreshold)
|
||||
{
|
||||
const float t = 1.0f - (WormValue / P.WormThreshold);
|
||||
@@ -8663,7 +8656,9 @@ 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 (Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
|
||||
if (VoxelWormField::GetNoiseMode() == 0
|
||||
&& WormLatticeStep <= 1
|
||||
&& Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
|
||||
&& VoxelMath::IsFinite(P.WormFrequency)
|
||||
&& VoxelMath::IsFinite(P.WormHorizontalBias)
|
||||
&& VoxelMath::IsFinite(P.WormThreshold)
|
||||
@@ -8783,6 +8778,7 @@ namespace
|
||||
private:
|
||||
FStrateGenerationParams P;
|
||||
uint32 SeedU;
|
||||
int32 WormLatticeStep = 0;
|
||||
};
|
||||
|
||||
#if WITH_EDITOR
|
||||
@@ -9738,7 +9734,10 @@ 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
|
||||
OutStack.Add(MakeUnique<FWormFieldSource>(P, Seed));
|
||||
if (P.WormStrength > 0.0f && P.WormThreshold > 0.0f)
|
||||
{
|
||||
OutStack.Add(MakeUnique<FWormFieldSource>(P, Seed));
|
||||
}
|
||||
|
||||
if (bAppendStructuralPosts)
|
||||
{
|
||||
@@ -10324,6 +10323,14 @@ bool VF_BuildStackFromRecipe(const FVoxelOpStackRecipe& Recipe,
|
||||
|
||||
for (const FVoxelOpRecipeEntry& Entry : Recipe.Modifiers)
|
||||
{
|
||||
if (Entry.OpClass == EVoxelStrateOpClass::WormFieldSource
|
||||
&& !(Params.TunnelNetworkParams.WormStrength > 0.0f
|
||||
&& Params.TunnelNetworkParams.WormThreshold > 0.0f))
|
||||
{
|
||||
// A disabled strate has no worm operator at all. This makes the off switch cheap on
|
||||
// the interpreted path as well as exact in its interval/classifier fold.
|
||||
continue;
|
||||
}
|
||||
TUniquePtr<IVoxelDensityOp> Modifier =
|
||||
VoxelStrateRecipePrivate::BuildRecipeOp(Entry, Params, Seed, SpineRadius,
|
||||
StrateManager, RoomPtr, ShaftPtr);
|
||||
|
||||
Reference in new issue
Block a user