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:
Fr0zkaandClaude Opus 5 committed 2026-09-14 08:19:50 +02:00
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);