From 3de7ce142055176ca0f829152acc26f0d89a848e Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Tue, 29 Sep 2026 15:58:39 +0200 Subject: [PATCH] docs(research): round two -- wider search, AVX2 integer probe, crater transaction design Fork of the Sol research session with the owner's answers (player-only 1 s collision; bounded digging but fast crater spells). AVX2 integer kernel 4.25-5.86x over its scalar reference with exact parity; radius-10 m crater = 714 bricks, cached-field edit < 1 ms (render not measured). Cost estimate revised to 6-12 engineer-months; kill test gate <= 0.35 s worker wall on real plans. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ --- RESEARCH-SPEED-2026-09.md | 96 +++++++++++++++--- Saved/Research/round2_probe-results.txt | 31 ++++++ Saved/Research/round2_probe.cpp | 125 ++++++++++++++++++++++++ 3 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 Saved/Research/round2_probe-results.txt create mode 100644 Saved/Research/round2_probe.cpp diff --git a/RESEARCH-SPEED-2026-09.md b/RESEARCH-SPEED-2026-09.md index 93687e5..8c1c4bc 100644 --- a/RESEARCH-SPEED-2026-09.md +++ b/RESEARCH-SPEED-2026-09.md @@ -2,9 +2,9 @@ ## Answer first -**Recommendation: compile the procedural plan into deterministic, sparse 8³-voxel bricks; mesh only bricks whose final field can cross zero; use direct field collision for immediate readiness, with cooked mesh collision relegated to a background compatibility path.** Keep the 25 cm lattice, full 3D operators, walkable route graph and seed/edit replication. Replace the point-at-a-time operator search with feature-to-brick binning, brick-constant operator state, integer or specified fixed-point evaluation, shared lattice samples, and a batched render upload. This is a new generation and collision architecture, not another tuning pass on the current mesher. OpenVDB's hierarchical sparse volume and narrow-band treatment, Voxel Plugin's near-surface storage, and the volumetric terrain example in GPU Gems 3 support the *shape* of the design, not its expected VoxelForge time. [OpenVDB paper](https://museth.org/Ken/Publications_files/Museth_TOG13.pdf), [Voxel Plugin performance notes](https://docs.voxelplugin.com/1.2/technical-notes/performance-and-profiling), [GPU Gems 3 volumetric terrain](https://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-1-generating-complex-procedural-terrains-using-gpu). +**Revised recommendation: compile a deterministic integer operator plan into spatially pruned 8³-voxel bricks, mesh only uncertain bricks, and give the player direct field collision. Add a transaction-wide GPU visual edit layer for large spells; keep baked meshes and optional Chaos collision as background caches.** The player collision definition supplied in round two removes the 512 simultaneous Chaos-cook requirement. The crater requirement adds a second critical path: changing 714 bricks cannot depend on 714 component uploads within one frame. Keep the 25 cm lattice, volumetric operators, walkable route graph and seed/layout/edit replication. Replace point-at-a-time feature search with a stable region-local program and conservative final-field bounds. Recent work on pruning SDF construction trees directly supports this direction, but its speedups on other scenes are not VoxelForge measurements. [Lipschitz Pruning, Eurographics 2025](https://wbrbr.org/publications/LipschitzPruning/documents/LipschitzPruning_submitted_to_EG25.pdf), [Accelerating Signed Distance Functions, 2025](https://perso.liris.cnrs.fr/eric.galin/Articles/2025-lod.pdf), [OpenVDB paper](https://museth.org/Ken/Publications_files/Museth_TOG13.pdf). -**The one-second target is plausible but not proved.** The arithmetic is decisive about what must change: +**The one-second target is plausible but not proved.** The round-two six-worker AVX2 probe processed a *synthetic* 256³ composition in **80.3–107.5 ms** across three three-trial runs with exact scalar parity; 17.374 M unique ring points at that measured throughput extrapolate to **83.2–111.3 ms**, leaving roughly 0.89 s for classification, mesh extraction, upload and visibility. This is an arithmetic extrapolation across different data and cache patterns, not a measured UE ring. The scalar probe took **430.3–496.2 ms**, a **4.25–5.86×** paired speedup from explicit AVX2. The recommendation is conditional on a production-stack parity/timing experiment and a UE upload/VR edit spike. The arithmetic is decisive about what must change: | Quantity | Arithmetic or measurement | Consequence | |---|---:|---| @@ -17,7 +17,7 @@ **Measured standalone feasibility probe on this machine:** A synthetic 256³ 3D field with 48 integer sphere features and three octaves of integer lattice noise took **471–481 ms** for 16,777,216 samples using six threads. Conservatively classifying 32,768 8³ bricks took **15.46 ms**; evaluating only the 7,563 uncertain bricks then took **106–130 ms**, with **zero sign mismatches** against the full evaluation over all 16,777,216 points. An eight-thread repeat took 349–367 ms full or 86–110 ms classified plus 15.59 ms classification. This is a *kernel probe*, not VoxelForge or a measured 512-tile load. Its primitive list and noise are far simpler than the current composer stacks. It shows that the required rate is physically credible on this CPU when work is converted to bounded integer kernels; it does **not** establish that the full game, render upload, or Chaos field integration finishes in one second. Benchmark details and limitations are below. -**Build cost:** a substantial rewrite, roughly **3–6 engineer-months for a first playable replacement, then 2–4 months of compatibility/performance hardening** (planning estimate, not measured productivity). The hard part is the numeric ABI and Chaos/character collision integration, followed by edit transaction rendering. A cheap proof or kill experiment is specified under Migration. If exact arbitrary rigid-body collision across all 512 tiles must be active through ordinary Chaos body cooking, the present evidence gives **no credible route to <1 s**. The owner would need to accept direct-field physics integration or relax that interpretation. Also, an unbounded-size edit cannot have a fixed same-frame CPU cost; the game needs a bounded interactive brush contract or an immediate GPU visual edit overlay. +**Build cost:** revise to roughly **6–12 engineer-months for a production replacement** (planning estimate, not a measured rate), because the numeric ABI, custom player movement queries, batched rendering, and transaction-wide crater visual layer are separate major systems. The first falsifiable experiments are smaller. No evidence here proves the UE render path can present a cold 64 m cube in under 1 s or a radius-10 m crater in the same VR frame. If those experiments fail, the owner must accept a reduced near ring, a delayed exact crater visual, or a more radical GPU render path; none can be silently assumed away. ## Local evidence and what it means @@ -53,9 +53,9 @@ The probe lacks passages, smooth Boolean operators, strata boundaries, edits, me | Architecture | Representation and pipeline | Main advantage | Main cost/risk | Verdict | |---|---|---|---|---| -| **A. Sparse compiled bricks + CPU contouring + field collision** | Seed/layout compile to a stable feature plan. Bin each primitive to touched bricks. Each 8³ brick stores a final-sign certificate (solid/air/uncertain), compact density band and edit version. Mesh uncertain bricks with marching cubes or surface nets; group tiles for upload. Query the same canonical field directly for collision. | Eliminates most repeated feature traversal, supports edits and 3D topology, removes cook from readiness. | Conservative certificates may fail on complex operator stacks; custom Chaos collision is unproved. | **Recommended experiment.** | +| **A. Sparse compiled bricks + batched CPU contouring + direct player field collision** | Seed/layout compile to a stable feature plan. Bin each primitive to touched bricks. Each 8³ brick stores a final-sign certificate (solid/air/uncertain), compact density band and edit version. Mesh uncertain bricks with marching cubes; group tiles for upload. Give the player field-aware movement. GPU edit transactions cover crater-scale changes. | Eliminates most repeated feature traversal, supports edits and 3D topology, removes cook from player readiness. | Conservative certificates may fail on complex stacks; player movement and same-frame crater rendering still need UE/VR proof. | **Recommended experiment.** | | **B. Analytic CSG/BVH + raymarch render and collision** | Keep a spatially indexed graph of implicit primitives and bounded noise, no resident sampled terrain except caches. GPU raymarches image-space rays through an acceleration structure; CPU queries analytic field for physics. Edits add CSG nodes. | Very long view and same-frame edits can avoid remeshing entirely. | Full-screen/stereo ray cost, non-SDF operators break safe sphere tracing, shadows/materials/UE integration; many edits enlarge BVH and query cost. It changes visual appearance. | Radical alternative if meshing/upload still dominate after A. | -| **C. Integer GPU brick generation + compute meshing** | CPU generates canonical integer plan/brick list; compute shader evaluates fixed-point density and emits deterministic mesh indices by prefix-sum, while CPU uses the same integer evaluator for authoritative collision. | Could offload 17–22 M sample and contour work; GPU Gems 3 demonstrates fully 3D GPU generation rather than a heightfield. | Cross-vendor integer ABI, GPU readback/synchronization for collision, VR frame contention, runtime mesh integration. | Research branch only until exact AMD/NVIDIA and CPU/GPU hash parity is demonstrated. | +| **C. Integer GPU brick generation + compute meshing** | CPU generates canonical integer plan/brick list; compute shader evaluates fixed-point density and emits deterministic mesh indices by prefix-sum, while CPU uses the same integer evaluator for authoritative player collision. | Could offload 17–22 M sample and contour work without collision readback; GPU Gems 3 demonstrates fully 3D GPU generation rather than a heightfield. | Cross-vendor integer ABI, duplicate CPU/GPU evaluators, VR frame contention, runtime mesh integration. | Research branch only until exact AMD/NVIDIA and CPU/GPU hash parity is demonstrated. | Architecture A should treat the **plan as the source of truth** and bricks as disposable caches. Compile op nodes once per region into a fixed order and collect local feature references by feature bounding box, with an explicit bound for noise, warps and edits. A brick certificate must enclose the **final** composed field: an operator that can add solid after a carve invalidates a carve-only proof. If any op cannot supply a safe bound, mark the brick uncertain. The current interval route's measured slowdown is a warning that a proof must cost less than the points it avoids. A local feature raster pass reverses the present “each point searches nearby features” loop and keeps shape data hot in cache. The sparse hierarchy stores occupied, empty and uncertain bricks; a compact, flat Morton or Z-major page table is likely better for the active 64 m cube than a pointer-heavy tree. OpenVDB provides a precedent for sparse, editable narrow-band fields, while sparse voxel octrees/DAGs are more compelling for static repeated geometry than for heavily edited procedural bricks. [OpenVDB](https://museth.org/Ken/Publications_files/Museth_TOG13.pdf), [Laine and Karras SVO report](https://research.nvidia.com/sites/default/files/pubs/2010-02_Efficient-Sparse-Voxel/laine2010tr1_paper.pdf), [Kämpe et al. sparse voxel DAG](https://www.cse.chalmers.se/~uffe/HighResolutionSparseVoxelDAGs.pdf). @@ -75,9 +75,9 @@ For A's collision, store an immutable field snapshot and expose a broad-phase AA **3D and composition.** The plan retains volumetric SDF/CSG regions, mountains, caves, overhangs and islands. A surface heightfield clipmap alone is disallowed: the original geometry-clipmap paper explicitly targets heightfields. Each current archetype, composer tag, structural post, passage and diff becomes a compiled op with a finite or explicitly unbounded influence declaration. [Geometry clipmaps paper](https://hhoppe.com/geomclipmap.pdf). The shipped examples support broad direction, not a claimed matching performance number: No Man's Sky describes its voxel-to-polygon pipeline and reports a later dual-marching-cubes rewrite improved loading; Astroneer describes re-polygonizing modified chunks; neither publishes a directly comparable one-second/64 m benchmark. Teardown's movable voxel volumes and packed occupancy hierarchy solve a different destructible-object problem, and Enshrouded's developer account confirms editable voxel terrain without exposing a transferable throughput figure. Dual Universe demonstrates a multiplayer editable voxel world, but its published material likewise gives no comparable generation latency. [NMS GDC talk](https://www.gdcvault.com/play/1024265/), [NMS update](https://www.nomanssky.com/worlds-part-I-update/), [Astroneer developer account](https://www.gamedeveloper.com/design/what-i-astroneer-i-s-devs-learned-while-leaving-early-access), [Teardown developer's voxel rendering account](https://blog.voxagon.se/2018/10/17/from-screen-space-to-voxel-space.html), [Enshrouded developer AMA](https://enshrouded.com/pl-PL/news/enshrouded-world-design-team-reddit-ama-recap), [Dual Universe developer diary](https://www.youtube.com/watch?v=MWcuwt9bjHo). -**Walk guarantee.** Keep the composer-generated entrance/exit route as an explicit graph of swept, capsule-clear walking corridors and landing floors. Apply that route as a late, protected operator whose minimum clearance and maximum slope have margins below the player capsule's mechanical limit; validate the final sampled collision representation with capsule sweeps. Decorative ops cannot narrow the protected clearance. If the guarantee must survive *arbitrary filling and floor removal by players*, unrestricted edits and guaranteed traversal conflict: protect the last path, auto-build replacement support, or interpret the guarantee as applying only before edits. This is a product decision; the current code's generated route tests do not settle post-edit behavior. +**Walk guarantee.** Keep the composer-generated entrance/exit route as an explicit graph of swept, capsule-clear walking corridors and landing floors. Apply that route as a late, protected operator whose minimum clearance and maximum slope have margins below the player capsule's mechanical limit; validate the final sampled collision representation with capsule sweeps. Decorative ops cannot narrow the protected clearance. For edits, protect a minimal support/clearance tube along one certified route; clip a crater's destructive part where it would remove the last walkable support or add an automatically generated bypass as part of the same transaction. A crater may therefore leave a thin protected bridge. This is a concrete rule that preserves the guarantee; the design of its visible cue is a gameplay/content task. The current route tests do not establish post-edit traversal, so verify it after each affected edit graph change. -**Clean digging.** Treat one edit as a transaction: allocate a monotonically numbered edit ID, compute every affected brick and one-cell halo from a single immutable pre-edit snapshot, generate replacement mesh pages, and publish *one* new field/render/collision epoch at a frame boundary. Border vertices use global lattice coordinates and a single owner, with identical edit IDs on both sides. A single render-thread command must switch the complete page set; a sequence of independent RMC section updates is not an atomic render publish. The physics snapshot switches at its matching simulation boundary. During preparation keep the old render and collision snapshot together; at commit swap all touched pages together. Never disable the support body before the replacement is ready, and never let a completed old cook restore it. Character velocity is carried across support replacement only from actual displacement/input; cancel contacts from an obsolete body and recompute grounded state without inventing a downward impulse. A 1 m-radius interactive brush touches at most eight 2 m bricks in the ordinary case; a one-cell halo may add more, so measure the exact maximum fanout. **This does not yet prove same-frame edits.** For bounded brushes, all preparation and the render/physics swap must finish before that frame's submission. For arbitrary larger brushes, render an immediate fixed-point edit overlay covering the whole brush in the same frame while batched meshes catch up, or define a maximum interactive brush size and prove its worst-case transaction time on the target and in VR. Both options require a real UE measurement. Network edits carry server order and ID; prediction displays the same transaction locally and reconciles on authoritative order. +**Clean digging.** Treat one edit as a transaction: allocate a monotonically numbered edit ID, compute every affected brick and one-cell halo from a single immutable pre-edit snapshot, and publish one canonical field/edit epoch before player movement in that frame. Border vertices use global lattice coordinates and a single owner, with identical edit IDs on both sides. The player queries the new field immediately; optional cooked bodies are never authoritative for the player and an obsolete cook cannot restore stale support. Character velocity is carried across an edit from actual displacement/input only; recompute grounded state without an invented downward impulse. A 1 m-radius interactive brush touches at most eight 2 m bricks at a grid corner before halo expansion. The render path switches the complete affected region in one frame using the GPU transaction described below, never a sequence of independent RMC tile updates. **This does not yet prove same-frame edits**: the UE/VR test must measure the whole transaction including GPU completion, stencil/depth, shadowing and stereo. Network edits carry server order and ID; prediction displays the same transaction locally and reconciles on authoritative order. **Streaming and long view.** Keep a 3D clipmap but make LOD1 available first at 16 cells per tile: 19³/35³ = **0.160** of today's per-tile sample requests, an arithmetic count, not a measured 6.25× wall speedup. Applying that ratio to the supplied 16.5 M LOD1 requests yields **2.64 M requests**; at the old ~2 µs/request this is **5.28 CPU-seconds**, or **0.88 s on six ideally scaled cores**, before upload. This arithmetic makes “a few seconds” credible for the preview even without the new brick speed, but it is no end-to-end guarantee. Refine to 32 cells later. Reuse lattice coordinates when coarse samples coincide with resident fine samples; outside the fine cube, evaluate coarse bricks independently. A far shell should be surface-aware and perhaps use a much lower-resolution 3D contour plus impostor for sealed distant strata; preserve visible caves/islands rather than flattening to terrain height. Use Transvoxel or a tested equivalent when meshes at unequal LOD meet. Prioritize spawn/teleport center, movement direction, falling support and edits; apply back-pressure to far work. UE Tasks priorities affect scheduling but do not preempt a running expensive tile; divide work into cancellable bricks. [UE Tasks documentation](https://dev.epicgames.com/documentation/unreal-engine/tasks-systems-in-unreal-engine), [Transvoxel](https://transvoxel.org/). @@ -87,13 +87,81 @@ For A's collision, store an immutable field snapshot and expose a broad-phase AA Keep RMC for the first experiment, but reduce component count by grouping spatial pages and separating render pages from collision. Replacing it with ProceduralMeshComponent only changes the wrapper around the same asynchronous cook; Epic documents `bUseAsyncCooking`, not a latency guarantee. `UDynamicMeshComponent` has useful edit representation but Epic lists no Nanite/LOD support and warns about render/memory efficiency. RMC's current upstream documentation claims runtime Nanite, and the locally installed RMC 5.4 source contains a runtime Nanite module and provider checks. **Revisit Nanite as an isolated *far/mostly static render* benchmark**, including PC VR stereo, page-build time, edit rebuild time and fallback mesh cost. It does not solve density evaluation or Chaos collision, and the first one-second ring should not wait for Nanite conversion. Nanite collision uses a fallback mesh, not Nanite triangles. [PMC API](https://dev.epicgames.com/documentation/unreal-engine/API/Plugins/ProceduralMeshComponent/UProceduralMeshComponent), [Epic dynamic-mesh guide](https://dev.epicgames.com/documentation/unreal-engine/geometry-scripting-users-guide-in-unreal-engine), [RMC docs](https://github.com/TriAxis-Games/RealtimeMeshComponent/blob/master/Docs/index.md), [Epic Nanite fallback details](https://dev.epicgames.com/documentation/unreal-engine/nanite-technical-details). -## Migration and decisive experiment +## Round two: wider search and revised engineering test -1. **Freeze a reference corpus.** Record seed/layout/edit cases for all eight archetypes, passage boundaries, the walk validator, 3D overhangs and the current 128³ profiling scene. Save cell signs, surface hashes, capsule-query answers and production wall-time ledgers. Keep the existing composer, content semantics and diff protocol initially; preserve old saves with a versioned generator. -2. **First cheap kill test (estimate: five working days), standalone then UE when permitted:** extract the actual TunnelNetwork hot path and one passage-bearing mixed recipe into a standalone harness, using recorded seed/layout inputs and output samples from the reference corpus. Compile each plan to fixed per-brick feature lists and mathematically conservative final-field bounds. Measure all 512-tile ring cells on this Ryzen, six worker threads, cold cache, with exact sign parity against `GetDensityAt`, including edited borders. **Continue only if** the cold 64 m cube reaches ≤0.5 s worker wall (or a measured surface-only equivalent), with zero false uniform proofs and reasonable memory. The synthetic benchmark in this report is not this test. A high “uncertain” rate *combined with* slow local feature evaluation, or per-brick proof cost like the current interval route, kills the plan. -3. **Collision spike before a rewrite:** integrate one custom field page into Chaos and CharacterMovement in a throwaway UE test scene, including ray, capsule sweep, rigid body contact and underfoot edit. Require exact query/readiness timing under 0.1–0.2 s across a cold 64 m cube, no false velocity, and no collision/visual epoch mismatch. If arbitrary Chaos physics cannot use the field representation, cost a background cooked-body hybrid or revise the target explicitly. -4. **Render spike:** feed the real 512-tile corpus into 2³-tile grouped RMC pages, measure game/render-thread upload, RHI fence, VR stereo frame time, and a one-frame multi-page edit transaction. Budget approximately 0.2–0.3 s of the one-second window for upload and publication; this is a proposed acceptance budget, **not measured**. -5. **Only after those gates:** port archetypes/composer ops, replace local density cache and classification, add fixed-point parity CI on Intel/AMD, then LOD transition and horizon work. Retain the old path behind a version switch until saves and multiplayer traces match or migration is explicit. The next-level target gets its own cold timing with the intended 16-cell preview and 32-cell refinement clocks reported separately. +### What the new local probe measured + +[`Saved/Research/round2_probe.cpp`](Saved/Research/round2_probe.cpp) is an independent C++20 program, not copied production code. It models the *kinds* found in `VoxelNoise.h`, `VoxelDensityOpStack.cpp`, and `VoxelGenerator.cpp`: hashed 3D gradient Perlin with a fixed-point quintic fade, three-octave fBm, ridged noise, one domain warp, upper/lower stratum bounds, a passage-like corridor, a room, and two smooth maxima. The gradient choice and fade shape follow the plugin, but the hash, coordinate scale, parameters, and composed graph differ. The code has a scalar reference and explicit eight-lane AVX2 integer evaluator; each lane writes exactly the same 16-bit value in the measured domain. The present plugin already has **SSE4.1 x4 Perlin batching across octaves**; the new speedup is therefore **against this program's scalar reference**, not against the production plugin's SSE path. + +Build/run from `Saved\Research` on the owner's Ryzen/Windows machine: + +```powershell +cmd /c '"E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul && cl /nologo /O2 /std:c++20 /EHsc /arch:AVX2 round2_probe.cpp /Fe:round2_probe.exe' +.\round2_probe.exe +``` + +MSVC compiled successfully; the installed setup script emitted a missing-`vswhere.exe` notice. Wall times below include six worker threads and output writes, exclude process startup and verification. Three three-trial runs with the same evaluation code (the second after dead-code cleanup, the third after adding the direct-query measurement) gave: + +| Work | Measured wall time | Meaning | +|---|---:|---| +| 256³ complete scalar field | 492.0, 496.2, 469.6; 430.3, 456.2, 447.1; 478.6, 471.0, 444.3 ms | 16,777,216 output points. | +| Same field, explicit AVX2 | 101.3, 106.0, 92.5; 89.2, 107.5, 94.6; 85.8, 80.3, 82.7 ms | Paired speedups **4.25–5.86×**, zero value mismatches. | +| Full value comparison | 0 mismatches in all 16,777,216 points on each trial | One machine and coordinate domain, not cross-vendor proof. | +| 200,000 spatially scattered direct field queries | 63.030, 62.785, 62.799 ms | **313.9–315.1 ns/query**, one scalar thread; all checksums equal. A synthetic player-query latency proxy, not a capsule sweep. | +| Radius-10 m spherical edit against cached field | 0.865; 0.914; 0.861 ms | Six-worker max-composition over the 81³ bounding cube; excludes rendering and copy. | +| Copy entire 256³ 16-bit field | 1.623; 1.422; 1.394 ms | An intentionally wasteful 32 MiB copy; local brick copy-on-write would copy much less. | +| Touched 8³ bricks / changed lattice sites | 714 / 94,843 | Exact for the synthetic sphere at a brick/tile boundary; geometry and edit content affect changed count. | + +**Inference, not measured production latency:** 17,373,979 ring points divided by the observed AVX2 throughput give **83.2–111.3 ms** for this operator mix. Even the slowest scalar trial extrapolates to ~514 ms; a 0.5 s worker budget is close without AVX2 and leaves no room for a more expensive real composer. The scattered-query result implies ~**635 queries in 0.2 ms** at this synthetic rate, versus **100** at the supplied current ~2 µs/sample. A real player capsule sweep must be bounded and separately timed; this arithmetic does not establish a 0.2 ms sweep. SIMD is one possible factor in the required ~12× reduction, not the entire answer. Probe limitations: the plugin uses float Perlin today, its ridged noise has feedback/squaring absent from this simplified ridge, several operator classes and dynamic world-composer decisions are absent, the program computes all points without brick classification, the six worker threads contend with no UE tasks, and no mesher/upload/collision/VR frame is timed. The fixed-point replacement will visibly alter worlds unless the project accepts a versioned new season or derives a compatible canonical approximation. Avoid claiming the synthetic 5× is a drop-in speedup. [FastNoise2's fused SIMD graph and published 261.1 M 3D Perlin points/s on a different Intel CPU](https://github.com/Auburn/FastNoise2), [FastNoise2 exact-reproducibility FAQ](https://github.com/Auburn/FastNoise2/wiki/FAQ). + +### New evidence that changes the architecture + +| Source-measured or documented result | Transfer to VoxelForge | +|---|---| +| Eurographics 2025 **Lipschitz Pruning** reports 0.91–1.61 ms for 256³ discretization on a laptop RTX 4060 for scenes with 53–6,023 nodes, plus 0.72–14.29 ms pruning; its most complex model gained 629× in sphere-tracing against naïve evaluation. | Strong evidence for **region-specific compiled operator programs**, including smooth CSG, not a VoxelForge GPU speed prediction. The method assumes primitives/operators with computable 1-Lipschitz bounds; arbitrary warped scalar density needs derived bounds or a fallback. Its fluid scene with 27,977 close particles needs 125.5 ms pruning and 6.99 ms discretization, demonstrating layout sensitivity. [Paper and Table 1](https://wbrbr.org/publications/LipschitzPruning/documents/LipschitzPruning_submitted_to_EG25.pdf). | +| **Accelerating Signed Distance Functions** reports up to three orders of magnitude on its construction-tree scenes, using proxy/LOD nodes. It expressly warns that a discontinuous proxy below a smooth union causes artifacts, and that manual LOD authoring and extra nodes cost memory. | Compile local plans and conservative proxies **with operator-aware legality**; no generic “replace any far branch with a constant.” Preserving the exact zero set near transitions matters for walking and digging. [Paper](https://perso.liris.cnrs.fr/eric.galin/Articles/2025-lod.pdf). | +| Keeter's SIGGRAPH 2020 interval method simplifies complex closed-form expressions by region; Knoll et al. compared interval and affine arithmetic for implicit ray tracing. | Both are real alternatives for exotic operators, but the **local** blanket interval attempt worsened 0.588 s to 2.057 s. Use inexpensive analytic primitive influence and final-sign certificates first; profile any tighter affine bound by avoided evaluations per microsecond. [Keeter](https://www.mattkeeter.com/research/mpr/), [Knoll et al.](https://www.vacet.org/publications/Knoll_CGF-implicits-2009.pdf), [local control](Docs/archive/PERF-ATTRIBUTION.md). | +| Eurographics 2025 **Fast Sphere Tracing of Procedural Volumetric Noise** reports a detailed 3D procedural-noise scene at **16 ms for 1024² pixels** on an Nvidia 4080 Ti, versus 110 ms naïve; the authors report up to 12× on opaque/constant-transparency scenes using derivative-aware stepping and nested fBm bounds. | Strongest recent case for the analytic-render alternative. Linear scaling from 1.05 M to 4.15 M stereo pixels would be ~**63 ms** on that *different GPU/scene*, before VR lighting; this is a cautionary inference, not a measured Quest 3 figure. Reuse its nested fBm bound idea for local-region culling even if raster meshes remain primary. [Paper](https://diglib.eg.org/bitstream/handle/10.1111/cgf70072/cgf70072.pdf). | +| JCGT 2019 reports **15–20%** faster 3D cellular noise traversal than standard Worley on its benchmark (for 16 M queries, one table row falls from 13.69 s to 11.15 s). | Relevant only to the plugin's cellular roughness branch, not its dominant gradient-Perlin calls; do not multiply this into a ring-wide speedup. [JCGT paper](https://jcgt.org/published/0008/01/02/). | +| Voxel Plugin 2's own change log claims up to **2×** world generation from skipping cells far from surface, plus up to **40%** VRAM reduction in an experimental Nanite path. Its docs separate collision and render invokers. | Confirms that surface sparsity and collision/render separation are practical in UE, but vendor numbers are not a transferable end-to-end 12×. [Voxel Plugin 2 change log](https://docs.voxelplugin.com/resources/change-log/2.0p8-changelog), [collision design](https://docs.voxelplugin.com/2.0p8%20-%20v2/design-docs/collision-mesh-navmesh). | +| FastNoise2 reports **261.1 M** AVX2 3D Perlin points/s on an Intel 7820X; its FAQ says floating SIMD levels can differ and advises strict FP plus a locked SIMD level for exact output. | Fuse whole op graph in registers; do not import float FastNoise2 with automatic SIMD dispatch as the canonical multiplayer field. Our fixed integer benchmark shows a path to parity on one CPU; cross-machine parity still needs testing. [Library and benchmark](https://github.com/Auburn/FastNoise2), [FAQ](https://github.com/Auburn/FastNoise2/wiki/FAQ). | +| Epic's UE 5.7 Mover comparison says movement can use a root scene component without a collision primitive and custom movement modes; local UE 5.7 `CharacterMovementComponent.cpp` still makes floor and move sweeps through the engine collision scene. | **Player collision should be a custom field-aware movement mode/adapter**, most plausibly Mover, while preserving sweep checks against non-terrain actors. Simply leaving the old CMC capsule on an uncooked mesh does not fulfill “collidable.” Mover is a migration risk and must be tested under network prediction. [Epic Mover comparison](https://dev.epicgames.com/documentation/unreal-engine/comparing-mover-and-character-movement-component-in-unreal-engine). | +| Epic's RDG documentation supports compute passes, dependency barriers and async compute but notes platform fallback to the graphics pipe. | A GPU edit mesher can be integrated with a render-graph transaction, but “async” does **not** establish same-frame latency or free VR time. [Epic RDG guide](https://dev.epicgames.com/documentation/unreal-engine/render-dependency-graph-in-unreal-engine). | + +### Crater spell: one transaction, up to 64 tiles + +A radius-10 m sphere is **40 lattice intervals** at 25 cm. Its 20 m AABB reaches up to **4 tiles per axis** when centered on a tile boundary, hence **64 full-detail 8 m tiles**; at a tile center it reaches at most 27. The sphere's continuous volume is `4π40³/3 = 268,083` voxel cubes versus `81³ = 531,441` candidate lattice sites. The local exact sphere/AABB enumeration found **714 2 m bricks** touching the ball. Independently contouring each 8-cell brick needs `714×9³ = 520,506` corner-sample reads before sharing; the real distinct set is smaller, and normal or LOD halos can add reads. A naïve re-evaluation at today's 2 µs/sample would cost about **1.04 CPU-seconds** for those corners, so **cache the base field and compose the edit over it**. The measured synthetic cached-field edit took **0.865–0.914 ms**, but no extraction or upload was measured. CPU copy-on-write at touched bricks has a raw 16-bit interior payload of `714×8³×2 = 731,136 bytes`; a full near-field 32 MiB copy was measured at 1.422–1.623 ms. The crater itself is ~one command (center/radius/shape/seed/version), not 95,000 replicated voxels. A pathological marching-cubes upper bound is `714×512×5 = 1.83 million` triangles; at three unshared 16-byte vertices each that is **87.7 MB** of transient output. Realistic counts must be measured, and GPU buffer overflow must fall back to a complete-region visual path, never publish half a crater. + +**Proposed fast path.** Commit an edit in a deterministic order with a monotonically increasing edit sequence. On the CPU, publish a new immutable edit-plan pointer for *all* 714 bricks before movement and render gather for that frame. A canonical signed integer field query composes the crater immediately, so player floor/capsule sweeps cannot see stale support; nonplayer traces use the same fallback until their optional Chaos mesh is ready. Never transfer a removed collision body's velocity or use old cooked floor data after the edit sequence changes. If the dig removes the floor, real gravity begins from the player's pre-edit velocity exactly once; if it adds terrain around the capsule, resolve penetration with a bounded positional correction that does not enter velocity. The entrance-to-exit route is a **protected graph corridor**: preflight the crater against a protected walkable tube and either clip its solid-adding part, carve a replacement bypass, or reject the spell by explicit gameplay rule. For pure excavation, connectivity cannot be reduced, though walking surfaces can be removed, so the route proof must include footholds/clearance, not only air connectivity. + +For visuals, use one GPU edit transaction over the whole affected region. Keep the near lattice field resident on the GPU; upload the compact command, compute the changed bricks and their transition halo in a **single render-graph dependency**, generate canonical marching-cubes triangles with a stable per-cell prefix sum, and swap the entire region's draw descriptors together at a frame boundary. Suppress the old region only when its replacement is drawable; no per-tile apply loop. All visible coarser LOD footprints touched by the spell take the same edit sequence, using the corresponding coarse lattice and transition mesh; an unloaded distant region records the command for generation when it enters view. A local volume-raymarch overlay can cover the transaction while mesh extraction is late, using the same canonical cached field and edit command, with a one-cell overlap and exact depth writes. The overlay must be checked against the meshed boundary and stereo views to rule out cracks, double surfaces, and ghost shadows. **This is an engineering design, not a proved same-frame guarantee:** no UE/GPU measurement was authorized in this research pass. The decisive GPU/VR test must finish edit compute + descriptors + draw in the **first submitted render frame whose simulation includes the command**; an input received after that frame's render submission belongs to the next frame. No affected tile may show a different edit sequence in that frame. [Epic RDG synchronization](https://dev.epicgames.com/documentation/unreal-engine/render-dependency-graph-in-unreal-engine), [GPU Gems 3's 3D GPU marching cubes](https://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-1-generating-complex-procedural-terrains-using-gpu). + +The current crash mode is especially clear for crater scale: synchronous center-tile remesh followed by up to 63 independently queued neighbors produces a visible wave; disabling old collision and waiting 0.4–1.4 s for cooks creates a falling gap; retaining old BodySetup creates ghost support. The transaction above removes those three states. It does **not** assume that optional Chaos rigid bodies can all get exact crater collision in the same frame; the owner expressly accepts field-query fallback for NPCs, arrows and other physics until their mesh is ready. + +### Serious alternatives, with quantified wins and losses + +| Alternative | Where it could win | Why it is not the primary route now | +|---|---|---| +| **Whole-world analytic raymarch (radical B)** | No persistent triangle mesh; edit command changes the next render. Keeter and 2025 pruning show that complex trees can be raytraced after regional simplification. | At 1920×1080, **2.07 M rays per eye**, or **4.15 M stereo rays** before shadows/VR supersampling; at 32 field steps this is **133 M queries/frame**. At the measured synthetic AVX2 throughput of ~156–209 M *grid* points/s across six cores, that many CPU queries would take ~0.64–0.85 s; GPU may be far faster. The 2025 procedural-noise paper measures **16 ms at 1024²** on a 4080 Ti; simple stereo-pixel scaling to 4.15 M gives ~63 ms before VR lighting, a scene/hardware inference. Density is not necessarily a distance bound for safe sphere tracing, and a full GPU renderer is a larger rewrite. [Keeter](https://www.mattkeeter.com/research/mpr/), [EG 2025 noise tracing](https://diglib.eg.org/bitstream/handle/10.1111/cgf70072/cgf70072.pdf), [SDF-grid ray tracing, JCGT](https://jcgt.org/published/0011/03/06/). | +| **All-GPU integer generation and meshing (C)** | The Eurographics RTX 4060 paper's 256³ discretization at 0.91–1.61 ms shows enormous headroom in a suitable GPU expression, though its data/model differ. Could supply same-frame crater triangles. | Requires explicit 32/64-bit integer arithmetic rules, fixed division/rounding, no unordered atomics for vertex order, deterministic prefix sums, CPU/GPU/AMD/NVIDIA parity hashes, and an UE RHI path. Any float-transcendental or vendor-specific FMA noise breaks the canonical requirement. The paper's pruning and rendering are GPU-only and do not prove the CPU player query. [Lipschitz Pruning](https://wbrbr.org/publications/LipschitzPruning/documents/LipschitzPruning_submitted_to_EG25.pdf), [Khronos float controls](https://github.com/KhronosGroup/Vulkan-Docs/blob/main/proposals/VK_KHR_shader_float_controls2.adoc). | +| **Dual contouring / surface nets / adaptive power-diagram contouring** | Potentially fewer vertices and sharper features; JCGT's SurfaceNets work reports better triangle quality than classic MC for segmentation models. A 2025 power-diagram method reconstructs complex SDF geometry from fewer samples. | Generation is ~97% density time in the local attribution, so changing contouring *alone* can save at most the remaining ~3% of that worker window. Adaptive sampling could save more but needs a certified error/feature rule for narrow passages. SIGGRAPH Asia 2024's GPU occupancy dual contouring still describes runtimes of **a few seconds** for its distinct reconstruction problem, not subsecond terrain streaming. Seam dependencies and LOD transition rules become more complex; neither solves cook or atomic edit transactions. Benchmark later if upload dominates after density rewrite. [Dual contouring](https://people.eecs.berkeley.edu/~jrs/meshpapers/JuLosassoSchaeferWarren.pdf), [JCGT SurfaceNets](https://jcgt.org/published/0011/01/03/), [Eurographics 2025 power-diagram contouring](https://onlinelibrary.wiley.com/doi/10.1111/cgf.70037), [SIGGRAPH Asia 2024 occupancy dual contouring](https://occupancy-based-dual-contouring.github.io/), [chunk seam example](https://ngildea.blogspot.com/2014/09/dual-contouring-chunked-terrain.html). | +| **SVO/DAG or OpenVDB as source of truth** | Empty-space skipping and sparse memory; GPU SVDAG editing shows large 3D painting can be interactive in a different system. | The world's seed/composer already *is* a compact source. At full 25 cm resolution, the 64 m cube alone has 17.37 M unique samples or **34.7 MB at 16 bits** if fully resident; a global 6 km view volume is vastly larger. DAG sharing degrades with unique noise and edits; keep a sparse cache/hierarchy, not a required full-world DAG. The cited GPU editor's code uses CUDA, so it is no cross-vendor solution. [OpenVDB](https://museth.org/Ken/Publications_files/Museth_TOG13.pdf), [SVDAG editing paper](https://diglib.eg.org/items/ffd7acf6-01f7-4e53-87f8-4cded382c944), [author code](https://github.com/mathijs727/GPU-SVDAG-Editing). | +| **Prebake each seasonal world in the shipped game** | If seasons have a finite, known seed/layout set, local NVMe transfer could remove cold density evaluation and deterministic divergence. | For this 64 m cube, even raw 16-bit density is **34.7 MB** before meshes; ~6 km horizontal radius with only an **8 m thick** full-detail slab is `π×6000²×8/(0.25³) ≈ 57.9 billion` voxels, **116 GB raw** per season. That slab is an intentionally generous lower bound for a mountainous/cave world. Sparse compressed meshes could be far smaller, but their disk, decompression, upload, and arbitrary composer/layout variants need an actual content budget. Prebake a few spawn hubs or far-field impostors, not every possible volume. | +| **Server-streamed chunk data** | Server could send already generated chunks, avoiding client generation. | A raw 34.7 MB 64 m cube in 1 s requires **278 Mb/s payload** before meshes/protocol, and this contradicts the explicit requirement that only seed, layout and edits replicate. Compression helps bandwidth, but latency/server scaling and the hard protocol rule remain. | +| **Far-field impostors, 2.5D clipmaps, Nanite** | Far view can be far cheaper if represented by coarse meshes/impostors; RMC locally contains a runtime Nanite proxy path, and Voxel Plugin 2 reports experimental Nanite memory savings. | An exterior heightfield loses caves/overhangs/islands when used as the whole world. Impostors are acceptable **beyond** interaction range if the world returns to 3D on approach, with a continuous crossfade and occlusion policy. Nanite can help mostly static far render, but Epic's dynamic mesh guidance says `UDynamicMeshComponent` is not Nanite-compatible, and Nanite fallback geometry still serves collision; runtime build/edit/VR costs here are unmeasured. [Geometry clipmaps](https://hhoppe.com/geomclipmap.pdf), [Epic dynamic mesh guidance](https://dev.epicgames.com/documentation/unreal-engine/working-with-meshes-in-unreal-engine), [Nanite fallback](https://dev.epicgames.com/documentation/unreal-engine/nanite-technical-details), [RMC code](https://github.com/TriAxis-Games/RealtimeMeshComponent). | + +### What was searched, and what was ruled out + +The source sweep covered SIGGRAPH closed-form interval rendering and GPU Gems 3 volumetric marching cubes; Eurographics 2025 Lipschitz pruning, derivative-aware procedural-noise tracing, proxy/LOD SDFs and adaptive contouring; older affine-interval ray tracing; JCGT SDF-grid ray tracing, cellular noise and SurfaceNets; HPG/i3D-style GPU mesh shader and SDF work; OpenVDB, SVO, DAG and GPU SVDAG editing; FastNoise2, ISPC, Inigo Quilez's analytic noise-derivative slides and table-free hashed noise; UE 5.7 Mover/CMC source, RMC local source, Epic RDG/Nanite/dynamic mesh documentation; Voxel Plugin 2; and developer material for No Man's Sky, Astroneer, Teardown, Enshrouded, Space Engineers, Vintage Story, Dual Universe, Sebastian Lague, Nick Gildea and 0fps. Quilez's derivative formula is useful for normal or local bound construction, but a sampled derivative is **not** a certified maximum over a brick. The strongest transferable ideas were **region-pruned expression trees, fused SIMD evaluation, sparse near-surface work, direct player field collision, and whole-region render transactions**. No retrieved shipped-game account publishes a directly comparable **cold 64 m, 25 cm, 3D editable, UE/VR, all-visible-and-player-collidable <1 s** measurement; their performance figures must not be presented as proof of this target. [Quilez noise-derivative slides](https://iquilezles.org/articles/function2009/function2009.pdf), [NMS GDC](https://www.gdcvault.com/play/1024265/), [Astroneer developer](https://www.gamedeveloper.com/design/what-i-astroneer-i-s-devs-learned-while-leaving-early-access), [Teardown developer](https://blog.voxagon.se/2018/10/17/from-screen-space-to-voxel-space.html), [Space Engineers source](https://github.com/KeenSoftwareHouse/SpaceEngineers), [Vintage Story developer](https://www.vintagestory.at/blog.html/news/de-jank-and-game-juice-update-1170-pre1-r322/), [0fps smooth voxel terrain](https://0fps.net/2012/07/12/smooth-voxel-terrain-part-2/). + +Specifically ruled out as a **complete** answer: greedy block meshing (different surface model), heightfield-only terrain, unbounded generic interval recursion (failed local control), auto-selected float SIMD noise (vendor/CPU parity risk), CUDA-only edit structures (AMD target), Nanite or another UE mesh component alone (density/cook bottlenecks), and one tile at a time crater updates. Isosurface mesher alternatives, affine arithmetic, full GPU generation, and far impostors remain research branches with explicit benchmark gates. [0fps block meshing](https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/), [FastNoise2 determinism FAQ](https://github.com/Auburn/FastNoise2/wiki/FAQ), [SVDAG editor code](https://github.com/mathijs727/GPU-SVDAG-Editing), [Epic PMC async cooking](https://dev.epicgames.com/documentation/unreal-engine/API/Plugins/ProceduralMeshComponent/UProceduralMeshComponent). + +### Revised gates and migration sequence + +1. **Freeze the numeric ABI and world-version rule.** A new integer kernel changes the existing float-generated world's terrain. Treat it as a new season/build version, or demonstrate exact backwards parity (unlikely); keep older season serialization explicit. Specify signed division, saturation, noise hash, fade table, zero tie, interpolation, material ID and stable op ordering. Run scalar/AVX2 hashes across different CPU models and CPU/GPU hashes across AMD/NVIDIA before enabling any GPU canonical path. Integer intrinsics are promising precisely because bitwise multiplication/shift can be matched, but the round-two parity test covers only one CPU. +2. **First cheap kill test (standalone, before UE):** extract two real seeded composer plans including warped rooms, passages, strata boundaries and edits, record original density/sign/route references, compile regional operator programs, and benchmark a cold 259³ ring with six workers. Record classifying cost, uncertain-brick fraction, branch count, worker wall, memory, and exact sign parity at all lattice points. A plausible initial gate is **≤0.35 s worker wall** for the production plan, reserving ≥0.65 s for mesh/upload/scene work; this is a budget decision, not a measured UE limit. If value compatibility with old seasons is required, benchmark that exact math separately. The existing round-two probe establishes only a lower-complexity feasibility bound. +3. **UE/VR gate when implementation is authorized:** measure render-thread upload and first visible frame for a cold 512-tile cube, plus Mover/field capsule sweeps under repeated underfoot edits. Implement one radius-10 m transaction with GPU direct mesh or exact local overlay and measure the *same frame* in PC and Quest 3 stereo, with screen captures at tile borders, occlusion and shadows. Fail the architecture if p99 edit frame exceeds the VR budget or any tile shows a different edit sequence. No standalone CPU result can substitute for this gate. +4. **Port in slices:** keep the composer/content schema and route graph; replace the evaluator with compiled per-region plans; add brick caches and shared lattice; move player terrain collision to canonical field queries while retaining ordinary sweeps for other actors; replace tile components with batched render pages; add transaction visual path; then optionally background Chaos bodies and far Nanite/impostors. Recheck multiplayer late join by replaying the ordered edit log and comparing region hashes. ## What not to do @@ -104,4 +172,4 @@ Keep RMC for the first experiment, but reduce component count by grouping spatia - Do not claim AVX2, dual contouring, Nanite or a different mesh component will erase the observed 97% density cost. Benchmark each in its proper stage. - Do not publish one touched tile while its neighbors still show the old edit; do not suppress collision under a pawn before a consistent replacement exists. Those are the visible ripple, vanish and false-support failure modes in the present implementation. -**Decision still required:** whether “all 512 tiles collidable” includes general Chaos rigid bodies or means exact player/projectile queries anywhere in the cube, and whether interactive dig tools may have a bounded brush extent. With unrestricted rigid-body cooking and unbounded same-frame edit size, no honest sub-second guarantee follows from the available evidence. The research recommendation preserves the full 3D game by changing the collision and edit contracts in implementation, but its final deadline must be proven by the two UE integration spikes above. +The owner has clarified both contracts: exact collision inside one second applies to the player, while bounded digging and radius-scale spells both require atomic same-frame visuals. The field-aware movement and transaction-wide GPU edit path above are therefore required parts of the proposed architecture. Their deadlines remain unproved until the authorized UE/VR integration gate can be run. diff --git a/Saved/Research/round2_probe-results.txt b/Saved/Research/round2_probe-results.txt new file mode 100644 index 0000000..8b90dca --- /dev/null +++ b/Saved/Research/round2_probe-results.txt @@ -0,0 +1,31 @@ +Machine: Ryzen 7 5800X3D, Windows, MSVC 2022, 2026-09-29. +Command from Saved/Research: +cmd /c '"E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul && cl /nologo /O2 /std:c++20 /EHsc /arch:AVX2 round2_probe.cpp /Fe:round2_probe.exe' +.\round2_probe.exe + +First run: +full trial=0 scalar_ms=492.007 avx2_ms=101.294 speedup=4.857 mismatch=0 +full trial=1 scalar_ms=496.238 avx2_ms=106.015 speedup=4.681 mismatch=0 +full trial=2 scalar_ms=469.590 avx2_ms=92.511 speedup=5.076 mismatch=0 +crater radius_vox=40 touched_bricks=714 tile_AABB_max=64 samples_AABB=531441 +crater copy_ms=1.623 edit_ms=0.865 changed_lattice=94843 copy_bytes=33554432 + +Second run after dead-code cleanup (same evaluation code): +full trial=0 scalar_ms=430.286 avx2_ms=89.209 speedup=4.823 mismatch=0 +full trial=1 scalar_ms=456.202 avx2_ms=107.464 speedup=4.245 mismatch=0 +full trial=2 scalar_ms=447.117 avx2_ms=94.584 speedup=4.727 mismatch=0 +crater radius_vox=40 touched_bricks=714 tile_AABB_max=64 samples_AABB=531441 +crater copy_ms=1.422 edit_ms=0.914 changed_lattice=94843 copy_bytes=33554432 + +Third run after adding a scattered direct-query measurement (same field evaluation code): +full trial=0 scalar_ms=478.627 avx2_ms=85.763 speedup=5.581 mismatch=0 +full trial=1 scalar_ms=471.015 avx2_ms=80.318 speedup=5.864 mismatch=0 +full trial=2 scalar_ms=444.320 avx2_ms=82.728 speedup=5.371 mismatch=0 +random_query trial=0 count=200000 ms=63.030 ns_per_query=315.1 checksum=-1501231 +random_query trial=1 count=200000 ms=62.785 ns_per_query=313.9 checksum=-1501231 +random_query trial=2 count=200000 ms=62.799 ns_per_query=314.0 checksum=-1501231 +crater radius_vox=40 touched_bricks=714 tile_AABB_max=64 samples_AABB=531441 +crater copy_ms=1.394 edit_ms=0.861 changed_lattice=94843 copy_bytes=33554432 + +Both MSVC builds succeeded. The vcvars script emitted a missing-vswhere.exe notice. +Synthetic workload; no Unreal build/launch or GPU benchmark. diff --git a/Saved/Research/round2_probe.cpp b/Saved/Research/round2_probe.cpp new file mode 100644 index 0000000..7ab663e --- /dev/null +++ b/Saved/Research/round2_probe.cpp @@ -0,0 +1,125 @@ +// Standalone research probe. Synthetic operator composition inspired by VoxelForge; +// NOT extracted production code. Compile with MSVC /O2 /arch:AVX2 /std:c++20. +#include +#include +#include +#include +#include +#include +#include +#include +constexpr int N=256, B=8, W=6; +using V=__m256i; +static std::vector scalarField(size_t(N)*N*N), vectorField(size_t(N)*N*N); +alignas(32) static int32_t fadeTable[256]; +static inline uint32_t hashS(uint32_t x,uint32_t y,uint32_t z,uint32_t seed){ + uint32_t h=seed^(x*0x9e3779b1u)^(y*0x85ebca77u)^(z*0xc2b2ae3du); + h^=h>>16; h*=0x7feb352du; h^=h>>15; h*=0x846ca68bu; return h^(h>>16); +} +static inline V hashV(V x,V y,V z,V seed){ + V h=_mm256_xor_si256(seed,_mm256_xor_si256(_mm256_mullo_epi32(x,_mm256_set1_epi32(0x9e3779b1u)), + _mm256_xor_si256(_mm256_mullo_epi32(y,_mm256_set1_epi32(0x85ebca77u)),_mm256_mullo_epi32(z,_mm256_set1_epi32(0xc2b2ae3du))))); + h=_mm256_xor_si256(h,_mm256_srli_epi32(h,16)); h=_mm256_mullo_epi32(h,_mm256_set1_epi32(0x7feb352du)); + h=_mm256_xor_si256(h,_mm256_srli_epi32(h,15)); h=_mm256_mullo_epi32(h,_mm256_set1_epi32(0x846ca68bu)); + return _mm256_xor_si256(h,_mm256_srli_epi32(h,16)); +} +static inline int lerpS(int a,int b,int t){return a+((b-a)*t>>8);} +static inline V lerpV(V a,V b,V t){return _mm256_add_epi32(a,_mm256_srai_epi32(_mm256_mullo_epi32(_mm256_sub_epi32(b,a),t),8));} +static inline int gradS(uint32_t h,int x,int y,int z){ + h&=15;int u=(h&8)?y:x;int v=(h&12)==0?y:((h&13)==12?x:z); + return ((h&1)?-u:u)+((h&2)?-v:v); +} +static inline V selectV(V mask,V a,V b){return _mm256_blendv_epi8(b,a,mask);} +static inline V gradV(V h,V x,V y,V z){ + V zero=_mm256_setzero_si256(); h=_mm256_and_si256(h,_mm256_set1_epi32(15)); + V u=selectV(_mm256_cmpeq_epi32(_mm256_and_si256(h,_mm256_set1_epi32(8)),zero),x,y); + V isY=_mm256_cmpeq_epi32(_mm256_and_si256(h,_mm256_set1_epi32(12)),zero); + V isX=_mm256_cmpeq_epi32(_mm256_and_si256(h,_mm256_set1_epi32(13)),_mm256_set1_epi32(12)); + V v=selectV(isY,y,selectV(isX,x,z)); + V negU=_mm256_cmpeq_epi32(_mm256_and_si256(h,_mm256_set1_epi32(1)),_mm256_set1_epi32(1)); + V negV=_mm256_cmpeq_epi32(_mm256_and_si256(h,_mm256_set1_epi32(2)),_mm256_set1_epi32(2)); + return _mm256_add_epi32(_mm256_sub_epi32(_mm256_xor_si256(u,negU),negU),_mm256_sub_epi32(_mm256_xor_si256(v,negV),negV)); +} +static inline int noiseS(int x,int y,int z,int shift,int seed){ + int ix=x>>shift,iy=y>>shift,iz=z>>shift,fx=(x&((1<>8);} +static inline V smoothMaxV(V a,V b){V d=_mm256_sub_epi32(a,b);V h=_mm256_max_epi32(_mm256_setzero_si256(),_mm256_sub_epi32(_mm256_set1_epi32(64),_mm256_abs_epi32(d))); + return _mm256_add_epi32(_mm256_max_epi32(a,b),_mm256_srai_epi32(_mm256_mullo_epi32(h,h),8));} +static inline V evalV(V x,V y,V z){ + V c=_mm256_set1_epi32(1024), warp=_mm256_srai_epi32(noiseV(_mm256_add_epi32(x,c),_mm256_add_epi32(y,c),_mm256_add_epi32(z,c),4,17),4); + V nx=_mm256_add_epi32(_mm256_add_epi32(x,c),warp),ny=_mm256_sub_epi32(_mm256_add_epi32(y,c),warp),nz=_mm256_add_epi32(z,c); + V fb=_mm256_add_epi32(noiseV(nx,ny,nz,4,100),_mm256_add_epi32(_mm256_srai_epi32(noiseV(nx,ny,nz,3,101),1),_mm256_srai_epi32(noiseV(nx,ny,nz,2,102),2))); + V ridge=_mm256_sub_epi32(_mm256_set1_epi32(128),_mm256_abs_epi32(noiseV(nx,ny,nz,3,202))); + // Scalar signed division truncates toward zero; AVX2 shift rounds negative down. + // Correct sign before shift to make the two exact. + auto divPow2=[](V a,int shift){V bias=_mm256_and_si256(_mm256_srai_epi32(a,31),_mm256_set1_epi32((1<>4; int nx=x+1024+warp,ny=y+1024-warp,nz=z+1024; + int fb=noiseS(nx,ny,nz,4,100)+(noiseS(nx,ny,nz,3,101)>>1)+(noiseS(nx,ny,nz,2,102)>>2); + int ridge=128-std::abs(noiseS(nx,ny,nz,3,202)); + int stratum=std::min(z-84+fb/4,170-z+ridge/4); + int dy=y-128,dz=z-128,dx=x-128; + int passage=(18*18-dy*dy-dz*dz)/8,room=(35*35-dx*dx-dy*dy-dz*dz)/16; + return smoothMaxS(stratum,smoothMaxS(passage,room)); +} +static inline size_t idx(int x,int y,int z){return(size_t(z)*N+y)*N+x;} +template static double ms(F&& f){auto t=std::chrono::steady_clock::now();f();return std::chrono::duration(std::chrono::steady_clock::now()-t).count();} +template static void parallel(F fn){std::array threads;for(int k=0;k points(200000);uint32_t rng=0x12345678; + for(auto& p:points){rng^=rng<<13;rng^=rng>>17;rng^=rng<<5;p.x=int(rng&255); + rng^=rng<<13;rng^=rng>>17;rng^=rng<<5;p.y=int(rng&255); + rng^=rng<<13;rng^=rng>>17;rng^=rng<<5;p.z=int(rng&255);} + for(int t=0;t<3;++t){int64_t checksum=0;double q=ms([&]{for(const auto& p:points)checksum+=evalS(p.x,p.y,p.z);}); + std::printf("random_query trial=%d count=%zu ms=%.3f ns_per_query=%.1f checksum=%lld\n",t,points.size(),q,q*1e6/points.size(),(long long)checksum);} + // Radius 10m at 25cm grid, center on tile boundary. Count exact AABB touched bricks. + const int cx=128,cy=128,cz=128,r=40;int touched=0;for(int bz=0;bz next(vectorField.size());double copy=ms([&]{next=vectorField;});size_t changed=0;double edit=ms([&]{parallel([&](int za,int zb){for(int z=std::max(za,cz-r);z=0){int d=std::max(vectorField[idx(x,y,z)],q/16);next[idx(x,y,z)]=(int16_t)d;}}});}); + for(int z=cz-r;z<=cz+r;++z)for(int y=cy-r;y<=cy+r;++y)for(int x=cx-r;x<=cx+r;++x)changed+=next[idx(x,y,z)]!=vectorField[idx(x,y,z)]; + std::printf("crater copy_ms=%.3f edit_ms=%.3f changed_lattice=%zu copy_bytes=%zu\n",copy,edit,changed,vectorField.size()*sizeof(int16_t)); +}