perf(generation): exact worm block skip with a proven 3D Perlin bound -- measured NEUTRAL

The sampler put the worm carve's first noise call (VoxelGenerator.cpp:3985, FusedWorm) at 19.4% of
LOD0. The worm only carves where N1 + N2 < T with N2 >= 0, so where N1 >= T it contributes nothing,
bit for bit. A block proven to have N1 >= T everywhere can skip both noise calls exactly.

- The Lipschitz bound for this Perlin3D implementation: L = (15/4) * sqrt(3) * 1.25 = 8.118988160,
  in scaled-N1 units, with a 1e-3 float-rounding margin. Adversarial sampling found a worst ratio
  of 3.187 (0.39 L). The existing 2D floor-relief bound (8.5) is a component bound of a different
  field and was confirmed not to transfer.
- A soundness test that can fail (VoxelForgeWormBlockSkipTest): 6,476 proved blocks, 355,945 exact
  lattice samples, 0 violations. A deliberately halved L proves a bad block; the full L rejects it.
- voxel.WormBlockSkip, default 1.

Field exact: export OBJ byte-identical (b3e5f4c3..9b377), 841/841 keyed tiles identical to
NextHeadStaticTrace_20260913, capability 20,830 / 10,909.

RESULT, stated plainly: no measurable speed gain. The skip rate is 4.07% of worm-eligible LOD0
samples and 0% at LOD1-4, because the bound is ~2.5x looser than the worst observed ratio at the
block size used. Paired on-vs-off, two interleaved runs each: static worker +2.15%, generation p50
+1.8%; moving worker -1.42%, request p50 -2.5%. Within noise. The next round turns the default OFF.
The proven bound and its test are kept for a tighter skip later (smaller or hierarchical blocks,
or a per-cell bound).

Run ledger (from Codex's report): the first build failed on an ambiguous test overload and was
fixed; two timing runs are void because the orchestrator stopped the session so the owner could
use the PC; the eight valid timing runs, the sampler run and the diagnostics runs completed. No
new crash folders. PERF-SAMPLED.md now lists all eight earlier-round UECC crash records.

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 04:29:11 +02:00
1 parent 5489b5e311
commit 26b34765d5
9 files changed
+972 -9

No files matched your search

+10
View File
@@ -580,6 +580,16 @@ driven by `EditorBrush*` props.
no loads AND no LOD mismatches outstanding.
- **SDF cache** (`GetDensityWithParams`): search-BOX validity, not chunk-key — gradient ±1
sampling must not thrash the (expensive) rebuild.
- **Worm block skip** (`VF_TryGetWormBlockSkip`): inside the unchanged `WormNetworkRange` mask,
a worker-local direct-indexed cache covers the mesher's 4×4×4 lattice blocks (including the
normal halo). It samples N1 once at the transformed block centre and proves the entire block
clears the threshold with the actual 3D hash-gradient field bound
`L = (15/4) * sqrt(3) * VOXEL_NOISE_SCALE = 8.118988160`, plus a `1e-3` scaled-output
rounding margin. The radius is measured after the exact `WormFrequency`, `VerticalScale`, and
`WormHorizontalBias` transform, so anisotropic Z is included. The cache is thread-local and
keyed by generator owner, seed, params/layout fingerprint, tile origin, step, lattice size, and
worm parameters; malformed/non-lattice/failed proofs fall through. A proof only suppresses N1
and N2 because N2 is nonnegative; it never changes `NetworkMask` or density arithmetic.
- **Operator channel metadata** (`FVoxelOpStack`): `ChannelReads`, `ChannelWrites`, and
`IsAdditive` are called only when an operator is added to a stack and their values are cached in
the stack entry. `ValidateChannelOrder` is assembly/diagnostic-only; no declaration virtual may
+6 -2
View File
@@ -341,7 +341,7 @@ This is **where terrain shape lives.**
| `ApplyPassageCarving` (static) | 197 | Punches passages/elevator through the seal. |
| `InitializeSettings` | 211 | Copies the effective seed, spine radius, and global XY world-bound settings from `UVoxelSettings` (the season owns all three when assigned); radius 0 preserves the unbounded field. |
| **`GetDensityAt`** | 218 | **Entry point.** Picks strate + generator type, materialises a cooked-season recipe on the existing per-chunk refetch when present, dispatches, then adds disturbances/diff. Its `CP_*` state is keyed by `(DensityCacheOwnerId, ChunkCoord, LayoutVersion)`; workers copy immutable recipe/vector data and never read editor composer state. |
| **`GetDensityWithParams`** | 277 | TunnelNetwork pipeline (~1000 lines). See §4. ⚠️ Takes **required** `ParamsFingerprint` + `LayoutVersion` since the AUDIT §C2 fix (2026-07-28) — they go into the SDF cache key so a chunk can no longer be evaluated against a neighbour's rooms. Callers compute the CRC **once per chunk** (`CP_TunnelFP`), never per voxel. |
| **`GetDensityWithParams`** | 277 | TunnelNetwork pipeline (~1000 lines). See §4. ⚠️ Takes **required** `ParamsFingerprint` + `LayoutVersion` since the AUDIT §C2 fix (2026-07-28) — they go into the SDF cache key so a chunk can no longer be evaluated against a neighbour's rooms. Callers compute the CRC **once per chunk** (`CP_TunnelFP`), never per voxel. The optional `voxel.WormBlockSkip` path uses `VF_TryGetWormBlockSkip` + a worker-local 4³ lattice-block cache to prove `|N1| >= WormThreshold` and remove both worm noise calls only; it never changes `NetworkMask` or the fallback field path. |
| **`GetSlabDensity`** | 1306 | FlatPlain/CrystalChamber pipeline. See §4.2. |
| `SampleSurfaceStructuralZ` | — | **F20:** the RAW SurfaceWorld heightfield (continents+mountains+detail), BEFORE any terrain op; returns terrain Z + relief M. Cliff re-samples it at an XY offset for a cheap analytic slope. |
| `ComputeSurfaceTerrainZ` / `GetSurfaceDensity` | — | SurfaceWorld heightfield → terrain Z, then density; biome **output-blend** lerps dominant/neighbour heights (`ParamsD`/`ParamsN`/weight). **F20 surface ops** (`FSurfaceGenerationParams`, biome-selected + slope/relief-conditioned, all default off): Cliff (slope-gated STEEPENING — push height from local mean where steep ⇒ sheer walls; 4 structural resamples only when on), Terrace (relief-gated + `TerraceHardness`), LayerLines (sedimentary shelves) — pure per-column height REMAPS applied here so the single height oracle stays consistent (MC/sheets/ClassifyTile/deco/BP bridge). **Phase 2 OVERHANG** (volumetric — real jutting shelves): in `SurfaceDensityFromColumn`, for AIR voxels in a window `(TerrainZ, TerrainZ+OverhangHeight]` above a steep slope, the heightfield is re-sampled UPHILL (toward the cliff) by a reach that GROWS with height (tiny low ⇒ air over the void, full high ⇒ borrows the far cliff rock) and unioned in ⇒ a shelf attached to the cliff, tapering out over the void with air beneath (the sketch). Per-column `OverhangAmp`(=strength·slope-gate) + unit uphill `(DirX,DirY)` resolved once in `ComputeSurfaceColumn` (gradient sampled at the REACH scale so a spot over the void can see the cliff), cached on `FSurfaceColumn`. Genuine 3D (per-voxel structural re-eval, gated to steep overhang columns). Off ⇒ byte-identical. The field-preserving LOD0 pass removes only needless temporaries/default construction; every output remains bit-identical. §8.14. |
@@ -359,7 +359,11 @@ This is **where terrain shape lives.**
> memoizes the strate index per (chunkZ, `GetLayoutVersion()`); `thread_local` per-cell lattice
> bakes cover slab columns (`GetSlabDensity` step 4), maze open edges, vertical shafts +
> cross-connectors, floating-island constants, and the disturbance chasms/bridges/ridges; worm
> tunnels short-circuit the 2nd Perlin when N1 ≥ WormThreshold (N2 ≥ 0 ⇒ can't carve). Room
> tunnels short-circuit the 2nd Perlin when N1 ≥ WormThreshold (N2 ≥ 0 ⇒ can't carve). With
> `voxel.WormBlockSkip=1`, a worker-local cache proves whole 4³ lattice blocks only when the
> actual 3D Perlin bound (`L = 8.118988160`, including `VOXEL_NOISE_SCALE`) plus a `1e-3`
> output-rounding margin clears the threshold; failed proofs use the original per-sample path.
> Room
> shapes are pre-baked in `FCachedRoom` (§3.7). **T2.b:** per-voxel fractal call sites take their
> octave count through `VoxelGenLOD::Eff(N)` (VoxelGenerator.h) — a `thread_local` bias set per
> tile by the mesher drops tail octaves on coarse tiles (opt-in `LODOctaveDrop`, default 0 = off);
+172
View File
@@ -928,3 +928,175 @@ Smaller unresolved groups map to `UnrealEditor-Engine.dll + RVA 0x500947` (gener
This closes the actionable part of candidate 5: the previous plugin constructor was removed, while
the remaining unknown is an engine-symbolisation limitation. No commit, push, or stash was performed.
## Worm block skip round (2026-09-14)
### Proof and gates
The worm skip is enabled by default through `voxel.WormBlockSkip=1`. It is fail-closed and only
removes the two worm noise calls after the unchanged `WormNetworkRange` mask has passed. The
worker-local cache is keyed by generator owner, seed, params/layout fingerprint, tile origin,
step, lattice size, and worm parameters; it is never shared across tiles or workers.
For this implementation's actual `GradDot` set, the unique gradients are
`(±1,±1,0)`, `(±1,0,±1)`, and `(0,±1,±1)`. The exact finite-support partial-derivative relaxation
with `Fade'(t)=30t²(1-t)²` has supremum `15/4`, attained at `(0.5,0.5,0.5)`. Therefore the
noise-space vector bound is
`L = (15/4) * sqrt(3) * VOXEL_NOISE_SCALE = 8.118988160` (`VOXEL_NOISE_SCALE=1.25`).
The existing 2D floor constant was proven differently and does not transfer: its comment uses
the loose component bound `[-1,1]`, four-edge interpolation difference bound, and
`max SmoothCurve' = 1.875`, giving `1 + 4*1.875 = 8.5` per partial. The worm derives its
bound from the actual 3D gradient support. The block radius is measured after the exact X/Y/Z
noise transform, including `WormFrequency`, `VerticalScale`, and `WormHorizontalBias`; `Abs` is
1-Lipschitz and the positive noise scale is included in `L`. A `1e-3` scaled-output margin is
subtracted before the threshold comparison. It is deliberately much larger than the accumulated
float rounding at the center/radius operations and is covered by the soundness test.
The adversarial attack used dense corner/face sampling plus random pairs: 17,365,280 pairs,
worst scaled ratio `3.187330411`, or `0.392577295*L`. The fail-capable automation test also
audited 6,476 proved blocks over 355,945 exact lattice samples with zero violations. A deliberately
halved `L` proves the negative-control block while the exact point has `N1=0.011259466 < 0.015`
and the full `L` rejects it.
Default-on export is byte-identical to the baseline: geometry hash
`B3E5F4C398DD0547C6C55F415872058246D4A292C2F0D636EE1CD0829DE9B377`, 82,273 vertices,
153,346 triangles. The static trace is 841/841 keyed tiles with zero field/empty/triangle
differences. Capability remains 20,830 / 10,909.
### Clean game A/B
Sampler off, diagnostics off, `voxel.OuterClassifierMode=0`, interleaved static and moving runs.
Static runs had 343 LOD0 ready samples; moving runs had 1,274. All valid runs had identical
applied geometry totals, zero validation calls, zero obsolete worker tasks, and verified the loaded
plugin module. The clean timings below used the staged runtime before the final counter-only
diagnostic-accounting rebuild (`81F52389A78543E41EEC8E3E40DEF8F2634A79EB83E2A933FF35EE42CD611E12`).
That patch is behind diagnostics, so it does not change this clean path. The final staged runtime
used by the last diagnostic run is `E72E140100B3D258F28E9DBA19CD95D379D98794DA49D24C708FDD01B5B5FE08`.
| run | switch | request p50/p95 (s) | generation p50/p95 (s) | worker s |
|---|---|---:|---:|---:|
| WormSkipGameOffStaticA_20260914 | off | 0.087151 / 0.150116 | 0.063115 / 0.104426 | 33.308914 |
| WormSkipGameOnStaticA_Resume_20260914 | on | 0.092174 / 0.154458 | 0.065730 / 0.110507 | 34.980771 |
| WormSkipGameOffMovingA_20260914 | off | 0.066421 / 0.138179 | 0.059918 / 0.108181 | 99.193222 |
| WormSkipGameOnMovingA_20260914 | on | 0.064163 / 0.135519 | 0.059273 / 0.106991 | 97.624292 |
| WormSkipGameOffStaticB_20260914 | off | 0.090372 / 0.160169 | 0.064016 / 0.109362 | 34.116813 |
| WormSkipGameOnStaticB_Resume_20260914 | on | 0.091922 / 0.154718 | 0.063731 / 0.112871 | 33.892686 |
| WormSkipGameOffMovingB_Resume_20260914 | off | 0.066659 / 0.142168 | 0.061916 / 0.110043 | 100.995082 |
| WormSkipGameOnMovingB_Resume_20260914 | on | 0.065557 / 0.141592 | 0.060515 / 0.110629 | 99.716139 |
Paired means, on relative to off:
| mode | request p50/p95 | generation p50/p95 | worker s | on vs off worker |
|---|---:|---:|---:|---:|
| static | off 0.088762 / 0.155143; on 0.092048 / 0.154588 | off 0.063566 / 0.106894; on 0.064731 / 0.111689 | 33.712864 → 34.436729 | +2.1471% |
| moving | off 0.066540 / 0.140174; on 0.064860 / 0.138556 | off 0.060917 / 0.109112; on 0.059894 / 0.108810 | 100.094152 → 98.670216 | −1.4226% |
The two-run result is mixed: moving improves modestly, while static is within ordinary run noise
and is slightly worse on worker sum. The switch remains default-on because the field proof is exact;
the timing result is not presented as a universal speed claim.
### Skip rate
The final diagnostics-enabled moving run used the final DLL and emitted 2,360 tile profiles. The
rate is `worm_block_skipped / worm_eligible`, not a fraction of all density samples:
| LOD | worm-eligible samples | successful block proofs | skipped eligible samples | skip rate |
|---:|---:|---:|---:|---:|
| 0 | 12,381,885 | 9,541 | 503,696 | 4.068007% |
| 1 | 4,821,000 | 0 | 0 | 0.000000% |
| 2 | 188,063 | 0 | 0 | 0.000000% |
| 3 | 58,276 | 0 | 0 | 0.000000% |
| 4 | 25,253 | 0 | 0 | 0.000000% |
### Sampler-on moving profile
`WormSkipGameOnMovingSampler_20260914` retained 96,649 samples with zero drops and zero capture
failures: 61,869 LOD0 and 34,780 LOD1+. It ran for 24.972305 s; resolved-frame fraction was
52.9174%, unknown-frame fraction 47.0826%, wait-like fraction 0.1011%, and resolved-leaf
fraction 95.3388%.
LOD0 exclusive top 20:
| # | samples | % | leaf |
|---:|---:|---:|---|
| 1 | 12472 | 20.1587 | `GetDensityWithParams` — `VoxelGenerator.cpp:3128` |
| 2 | 3137 | 5.0704 | `GetDensityAt` — `VoxelGenerator.cpp:2994` |
| 3 | 2853 | 4.6114 | unknown |
| 4 | 2540 | 4.1054 | `Sqrt` |
| 5 | 2238 | 3.6173 | `VoxelSDF::SmoothMin` — `VoxelCaveMorphology.h:170` |
| 6 | 1736 | 2.8059 | `VF_ProjectNativePassageFloorUncached` — `VoxelStrateManager.cpp:561` |
| 7 | 1704 | 2.7542 | `FChunkSDFSpatialIndex::GetRange` — `VoxelCaveMorphology.cpp:1356` |
| 8 | 1434 | 2.3178 | `VF_ProjectTunnelSegmentXY` — `VoxelCaveMorphology.cpp:970` |
| 9 | 1244 | 2.0107 | `ProjectWalkableTunnelFloor` — `VoxelPassageGeometry.h:338` |
| 10 | 1229 | 1.9865 | `VF_EvaluateSweptTunnelChain` — `VoxelCaveMorphology.cpp:1128` |
| 11 | 1151 | 1.8604 | `EvaluateTunnelCoreWorld` lambda — `VoxelCaveMorphology.cpp:7635` |
| 12 | 1009 | 1.6309 | swept-chain lambda — `VoxelCaveMorphology.cpp:1074` |
| 13 | 938 | 1.5161 | `EvaluateSDFCached` lambda — `VoxelCaveMorphology.cpp:7526` |
| 14 | 819 | 1.3238 | `IsFiniteFast` — `VoxelTypes.h:30` |
| 15 | 769 | 1.2429 | `IsFinite` — `VoxelTypes.h:47` |
| 16 | 764 | 1.2349 | `EvaluateModifierSDF` — `VoxelStrateManager.cpp:2451` |
| 17 | 748 | 1.2090 | `VF_EvaluatePassageLandingSDF` — `VoxelCaveMorphology.cpp:5673` |
| 18 | 739 | 1.1945 | `GenerateMesh` — `VoxelMarchingCubesMesher.cpp:578` |
| 19 | 724 | 1.1702 | `FScopedTimer::End` — `VoxelDensityProfile.h:435` |
| 20 | 700 | 1.1314 | `VF_DistanceSquaredToAabb` — `VoxelCaveMorphology.cpp:74` |
LOD0 inclusive top 20:
| # | samples | % | inclusive function |
|---:|---:|---:|---|
| 1 | 61869 | 100.0000 | `Invoke` |
| 2 | 61869 | 100.0000 | `LowLevelTasks::FTask::Init` lambda |
| 3 | 61869 | 100.0000 | `LowLevelTasks::TTaskDelegate::Call` |
| 4 | 61869 | 100.0000 | `UE::Tasks::Private::FTaskBase::Init` lambda |
| 5 | 61869 | 100.0000 | `LowLevelTasks::TTaskDelegate::CallAndMove` |
| 6 | 61869 | 100.0000 | `UE::Tasks::Private::FTaskBase::TryExecuteTask` |
| 7 | 61869 | 100.0000 | `TExecutableTaskBase::ExecuteTask` |
| 8 | 61869 | 100.0000 | `AVoxelWorld::LoadTile` lambda — `VoxelWorld.cpp:3782` |
| 9 | 61869 | 100.0000 | `AVoxelWorld::GenerateTileResult` — `VoxelWorld.cpp:4142` |
| 10 | 61774 | 99.8464 | `GenerateMesh` — `VoxelMarchingCubesMesher.cpp:578` |
| 11 | 60310 | 97.4802 | `GetDensityAt` — `VoxelGenerator.cpp:2606` |
| 12 | 38073 | 61.5381 | `GetDensityWithParams` — `VoxelGenerator.cpp:3426` |
| 13 | 15666 | 25.3212 | `VF_ForEachSpatialCandidate` — `VoxelCaveMorphology.cpp:1570` |
| 14 | 9775 | 15.7995 | `EvaluateSDFCached` — `VoxelCaveMorphology.cpp:7484` |
| 15 | 7846 | 12.6816 | `VF_EvaluateSweptTunnel` — `VoxelCaveMorphology.cpp:1167` |
| 16 | 7460 | 12.0577 | `VF_EvaluateSweptTunnelChain` — `VoxelCaveMorphology.cpp:1128` |
| 17 | 7276 | 11.7603 | `ApplyPassageCarvingOnly` — `VoxelStrateManager.cpp:2596` |
| 18 | 7209 | 11.6520 | `EvaluateTunnelCoreWorld` — `VoxelCaveMorphology.cpp:7732` |
| 19 | 7128 | 11.5211 | `VF_ApplyPassageCarving` — `VoxelDensityPrimitives.h:75` |
| 20 | 7106 | 11.4856 | `EvaluateModifierSDF` — `VoxelStrateManager.cpp:2538` |
### Run ledger
Every worm-round launch is listed here, including invalidated launches and the compile retry:
| launch | outcome |
|---|---|
| Initial staged build | Failed compiling `VoxelForgeWormBlockSkipTest.cpp` because of an ambiguous `FMath::IsNearlyEqual` overload; fixed by an explicit cast. No Unreal process was launched. |
| Rebuilt staged plugin | Succeeded; final build log reports `Result: Succeeded`. |
| `VoxelForge.Determinism.WormBlockSkipSoundness` | Passed: 6,476 proofs / 355,945 lattice samples / 0 violations; halved-L control fails as intended. |
| `WormSkipFieldOn_20260914` | Passed; export byte-identical and loaded module verified. |
| `WormSkipStaticTrace_20260914` | Data passed 841/841; harness intentionally stopped the process after `.done` (`ExitCode=-1`), not a crash. |
| `WormSkipCapability_20260914` | Passed; capability 20,830 / 10,909. |
| `WormSkipGameOffStaticA_20260914` | Completed; valid off A. |
| `WormSkipGameOnStaticA_20260914` | Launched before the stop; void by owner instruction and excluded, even though a complete artifact exists. |
| `WormSkipGameOffMovingA_20260914` | Completed; valid on/off interleave partner. |
| `WormSkipGameOnMovingA_20260914` | Completed; valid on/off interleave partner. |
| `WormSkipGameOffStaticB_20260914` | Completed; valid off B. |
| `WormSkipGameOnStaticB_20260914` | Interrupted at the stop; partial module/RSS artifacts only, void and excluded. |
| `WormSkipGameOnStaticA_Resume_20260914` | Completed; valid on A replacement. |
| `WormSkipGameOffMovingB_Resume_20260914` | Completed; valid off B replacement. |
| `WormSkipGameOnMovingB_Resume_20260914` | Completed; valid on B replacement. |
| `WormSkipGameOnStaticB_Resume_20260914` | Completed; valid on B replacement. |
| `WormSkipGameOnMovingSampler_20260914` | Completed; sampler-on moving profile, zero drops/failures. |
| `WormSkipDiagnosticsMoving_20260914` | Completed; superseded by the final counter-semantics diagnostic run, not used for reported skip rates. |
| `WormSkipDiagnosticsMovingProofs_20260914` | Completed on final DLL; per-LOD skip rates above, module verified. |
The Saved crash inventory also contains earlier-round UECC artifacts, which are kept visible here:
three failed `Task4CurrentTracePIE` attempts on 2026-09-09 (plugin-manager/ShaderCore/DDC launch
failures), `GameMovingOn_20260913` (fatal shutdown), `MemoGameStaticOffA_20260913` (no writable
DDC graph; retried successfully), `TakeoverFinalMovingSamplerOnHost_20260913` (crash artifact;
`...Host2` retry succeeded), `Final3MovingSamplerOn_20260913` (fatal shutdown), and
`IsFiniteExact_20260913` (no writable DDC graph). No CrashReportClient crash occurred in the
worm-round launches above.
@@ -0,0 +1,350 @@
// Soundness and empirical coverage for the worker-local worm N1 block proof.
#if WITH_DEV_AUTOMATION_TESTS
#include "Misc/AutomationTest.h"
#include "VoxelCaveMorphology.h"
#include "VoxelNoise.h"
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FVoxelForgeWormBlockSkipTest,
"VoxelForge.Determinism.WormBlockSkipSoundness",
EAutomationTestFlags_ApplicationContextMask | EAutomationTestFlags::EngineFilter)
namespace
{
constexpr float WormFrequency = 0.015f;
constexpr float WormHorizontalBias = 3.0f;
constexpr float WormThreshold = 0.06f;
constexpr float WormVerticalScale = 1.0f;
constexpr int32 TestCellsPerAxis = 32;
constexpr int32 TestTileCount = 192;
constexpr int32 TestRandomPairCount = 500000;
FORCEINLINE uint32 NextTestBits(uint32& State)
{
State += 0x9E3779B9u;
uint32 Z = State;
Z = (Z ^ (Z >> 16)) * 0x7FEB352Du;
Z = (Z ^ (Z >> 15)) * 0x846CA68Bu;
return Z ^ (Z >> 16);
}
FORCEINLINE float NextTestUnit(uint32& State)
{
return static_cast<float>(NextTestBits(State)) / 4294967296.0f;
}
FORCEINLINE float ScaledN1(const FVector3f& Position)
{
return FMath::Abs(VoxelNoise::Perlin3D(Position) * VOXEL_NOISE_SCALE);
}
FORCEINLINE FVector3f MakeWormNoisePosition(
int32 WorldX, int32 WorldY, int32 WorldZ, uint32 Seed)
{
float EffectiveZ = static_cast<float>(WorldZ);
if (WormVerticalScale != 1.0f && WormVerticalScale > 0.0f)
{
EffectiveZ /= WormVerticalScale;
}
const float WormZFreq = WormFrequency * WormHorizontalBias;
return FVector3f(
static_cast<float>(WorldX) * WormFrequency
+ VoxelHash::SeedOffset(Seed, 1.0f),
static_cast<float>(WorldY) * WormFrequency
+ VoxelHash::SeedOffset(Seed, 1.7f),
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(Seed, 2.3f));
}
FORCEINLINE double FadePrime(double T)
{
return 30.0 * T * T * (1.0 - T) * (1.0 - T);
}
FORCEINLINE double GradientSupport(double X, double Y, double Z)
{
const double AX = FMath::Abs(X);
const double AY = FMath::Abs(Y);
const double AZ = FMath::Abs(Z);
return FMath::Max(FMath::Max(AX + AY, AX + AZ), AY + AZ);
}
// Supremum of the exact finite support relaxation used in the header derivation. This is
// intentionally independent of the hash: all eight corners may choose any member of the
// actual GradDot set, so this is the field-wide proof envelope rather than an average sample.
double SupportRelaxedXDerivative(double X, double Y, double Z)
{
const double D = FadePrime(X);
const double SY = Y * Y * Y * (Y * (Y * 6.0 - 15.0) + 10.0);
const double SZ = Z * Z * Z * (Z * (Z * 6.0 - 15.0) + 10.0);
double Result = 0.0;
for (int32 J = 0; J < 2; ++J)
{
for (int32 K = 0; K < 2; ++K)
{
const double Weight = (J != 0 ? SY : 1.0 - SY)
* (K != 0 ? SZ : 1.0 - SZ);
const double YLocal = Y - static_cast<double>(J);
const double ZLocal = Z - static_cast<double>(K);
Result += Weight * (
GradientSupport(1.0 - X - D * X, -D * YLocal, -D * ZLocal)
+ GradientSupport(X - D * (1.0 - X), D * YLocal, D * ZLocal));
}
}
return Result;
}
}
bool FVoxelForgeWormBlockSkipTest::RunTest(const FString& Parameters)
{
(void)Parameters;
const double FullL = VoxelNoise::WormN1NoiseSpaceLipschitzBound;
const double HalfL = FullL * 0.5;
TestTrue(TEXT("the production N1 Lipschitz bound is finite and positive"),
FMath::IsFinite(FullL) && FullL > 0.0);
TestTrue(TEXT("the actual 3D partial bound is 15/4"),
FMath::IsNearlyEqual(VoxelNoise::Perlin3DPartialAbsBound, 3.75, 1.0e-12));
TestTrue(TEXT("VOXEL_NOISE_SCALE is included in the N1 bound"),
FMath::IsNearlyEqual(
FullL,
static_cast<double>(VOXEL_NOISE_SCALE)
* VoxelNoise::Perlin3DPartialAbsBound
* static_cast<double>(1.732050807568877293527446341505872L),
1.0e-12));
// Check the finite support maximization densely, including corners and every cell face. The
// closed-form case split is recorded beside the production constant; this grid is a regression
// tripwire for changing GradDot/Fade/Lerp without updating that proof.
double MaxRelaxedSupport = 0.0;
FVector3f MaxRelaxedPoint = FVector3f::ZeroVector;
constexpr int32 SupportGrid = 128;
for (int32 IX = 0; IX <= SupportGrid; ++IX)
{
const double X = static_cast<double>(IX) / SupportGrid;
for (int32 IY = 0; IY <= SupportGrid; ++IY)
{
const double Y = static_cast<double>(IY) / SupportGrid;
for (int32 IZ = 0; IZ <= SupportGrid; ++IZ)
{
const double Z = static_cast<double>(IZ) / SupportGrid;
const double Value = SupportRelaxedXDerivative(X, Y, Z);
if (Value > MaxRelaxedSupport)
{
MaxRelaxedSupport = Value;
MaxRelaxedPoint = FVector3f(
static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z));
}
}
}
}
AddInfo(FString::Printf(
TEXT("3D support relaxation max=%.12f at (%.6f,%.6f,%.6f), bound=%.12f; "
"the exact case split gives 15/4 at (0.5,0.5,0.5)."),
MaxRelaxedSupport, MaxRelaxedPoint.X, MaxRelaxedPoint.Y, MaxRelaxedPoint.Z,
VoxelNoise::Perlin3DPartialAbsBound));
TestTrue(TEXT("the dense support relaxation stays below the proven partial bound"),
MaxRelaxedSupport <= VoxelNoise::Perlin3DPartialAbsBound + 1.0e-10);
TestTrue(TEXT("the support relaxation reaches the stated supremum"),
MaxRelaxedSupport >= VoxelNoise::Perlin3DPartialAbsBound - 1.0e-10);
// Empirical attack: samples straddle lattice faces/corners at several scales, then a large
// deterministic random-pair population probes ordinary cells and arbitrary directions.
double MaxEmpiricalRatio = 0.0;
FVector3f WorstA = FVector3f::ZeroVector;
FVector3f WorstB = FVector3f::ZeroVector;
uint64 PairCount = 0;
auto ObservePair = [&](const FVector3f& A, const FVector3f& B)
{
const double DX = static_cast<double>(A.X) - static_cast<double>(B.X);
const double DY = static_cast<double>(A.Y) - static_cast<double>(B.Y);
const double DZ = static_cast<double>(A.Z) - static_cast<double>(B.Z);
const double Distance = FMath::Sqrt(DX * DX + DY * DY + DZ * DZ);
if (!(Distance > 0.0))
{
return;
}
++PairCount;
const double Ratio = FMath::Abs(
static_cast<double>(ScaledN1(A)) - static_cast<double>(ScaledN1(B))) / Distance;
if (Ratio > MaxEmpiricalRatio)
{
MaxEmpiricalRatio = Ratio;
WorstA = A;
WorstB = B;
}
};
constexpr float FaceEpsilons[] = { 1.0e-5f, 1.0e-4f, 1.0e-3f, 1.0e-2f, 5.0e-2f };
constexpr float FaceCoordinates[] = {
1.0e-3f, 1.0e-2f, 0.1f, 0.25f, 0.5f, 0.75f, 0.9f, 0.99f, 0.999f };
for (int32 X = -12; X < 12; ++X)
{
for (int32 Y = -12; Y < 12; ++Y)
{
for (int32 Z = -12; Z < 12; ++Z)
{
for (const float Epsilon : FaceEpsilons)
{
for (const float V : FaceCoordinates)
{
for (const float W : FaceCoordinates)
{
ObservePair(
FVector3f(X + 1.0f - Epsilon, Y + V, Z + W),
FVector3f(X + 1.0f + Epsilon, Y + V, Z + W));
ObservePair(
FVector3f(X + V, Y + 1.0f - Epsilon, Z + W),
FVector3f(X + V, Y + 1.0f + Epsilon, Z + W));
ObservePair(
FVector3f(X + V, Y + W, Z + 1.0f - Epsilon),
FVector3f(X + V, Y + W, Z + 1.0f + Epsilon));
}
}
ObservePair(
FVector3f(X + 1.0f - Epsilon, Y + 1.0f - Epsilon, Z + 1.0f - Epsilon),
FVector3f(X + 1.0f + Epsilon, Y + 1.0f + Epsilon, Z + 1.0f + Epsilon));
}
}
}
}
uint32 RandomState = 0xA5B3571Du;
for (int32 Index = 0; Index < TestRandomPairCount; ++Index)
{
const FVector3f A(
NextTestUnit(RandomState) * 128.0f - 64.0f,
NextTestUnit(RandomState) * 128.0f - 64.0f,
NextTestUnit(RandomState) * 128.0f - 64.0f);
const FVector3f B(
A.X + NextTestUnit(RandomState) * 0.5f - 0.25f,
A.Y + NextTestUnit(RandomState) * 0.5f - 0.25f,
A.Z + NextTestUnit(RandomState) * 0.5f - 0.25f);
ObservePair(A, B);
}
AddInfo(FString::Printf(
TEXT("Empirical scaled-N1 Lipschitz attack: pairs=%llu worst=%.9f, worst/L=%.9f, "
"L=%.9f; worst A=(%.6f,%.6f,%.6f) B=(%.6f,%.6f,%.6f)."),
static_cast<unsigned long long>(PairCount), MaxEmpiricalRatio,
MaxEmpiricalRatio / FullL, FullL,
WorstA.X, WorstA.Y, WorstA.Z, WorstB.X, WorstB.Y, WorstB.Z));
TestTrue(TEXT("empirical near-face/corner/random ratios stay below L"),
MaxEmpiricalRatio <= FullL + 0.01);
// Brute-force the exact mesher lattice for a large deterministic set of tile contexts. Every
// block admitted by the production proof is checked at every lattice point it covers.
uint64 BlocksScanned = 0;
uint64 ProductionProofs = 0;
uint64 ProductionLatticeSamples = 0;
uint64 ProductionViolations = 0;
for (int32 TileIndex = 0; TileIndex < TestTileCount; ++TileIndex)
{
const FIntVector TileOrigin(
(TileIndex % 17 - 8) * 64,
((TileIndex / 17) % 13 - 6) * 64,
((TileIndex / 221) % 9 - 4) * 64);
const uint32 Seed = 1337u + static_cast<uint32>(TileIndex) * 0x9E3779B9u;
for (int32 BlockZ = 0; BlockZ < 9; ++BlockZ)
{
for (int32 BlockY = 0; BlockY < 9; ++BlockY)
{
for (int32 BlockX = 0; BlockX < 9; ++BlockX)
{
++BlocksScanned;
const int32 MinX = BlockX * VoxelNoise::WormBlockSampleSide - 1;
const int32 MinY = BlockY * VoxelNoise::WormBlockSampleSide - 1;
const int32 MinZ = BlockZ * VoxelNoise::WormBlockSampleSide - 1;
const int32 MaxX = FMath::Min(
TestCellsPerAxis + 1,
MinX + VoxelNoise::WormBlockSampleSide - 1);
const int32 MaxY = FMath::Min(
TestCellsPerAxis + 1,
MinY + VoxelNoise::WormBlockSampleSide - 1);
const int32 MaxZ = FMath::Min(
TestCellsPerAxis + 1,
MinZ + VoxelNoise::WormBlockSampleSide - 1);
const FVector3f Q0 = MakeWormNoisePosition(
TileOrigin.X + MinX, TileOrigin.Y + MinY, TileOrigin.Z + MinZ, Seed);
const FVector3f Q1 = MakeWormNoisePosition(
TileOrigin.X + MaxX, TileOrigin.Y + MaxY, TileOrigin.Z + MaxZ, Seed);
const FVector3f QMin(
FMath::Min(Q0.X, Q1.X), FMath::Min(Q0.Y, Q1.Y), FMath::Min(Q0.Z, Q1.Z));
const FVector3f QMax(
FMath::Max(Q0.X, Q1.X), FMath::Max(Q0.Y, Q1.Y), FMath::Max(Q0.Z, Q1.Z));
const FVector3f QCenter(
static_cast<float>((static_cast<double>(QMin.X) + QMax.X) * 0.5),
static_cast<float>((static_cast<double>(QMin.Y) + QMax.Y) * 0.5),
static_cast<float>((static_cast<double>(QMin.Z) + QMax.Z) * 0.5));
if (!VoxelNoise::ProvesScaledAbsPerlin3DAbove(
QCenter, QMin, QMax, WormThreshold, FullL))
{
continue;
}
++ProductionProofs;
for (int32 Z = MinZ; Z <= MaxZ; ++Z)
{
for (int32 Y = MinY; Y <= MaxY; ++Y)
{
for (int32 X = MinX; X <= MaxX; ++X)
{
++ProductionLatticeSamples;
const float ExactN1 = ScaledN1(MakeWormNoisePosition(
TileOrigin.X + X, TileOrigin.Y + Y, TileOrigin.Z + Z, Seed));
if (ExactN1 < WormThreshold)
{
++ProductionViolations;
}
}
}
}
}
}
}
}
AddInfo(FString::Printf(
TEXT("Production block audit: tiles=%d blocks=%llu proofs=%llu lattice_samples=%llu "
"violations=%llu, side=%d, threshold=%.6f."),
TestTileCount, static_cast<unsigned long long>(BlocksScanned),
static_cast<unsigned long long>(ProductionProofs),
static_cast<unsigned long long>(ProductionLatticeSamples),
static_cast<unsigned long long>(ProductionViolations),
VoxelNoise::WormBlockSampleSide, WormThreshold));
TestTrue(TEXT("the production-bound block audit found at least one proof"),
ProductionProofs > 0);
TestEqual(TEXT("every production-bound proof is sound on its exact lattice"),
ProductionViolations, static_cast<uint64>(0));
// Fail-capable negative control. This pair is from a real low-coordinate hash cell. Its exact
// scaled-N1 slope is above L/2; the threshold is selected between the two exact values, so a
// deliberately halved bound admits a proof that the second lattice point violates.
const FVector3f WitnessCenter(1510.5478515625f, 2191.43701171875f, 7279.404296875f);
const FVector3f WitnessPoint(1510.54931640625f, 2191.437255859375f, 7279.50390625f);
const FVector3f WitnessMin(
2.0f * WitnessCenter.X - WitnessPoint.X,
2.0f * WitnessCenter.Y - WitnessPoint.Y,
2.0f * WitnessCenter.Z - WitnessPoint.Z);
const FVector3f WitnessMax = WitnessPoint;
constexpr float WitnessThreshold = 0.015f;
const float WitnessCenterN1 = ScaledN1(WitnessCenter);
const float WitnessPointN1 = ScaledN1(WitnessPoint);
const bool bHalfProof = VoxelNoise::ProvesScaledAbsPerlin3DAbove(
WitnessCenter, WitnessMin, WitnessMax, WitnessThreshold, HalfL);
const bool bFullProof = VoxelNoise::ProvesScaledAbsPerlin3DAbove(
WitnessCenter, WitnessMin, WitnessMax, WitnessThreshold, FullL);
AddInfo(FString::Printf(
TEXT("Halved-L negative control: center_N1=%.9f point_N1=%.9f threshold=%.6f "
"half_proof=%d full_proof=%d."),
WitnessCenterN1, WitnessPointN1, WitnessThreshold,
bHalfProof ? 1 : 0, bFullProof ? 1 : 0));
TestTrue(TEXT("the deliberately halved L admits the negative-control block"), bHalfProof);
TestFalse(TEXT("the full L rejects the negative-control block"), bFullProof);
TestTrue(TEXT("the negative-control lattice point really violates N1 >= threshold"),
WitnessPointN1 < WitnessThreshold);
return true;
}
#endif // WITH_DEV_AUTOMATION_TESTS
@@ -688,6 +688,9 @@ namespace VoxelDensityProfile
case ECounter::FusedTunnelSamples: return TEXT("FusedTunnelSamples");
case ECounter::FusedTunnelDetailSamples: return TEXT("FusedTunnelDetailSamples");
case ECounter::FusedTunnelDetailSkipped: return TEXT("FusedTunnelDetailSkipped");
case ECounter::WormEligibleSamples: return TEXT("WormEligibleSamples");
case ECounter::WormBlockProofs: return TEXT("WormBlockProofs");
case ECounter::WormBlockSkippedSamples: return TEXT("WormBlockSkippedSamples");
case ECounter::OpBlockBuilds: return TEXT("OpBlockBuilds");
case ECounter::OpBlockSamples: return TEXT("OpBlockSamples");
case ECounter::OpBlockOperators: return TEXT("OpBlockOperators");
+311 -5
View File
@@ -85,6 +85,32 @@ namespace
}
}
// A proved N1-above-threshold block skips both worm noise calls. The switch is parsed once
// on the same scalar entry point as the other generation A/B switches; 0 is the exact legacy
// path, and 1 is the default after the proof/soundness test passes.
int32 GVoxelForgeWormBlockSkip = 1;
FAutoConsoleVariableRef CVarVoxelForgeWormBlockSkip(
TEXT("voxel.WormBlockSkip"),
GVoxelForgeWormBlockSkip,
TEXT("Skip worm N1/N2 when a worker-local noise-space block proof says N1 >= threshold."));
bool GVoxelForgeWormBlockSkipSwitchParsed = false;
void VF_ParseWormBlockSkipSwitch()
{
if (GVoxelForgeWormBlockSkipSwitchParsed)
{
return;
}
GVoxelForgeWormBlockSkipSwitchParsed = true;
int32 CommandLineValue = GVoxelForgeWormBlockSkip;
if (FParse::Value(
FCommandLine::Get(), TEXT("voxel.WormBlockSkip="), CommandLineValue))
{
GVoxelForgeWormBlockSkip = CommandLineValue;
}
GVoxelForgeWormBlockSkip = GVoxelForgeWormBlockSkip != 0 ? 1 : 0;
}
// A tile-sized cache window is the production default on the coarse paths where it wins.
// Keep the switches in the generator module so native and op-stack sources make the same A/B
// decision, including when a headless harness applies command-line CVars after module startup.
@@ -309,6 +335,257 @@ struct FSurfaceColumnCache
// donc un ClassifyTile qui rend Mixed laisse ses colonnes chaudes pour le GenerateMesh qui suit.
static thread_local FSurfaceColumnCache GSurfColCache;
//=============================================================================
// WORM N1 BLOCK PROOF (worker-local, scalar GetDensityAt hand-off)
//=============================================================================
// GenerateMesh installs TileOriginVoxels/SampleStep/TileCellsPerAxis around every density-grid
// fill. Keep the verdicts here, rather than in the mesher, because the scalar GetDensityAt path
// owns the actual worm call and is also used by standalone/classifier queries. The cache is
// thread_local, direct-indexed by the block coordinate, and invalidated by every field identity
// that can affect N1. A miss or an invalid context always returns false and therefore executes
// the old N1/N2 code.
namespace
{
constexpr int32 VF_WormBlockCacheAxis =
(CHUNK_SIZE + 3 + VoxelNoise::WormBlockSampleSide - 1)
/ VoxelNoise::WormBlockSampleSide;
constexpr int32 VF_WormBlockCacheEntryCount =
VF_WormBlockCacheAxis * VF_WormBlockCacheAxis * VF_WormBlockCacheAxis;
static_assert(VF_WormBlockCacheAxis == 9,
"The fixed worm block table must cover the 32-cell mesher lattice plus its halo.");
FORCEINLINE uint32 VF_FloatBits(float Value)
{
uint32 Bits = 0;
FMemory::Memcpy(&Bits, &Value, sizeof(Bits));
return Bits;
}
struct FWormBlockSkipEntry
{
bool bValid = false;
bool bSkip = false;
};
struct FWormBlockSkipCache
{
bool bContextValid = false;
uint64 OwnerId = 0;
uint32 Seed = 0;
uint32 ParamsFingerprint = 0xFFFFFFFFu;
uint32 LayoutVersion = 0xFFFFFFFFu;
FIntVector TileOrigin = FIntVector::ZeroValue;
int32 Step = 0;
int32 Cells = 0;
uint32 WormFrequencyBits = 0;
uint32 WormHorizontalBiasBits = 0;
uint32 WormThresholdBits = 0;
uint32 VerticalScaleBits = 0;
FWormBlockSkipEntry Entries[VF_WormBlockCacheEntryCount];
void SetContext(
uint64 InOwnerId, uint32 InSeed, uint32 InParamsFingerprint,
uint32 InLayoutVersion, const FIntVector& InTileOrigin,
int32 InStep, int32 InCells, const FStrateGenerationParams& Params)
{
const uint32 InWormFrequencyBits = VF_FloatBits(Params.WormFrequency);
const uint32 InWormHorizontalBiasBits = VF_FloatBits(Params.WormHorizontalBias);
const uint32 InWormThresholdBits = VF_FloatBits(Params.WormThreshold);
const uint32 InVerticalScaleBits = VF_FloatBits(Params.VerticalScale);
const bool bChanged =
!bContextValid
|| OwnerId != InOwnerId
|| Seed != InSeed
|| ParamsFingerprint != InParamsFingerprint
|| LayoutVersion != InLayoutVersion
|| TileOrigin != InTileOrigin
|| Step != InStep
|| Cells != InCells
|| WormFrequencyBits != InWormFrequencyBits
|| WormHorizontalBiasBits != InWormHorizontalBiasBits
|| WormThresholdBits != InWormThresholdBits
|| VerticalScaleBits != InVerticalScaleBits;
if (!bChanged)
{
return;
}
bContextValid = true;
OwnerId = InOwnerId;
Seed = InSeed;
ParamsFingerprint = InParamsFingerprint;
LayoutVersion = InLayoutVersion;
TileOrigin = InTileOrigin;
Step = InStep;
Cells = InCells;
WormFrequencyBits = InWormFrequencyBits;
WormHorizontalBiasBits = InWormHorizontalBiasBits;
WormThresholdBits = InWormThresholdBits;
VerticalScaleBits = InVerticalScaleBits;
FMemory::Memzero(Entries, sizeof(Entries));
}
};
static thread_local FWormBlockSkipCache GWormBlockSkipCache;
FORCEINLINE FVector3f VF_WormN1NoisePosition(
float WorldX, float WorldY, float WorldZ,
const FStrateGenerationParams& Params, uint32 SeedU)
{
float EffectiveZ = WorldZ;
if (Params.VerticalScale != 1.0f && Params.VerticalScale > 0.0f)
{
EffectiveZ = WorldZ / Params.VerticalScale;
}
const float WormZFreq = Params.WormFrequency * Params.WormHorizontalBias;
return FVector3f(
WorldX * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.0f),
WorldY * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.7f),
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(SeedU, 2.3f));
}
FORCEINLINE bool VF_TryGetWormBlockSkip(
uint64 OwnerId, uint32 SeedU, uint32 ParamsFingerprint, uint32 LayoutVersion,
float WorldX, float WorldY, float WorldZ,
const FStrateGenerationParams& Params, bool& bOutProofComputed)
{
bOutProofComputed = false;
// Point queries and malformed authored parameters stay on the exact original path. In
// particular, VerticalScale <= 0 has legacy "no division" semantics; declining the proof
// here avoids making a new promise for malformed data.
if (!FMath::IsFinite(WorldX) || !FMath::IsFinite(WorldY) || !FMath::IsFinite(WorldZ)
|| WorldX != FMath::FloorToFloat(WorldX)
|| WorldY != FMath::FloorToFloat(WorldY)
|| WorldZ != FMath::FloorToFloat(WorldZ)
|| !FMath::IsFinite(Params.WormFrequency)
|| !FMath::IsFinite(Params.WormHorizontalBias)
|| !FMath::IsFinite(Params.WormThreshold)
|| !FMath::IsFinite(Params.VerticalScale)
|| !(Params.WormThreshold > 0.0f)
|| !(Params.VerticalScale > 0.0f)
|| !FMath::IsFinite(Params.WormFrequency * Params.WormHorizontalBias))
{
return false;
}
const int32 Step = VoxelGenLOD::SampleStep;
const int32 Cells = VoxelGenLOD::TileCellsPerAxis;
if (Step <= 0 || Cells <= 0 || Cells > CHUNK_SIZE)
{
return false;
}
// FMath::RoundToInt is only reached after the finite/integer check and a range guard. The
// tile context itself is int32, so coordinates outside this range cannot belong to it.
constexpr float SafeInt32Min = -2147483008.0f;
constexpr float SafeInt32Max = 2147483008.0f;
if (WorldX < SafeInt32Min || WorldX > SafeInt32Max
|| WorldY < SafeInt32Min || WorldY > SafeInt32Max
|| WorldZ < SafeInt32Min || WorldZ > SafeInt32Max)
{
return false;
}
const int32 IX = FMath::RoundToInt(WorldX);
const int32 IY = FMath::RoundToInt(WorldY);
const int32 IZ = FMath::RoundToInt(WorldZ);
const FIntVector TileOrigin = VoxelGenLOD::TileOriginVoxels;
const int64 DX = static_cast<int64>(IX) - static_cast<int64>(TileOrigin.X);
const int64 DY = static_cast<int64>(IY) - static_cast<int64>(TileOrigin.Y);
const int64 DZ = static_cast<int64>(IZ) - static_cast<int64>(TileOrigin.Z);
if (DX % Step != 0 || DY % Step != 0 || DZ % Step != 0)
{
return false;
}
const int32 LocalX = static_cast<int32>(DX / Step);
const int32 LocalY = static_cast<int32>(DY / Step);
const int32 LocalZ = static_cast<int32>(DZ / Step);
const int32 MinLocalLattice = -1;
const int32 MaxLocalLattice = Cells + 1;
if (LocalX < MinLocalLattice || LocalX > MaxLocalLattice
|| LocalY < MinLocalLattice || LocalY > MaxLocalLattice
|| LocalZ < MinLocalLattice || LocalZ > MaxLocalLattice)
{
return false;
}
const int32 BlockX = (LocalX + 1) / VoxelNoise::WormBlockSampleSide;
const int32 BlockY = (LocalY + 1) / VoxelNoise::WormBlockSampleSide;
const int32 BlockZ = (LocalZ + 1) / VoxelNoise::WormBlockSampleSide;
if (BlockX < 0 || BlockX >= VF_WormBlockCacheAxis
|| BlockY < 0 || BlockY >= VF_WormBlockCacheAxis
|| BlockZ < 0 || BlockZ >= VF_WormBlockCacheAxis)
{
return false;
}
GWormBlockSkipCache.SetContext(
OwnerId, SeedU, ParamsFingerprint, LayoutVersion, TileOrigin, Step, Cells, Params);
FWormBlockSkipEntry& Entry = GWormBlockSkipCache.Entries[
(BlockZ * VF_WormBlockCacheAxis + BlockY) * VF_WormBlockCacheAxis + BlockX];
if (Entry.bValid)
{
return Entry.bSkip;
}
const int32 BlockMinX = BlockX * VoxelNoise::WormBlockSampleSide - 1;
const int32 BlockMinY = BlockY * VoxelNoise::WormBlockSampleSide - 1;
const int32 BlockMinZ = BlockZ * VoxelNoise::WormBlockSampleSide - 1;
const int32 BlockMaxX = FMath::Min(MaxLocalLattice,
BlockMinX + VoxelNoise::WormBlockSampleSide - 1);
const int32 BlockMaxY = FMath::Min(MaxLocalLattice,
BlockMinY + VoxelNoise::WormBlockSampleSide - 1);
const int32 BlockMaxZ = FMath::Min(MaxLocalLattice,
BlockMinZ + VoxelNoise::WormBlockSampleSide - 1);
const auto WorldAt = [Step, &TileOrigin](int32 Local, int32 Origin) -> int64
{
return static_cast<int64>(Origin) + static_cast<int64>(Local) * Step;
};
const int64 MinWorldX64 = WorldAt(BlockMinX, TileOrigin.X);
const int64 MinWorldY64 = WorldAt(BlockMinY, TileOrigin.Y);
const int64 MinWorldZ64 = WorldAt(BlockMinZ, TileOrigin.Z);
const int64 MaxWorldX64 = WorldAt(BlockMaxX, TileOrigin.X);
const int64 MaxWorldY64 = WorldAt(BlockMaxY, TileOrigin.Y);
const int64 MaxWorldZ64 = WorldAt(BlockMaxZ, TileOrigin.Z);
if (MinWorldX64 < MIN_int32 || MinWorldX64 > MAX_int32
|| MinWorldY64 < MIN_int32 || MinWorldY64 > MAX_int32
|| MinWorldZ64 < MIN_int32 || MinWorldZ64 > MAX_int32
|| MaxWorldX64 < MIN_int32 || MaxWorldX64 > MAX_int32
|| MaxWorldY64 < MIN_int32 || MaxWorldY64 > MAX_int32
|| MaxWorldZ64 < MIN_int32 || MaxWorldZ64 > MAX_int32)
{
return false;
}
const FVector3f Q0 = VF_WormN1NoisePosition(
static_cast<float>(static_cast<int32>(MinWorldX64)),
static_cast<float>(static_cast<int32>(MinWorldY64)),
static_cast<float>(static_cast<int32>(MinWorldZ64)), Params, SeedU);
const FVector3f Q1 = VF_WormN1NoisePosition(
static_cast<float>(static_cast<int32>(MaxWorldX64)),
static_cast<float>(static_cast<int32>(MaxWorldY64)),
static_cast<float>(static_cast<int32>(MaxWorldZ64)), Params, SeedU);
const FVector3f QMin(
FMath::Min(Q0.X, Q1.X), FMath::Min(Q0.Y, Q1.Y), FMath::Min(Q0.Z, Q1.Z));
const FVector3f QMax(
FMath::Max(Q0.X, Q1.X), FMath::Max(Q0.Y, Q1.Y), FMath::Max(Q0.Z, Q1.Z));
const FVector3f QCenter(
static_cast<float>((static_cast<double>(QMin.X) + static_cast<double>(QMax.X)) * 0.5),
static_cast<float>((static_cast<double>(QMin.Y) + static_cast<double>(QMax.Y)) * 0.5),
static_cast<float>((static_cast<double>(QMin.Z) + static_cast<double>(QMax.Z)) * 0.5));
Entry.bSkip = VoxelNoise::ProvesScaledAbsPerlin3DAbove(
QCenter, QMin, QMax, Params.WormThreshold,
VoxelNoise::WormN1NoiseSpaceLipschitzBound);
Entry.bValid = true;
bOutProofComputed = true;
return Entry.bSkip;
}
}
//=============================================================================
// FRACTAL NOISE (fBm — fractional Brownian motion)
//=============================================================================
@@ -1812,6 +2089,7 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_GetDensityAt);
VF_ParseFastIsFiniteSwitch();
VF_ParseFusedEvaluatorSwitch();
VF_ParseWormBlockSkipSwitch();
VoxelDensityProfile::FScopedTimer DensityProfileTimer(
VoxelDensityProfile::EBucket::GetDensityAt);
VoxelDensityProfile::FScopedTimer DensityPrologueTimer(
@@ -3980,9 +4258,36 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
if (NetworkMask > 0.0f)
{
float WormZFreq = Params.WormFrequency * Params.WormHorizontalBias;
const bool bCollectWormDiagnostics =
bCollectFusedDiagnostics && VoxelDensityProfile::AreCountersEnabled();
if (bCollectWormDiagnostics)
{
VoxelDensityProfile::AddCounter(
VoxelDensityProfile::ECounter::WormEligibleSamples);
}
float N1 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
bool bWormBlockProofComputed = false;
const bool bSkipWormBlock = GVoxelForgeWormBlockSkip != 0
&& VF_TryGetWormBlockSkip(
DensityCacheOwnerId, SeedU, ParamsFingerprint, LayoutVersion,
WorldX, WorldY, WorldZ, Params, bWormBlockProofComputed);
if (bWormBlockProofComputed && bSkipWormBlock && bCollectWormDiagnostics)
{
VoxelDensityProfile::AddCounter(
VoxelDensityProfile::ECounter::WormBlockProofs);
}
if (bSkipWormBlock)
{
if (bCollectWormDiagnostics)
{
VoxelDensityProfile::AddCounter(
VoxelDensityProfile::ECounter::WormBlockSkippedSamples);
}
}
else
{
const float WormZFreq = Params.WormFrequency * Params.WormHorizontalBias;
const float N1 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
WorldX * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.0f),
WorldY * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.7f),
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(SeedU, 2.3f)
@@ -3992,22 +4297,23 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
// skip the second Perlin entirely (most voxels; bit-identical output).
if (N1 < Params.WormThreshold)
{
float N2 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
const float N2 = FMath::Abs(VoxelNoise::Perlin3D(FVector3f(
WorldX * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.0f) + 137.0f,
WorldY * Params.WormFrequency + VoxelHash::SeedOffset(SeedU, 1.7f) + 259.0f,
EffectiveZ * WormZFreq + VoxelHash::SeedOffset(SeedU, 2.3f) + 431.0f
)) * VOXEL_NOISE_SCALE);
float WormValue = N1 + N2;
const float WormValue = N1 + N2;
if (WormValue < Params.WormThreshold)
{
float t = 1.0f - (WormValue / Params.WormThreshold);
const float t = 1.0f - (WormValue / Params.WormThreshold);
Density -= t * Params.WormStrength * NetworkMask;
}
}
}
}
}
FusedWormTimer.End();
+18 -2
View File
@@ -3860,6 +3860,16 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector
CycleDelta(VoxelDensityProfile::EBucket::RoomGraphBuild));
const double EvaluationSeconds = FMath::Max(
0.0, TileSeconds - CacheBuildSeconds);
const uint64 WormEligibleSamples = CounterDelta(
VoxelDensityProfile::ECounter::WormEligibleSamples);
const uint64 WormBlockProofs = CounterDelta(
VoxelDensityProfile::ECounter::WormBlockProofs);
const uint64 WormBlockSkippedSamples = CounterDelta(
VoxelDensityProfile::ECounter::WormBlockSkippedSamples);
const double WormBlockSkipRate = WormEligibleSamples > 0
? static_cast<double>(WormBlockSkippedSamples)
/ static_cast<double>(WormEligibleSamples)
: 0.0;
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeTileProfile] tile=(%d,%d,%d) level=%d step=%d cells=%d sheet=%d aborted=%d empty=%d "
"verdict=%d classify=%.6f mesh=%.6f streams=%.6f seconds=%.6f "
@@ -3876,7 +3886,9 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector
"cache_op_local=%llu cache_classifier_shared=%llu cache_classifier_local=%llu "
"cache_unknown=%llu room_candidates=%llu room_evaluated=%llu "
"tunnel_candidates=%llu tunnel_evaluated=%llu tunnel_core_candidates=%llu "
"tunnel_core_evaluated=%llu support_column_candidates=%llu"),
"tunnel_core_evaluated=%llu support_column_candidates=%llu "
"worm_eligible=%llu worm_block_proofs=%llu worm_block_skipped=%llu "
"worm_skip_rate=%.6f"),
Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level, Step, Cells,
bSheetTile ? 1 : 0, Result.bAborted ? 1 : 0,
Result.bEmpty ? 1 : 0, ClassifyVerdict, ClassifySeconds, MeshSeconds, StreamSeconds,
@@ -3918,7 +3930,11 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector
static_cast<unsigned long long>(CounterDelta(VoxelDensityProfile::ECounter::CaveTunnelEvaluated)),
static_cast<unsigned long long>(CounterDelta(VoxelDensityProfile::ECounter::TunnelCoreCandidates)),
static_cast<unsigned long long>(CounterDelta(VoxelDensityProfile::ECounter::TunnelCoreEvaluated)),
static_cast<unsigned long long>(CounterDelta(VoxelDensityProfile::ECounter::TunnelSupportColumnCandidates)));
static_cast<unsigned long long>(CounterDelta(VoxelDensityProfile::ECounter::TunnelSupportColumnCandidates)),
static_cast<unsigned long long>(WormEligibleSamples),
static_cast<unsigned long long>(WormBlockProofs),
static_cast<unsigned long long>(WormBlockSkippedSamples),
WormBlockSkipRate);
if (bProfileOps)
{
@@ -150,6 +150,9 @@ namespace VoxelDensityProfile
FusedTunnelSamples,
FusedTunnelDetailSamples,
FusedTunnelDetailSkipped,
WormEligibleSamples,
WormBlockProofs,
WormBlockSkippedSamples,
OpBlockBuilds,
OpBlockSamples,
OpBlockOperators,
+99
View File
@@ -30,6 +30,7 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelTypes.h"
#if !defined(VF_NOISE_USE_SIMD)
#if PLATFORM_ENABLE_VECTORINTRINSICS && PLATFORM_CPU_X86_FAMILY
@@ -141,6 +142,104 @@ FORCEINLINE float Perlin3D(const FVector3f& P)
return Perlin3D(P.X, P.Y, P.Z);
}
//=============================================================================
// LIPSCHITZ BOUND FOR THE ACTUAL 3D FIELD
//=============================================================================
// This is deliberately derived from the implementation above, rather than borrowed from a
// textbook Perlin constant. GradDot's h&15 table has the twelve UNNORMALIZED gradients
//
// (±1,±1,0), (±1,0,±1), (0,±1,±1)
//
// (the four duplicate selectors do not add any vectors). For one partial derivative, write the
// four x-edges of the trilinear interpolation as independent gradient pairs. With
// d = Fade'(x) = 30 x²(1-x)², each edge contributes the support of the actual gradient set at
//
// c0 = (1-x-dx, -dy, -dz), c1 = (x-d(1-x), dy, dz).
//
// The support is max(|a|+|b|, |a|+|c|, |b|+|c|), because every allowed gradient has exactly two
// non-zero ±1 components. Taking the four y/z edge weights and the exact fade derivative, a
// finite case split over those three support branches has supremum 15/4 on [0,1]^3 (attained at
// x=y=z=1/2). This maximization permits every corner hash to choose any member of the actual
// set, so it is an upper bound for every hash cell; it is also the supremum of that finite support
// relaxation, not the looser 1 + 4*max(Fade') = 8.5 bound used by the unrelated 2D floor relief.
//
// The vector bound below follows the same per-axis-bound × sqrt(dimension) method used by the
// floor-relief proof. Abs is 1-Lipschitz and VOXEL_NOISE_SCALE is positive, so the scaled N1
// field has this bound in noise-space coordinates. WormBlockSkip computes its radius after the
// anisotropic world->noise transform, so the HBias and VerticalScale factors are included there.
static constexpr double Perlin3DPartialAbsBound = 15.0 / 4.0;
static constexpr double Perlin3DGradientBound =
Perlin3DPartialAbsBound * 1.732050807568877293527446341505872L;
static constexpr double WormN1NoiseSpaceLipschitzBound =
static_cast<double>(VOXEL_NOISE_SCALE) * Perlin3DGradientBound;
// A four-point side gives the natural small worker-local blocks for the mesher's 35-point
// (32 cells + one-sample normal halo) LOD0 lattice. The cache is only an optimization; a failed
// proof falls through to the original per-sample N1/N2 code.
static constexpr int32 WormBlockSampleSide = 4;
// The center value is evaluated with the same float Perlin expression as N1. The endpoint noise
// coordinates are already float results of monotone positive/negative affine transforms, so their
// min/max box contains every float lattice sample exactly. The 1e-3 scaled-N1 margin covers the
// remaining center-evaluation/interpolation rounding with substantial headroom; the proof remains
// strict because both the Lipschitz term and this margin are subtracted before comparing with T.
static constexpr double WormBlockOutputRoundMargin = 1.0e-3;
FORCEINLINE bool ProvesScaledAbsPerlin3DAbove(
const FVector3f& CenterNoisePosition,
const FVector3f& MinNoisePosition,
const FVector3f& MaxNoisePosition,
float Threshold,
double ScaledFieldLipschitzBound)
{
if (!FMath::IsFinite(CenterNoisePosition.X)
|| !FMath::IsFinite(CenterNoisePosition.Y)
|| !FMath::IsFinite(CenterNoisePosition.Z)
|| !FMath::IsFinite(MinNoisePosition.X)
|| !FMath::IsFinite(MinNoisePosition.Y)
|| !FMath::IsFinite(MinNoisePosition.Z)
|| !FMath::IsFinite(MaxNoisePosition.X)
|| !FMath::IsFinite(MaxNoisePosition.Y)
|| !FMath::IsFinite(MaxNoisePosition.Z)
|| !FMath::IsFinite(Threshold)
|| !(Threshold > 0.0f)
|| !FMath::IsFinite(ScaledFieldLipschitzBound)
|| !(ScaledFieldLipschitzBound > 0.0))
{
return false;
}
const double Dx = FMath::Max(
FMath::Abs(static_cast<double>(MinNoisePosition.X)
- static_cast<double>(CenterNoisePosition.X)),
FMath::Abs(static_cast<double>(MaxNoisePosition.X)
- static_cast<double>(CenterNoisePosition.X)));
const double Dy = FMath::Max(
FMath::Abs(static_cast<double>(MinNoisePosition.Y)
- static_cast<double>(CenterNoisePosition.Y)),
FMath::Abs(static_cast<double>(MaxNoisePosition.Y)
- static_cast<double>(CenterNoisePosition.Y)));
const double Dz = FMath::Max(
FMath::Abs(static_cast<double>(MinNoisePosition.Z)
- static_cast<double>(CenterNoisePosition.Z)),
FMath::Abs(static_cast<double>(MaxNoisePosition.Z)
- static_cast<double>(CenterNoisePosition.Z)));
const double Radius = FMath::Sqrt(Dx * Dx + Dy * Dy + Dz * Dz);
// Keep this operation in float and in the same order as the production N1 expression. The
// double conversion is only for the conservative comparison below.
const float CenterN1 = FMath::Abs(
Perlin3D(CenterNoisePosition) * VOXEL_NOISE_SCALE);
if (!FMath::IsFinite(CenterN1))
{
return false;
}
return static_cast<double>(CenterN1)
- ScaledFieldLipschitzBound * Radius
>= static_cast<double>(Threshold) + WormBlockOutputRoundMargin;
}
//=============================================================================
// 4-WIDE BATCH — the SIMD multiplier. Computes 4 independent Perlin samples.
// Inputs are 4-element arrays; unused lanes must be zero-filled by the caller