research(step2e): 8 parameter profiles, worst 570 ms -- speed gate met, look NOT yet accepted
Editor-only, default off. Seeded chamber graph (jittered XY grid, spanning tree, optional loops, tunnels, shafts, pillars, ledges, spires, floating masses, basins), 8 profiles, four detail bands at every surface-affecting 25 cm sample, sound brick proofs. 259^3 ring, six workers, medians of 3: 404-570 ms (worst TerracedBasin 570.0 ms). Detail, seam, bound-audit (0 violations, undersized control caught), determinism (1 vs 6 workers) and TraversalSeeds all pass; live tests untouched. Not accepted yet: the profiles are 81-97% open air. In the slices a "TightNetwork" is a large void with scattered solid blobs (rooms of 0.5-0.76 x pitch overlap and merge), and the finest detail band shows as salt-and-pepper speckle with 22-109 separate 1 m components per ring: fast partly because air bricks skip, and the look needs the owner's judgement. Also missing vs live: maze, flat/plain, crystal-chamber, surface-world and underwater grammars; water geometry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
No files matched your search
@@ -119,9 +119,9 @@ remains `0`, and lateral regions remain gated off.
|
|||||||
| `VoxelForge.Build.cs` | Deps: Core, CoreUObject, Engine, **GameplayTags**, **RealtimeMeshComponent**. |
|
| `VoxelForge.Build.cs` | Deps: Core, CoreUObject, Engine, **GameplayTags**, **RealtimeMeshComponent**. |
|
||||||
| `Tools/VoxelForgeTest.ps1` | The single guarded test entry point. `-Scenario canonical|owner|probe|perf|tests|surface-fall|crossing|gate-stress|visual-edit|visual-lod|visual-gap-walk|visual-gap-inject|dig-motion|parity|horizon|horizon-render|determinism|region-eval|step2d|step2e`, optional `-Build`, `-Assets owner|default`, `-Cvars`, absolute `-Out`, `-Label`, `-HorizonLevel`, `-HorizonRenderDistanceChunks`, `-ParityExportSize=32|64|128`, `-ParityExportTile=x,y,z`, `-SharedDDC`, `-SampleDensityStacks`, `-StackSampleIntervalUs`, and `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH`; stages the host/assets, isolates user/DDC/config state, serializes one Unreal launch at a time, enforces the 8 GiB/30-minute guards, waits for 6 GiB free RAM before launches, and emits compact `result.json`/`summary.txt` plus full logs. Parity can render its game leg with `-EnableRender` and compares the selected export region against the exact streamed tile hashes. `visual-gap-walk` records camera-frustum surface-point coverage at 6000 cm/s; `visual-gap-inject` proves an early component hide is detected; `dig-motion` logs per-frame vertical velocity, gate, support readiness, and movement mode. `-Cvars @{ 'voxel.TestGapAuditLegacyHandoff'=1 }` replays the old visibility handoff for A/B audit baselines. Horizon traces report desired/loaded tiles, resident stream geometry, worker seconds, steady wall time, and peak private memory; `horizon-render` captures the owner view; `determinism` compares per-tile hashes across the default CRT path and `-voxel.CrtFma3=0`; `region-eval` compares the live path with the default-off editor chunk program on the 259³ lattice and five-seed probe set; `step2d` retains the earlier independent field; `step2e` measures eight room-network profiles on the 259³ ring, emits variety metrics and live/new slices, and checks detail, boundaries, bounds, and 1-vs-6-worker hashes. `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH` checks a full-ring hash at another partition count. `-SampleDensityStacks` captures profiles, and `-StackSampleIntervalUs` sets the sampling interval.
|
| `Tools/VoxelForgeTest.ps1` | The single guarded test entry point. `-Scenario canonical|owner|probe|perf|tests|surface-fall|crossing|gate-stress|visual-edit|visual-lod|visual-gap-walk|visual-gap-inject|dig-motion|parity|horizon|horizon-render|determinism|region-eval|step2d|step2e`, optional `-Build`, `-Assets owner|default`, `-Cvars`, absolute `-Out`, `-Label`, `-HorizonLevel`, `-HorizonRenderDistanceChunks`, `-ParityExportSize=32|64|128`, `-ParityExportTile=x,y,z`, `-SharedDDC`, `-SampleDensityStacks`, `-StackSampleIntervalUs`, and `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH`; stages the host/assets, isolates user/DDC/config state, serializes one Unreal launch at a time, enforces the 8 GiB/30-minute guards, waits for 6 GiB free RAM before launches, and emits compact `result.json`/`summary.txt` plus full logs. Parity can render its game leg with `-EnableRender` and compares the selected export region against the exact streamed tile hashes. `visual-gap-walk` records camera-frustum surface-point coverage at 6000 cm/s; `visual-gap-inject` proves an early component hide is detected; `dig-motion` logs per-frame vertical velocity, gate, support readiness, and movement mode. `-Cvars @{ 'voxel.TestGapAuditLegacyHandoff'=1 }` replays the old visibility handoff for A/B audit baselines. Horizon traces report desired/loaded tiles, resident stream geometry, worker seconds, steady wall time, and peak private memory; `horizon-render` captures the owner view; `determinism` compares per-tile hashes across the default CRT path and `-voxel.CrtFma3=0`; `region-eval` compares the live path with the default-off editor chunk program on the 259³ lattice and five-seed probe set; `step2d` retains the earlier independent field; `step2e` measures eight room-network profiles on the 259³ ring, emits variety metrics and live/new slices, and checks detail, boundaries, bounds, and 1-vs-6-worker hashes. `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH` checks a full-ring hash at another partition count. `-SampleDensityStacks` captures profiles, and `-StackSampleIntervalUs` sets the sampling interval.
|
||||||
| `Public/VoxelForgeModule.h` / `Private/VoxelForgeModule.cpp` | `FVoxelForgeModule` boilerplate (Startup/Shutdown just log). |
|
| `Public/VoxelForgeModule.h` / `Private/VoxelForgeModule.cpp` | `FVoxelForgeModule` boilerplate (Startup/Shutdown just log). |
|
||||||
| `Source/VoxelForgeEditor/VoxelForgeEditor.Build.cs` / `Private/VoxelForgeExploreCommandlet.*` | Editor/commandlet-only `-run=VoxelForgeExplore`; owns bounded render/`VF_` walk/OBJ export orchestration and is not linked by Game/Shipping. Optional `-exporttilex/y/z` sets an exact L0 tile origin for controlled export/game parity; omitting all three preserves the existing center-derived origin. `-regioneval=1` retains the exact-field step-2c research harness. `-step2d` retains the earlier independent field benchmark; `-step2e` measures eight room-network profiles and writes timing, variety, and side-by-side slice evidence under `Saved/Research/step2e`. |
|
| `Source/VoxelForgeEditor/VoxelForgeEditor.Build.cs` / `Private/VoxelForgeExploreCommandlet.*` | Editor/commandlet-only `-run=VoxelForgeExplore`; owns bounded render/`VF_` walk/OBJ export orchestration and is not linked by Game/Shipping. Optional `-exporttilex/y/z` sets an exact L0 tile origin for controlled export/game parity; omitting all three preserves the existing center-derived origin. `-regioneval=1` retains the exact-field step-2c research harness. `-step2d` retains the earlier independent field benchmark; `-step2e` measures eight room-network profiles and writes timing, per-profile parameter ranges, nominal chamber-volume quantiles, vertical-run and tunnel metrics, and side-by-side live/new slice evidence under `Saved/Research/step2e`. The report records 12.5 cm scaling guidance and notes that basin water levels are parameters without water rendering or simulation. Its hardest-profile gates include full-detail parity, seam injection, sound and undersized-bound controls, and repeated / 1-vs-6-worker hash checks. |
|
||||||
| `Source/VoxelForgeEditor/Private/VoxelForgeRegionEvalExperiment.*` | Six-worker lattice drivers for step 2c, step 2d, and step 2e. The original path still compares live `GetDensityAt` with the editor chunk program. Research modes assign contiguous batches of 8³ bricks dynamically so surface-heavy work balances across workers. Each skip requires a macro Lipschitz bound plus the complete detail-amplitude supremum; uncertain bricks retain all 25 cm detail samples. Timings split classification, point evaluation, and uniform fill; step 2e hashes compare workers 1 and 6. |
|
| `Source/VoxelForgeEditor/Private/VoxelForgeRegionEvalExperiment.*` | Six-worker lattice drivers for step 2c, step 2d, and step 2e. The original path still compares live `GetDensityAt` with the editor chunk program. Research modes assign contiguous batches dynamically so surface-heavy work balances across workers; step 2e uses 4³ proof bricks and stages each evaluated brick before copying contiguous X rows, while step 2d retains 8³. Each skip requires a macro Lipschitz bound plus the complete detail-amplitude supremum; uncertain bricks retain all 25 cm detail samples. Timings split classification, point evaluation, and uniform fill; step 2e hashes compare workers 1 and 6. |
|
||||||
| `Public/VoxelRedefinedDensityField.h` / `Private/VoxelRedefinedDensityField.cpp` | Two default-off `WITH_EDITOR` research fields, selected by `voxel.ResearchRedefinedDensityField` (step 2d) and `voxel.ResearchParameterizedCave` (step 2e). Step 2e deterministically assigns one of eight parameter profiles per strate, then builds jittered rooms and a root-connected tunnel graph with optional loops and shafts, pillars, ledges, floating masses, stalactites/stalagmites, and basin floors; four bounded world-space value-noise bands, including a one-sample micro band, are evaluated at full resolution. Step 2e proofs include the model Lipschitz bound, passage/refinement fallback, and full detail supremum; a local derivative bound permits sound proofs through landing-floor blends. The public API adds no reflected class layout. |
|
| `Public/VoxelRedefinedDensityField.h` / `Private/VoxelRedefinedDensityField.cpp` | Two default-off `WITH_EDITOR` research fields, selected by `voxel.ResearchRedefinedDensityField` (step 2d) and `voxel.ResearchParameterizedCave` (step 2e). Step 2e deterministically assigns one of eight parameter profiles per strate, then builds jittered rooms and a root-connected tunnel graph with optional loops and shafts, pillars, ledges, floating masses, stalactites/stalagmites, and basin floors. The room evaluator checks the containing cell first, then cardinal and diagonal neighbors, with horizontal/vertical upper-bound rejection before feature work. A padded thread-local generated-cell cache is reused across adjacent proof bricks, and XY-dependent room/tunnel distances are reused through each vertical column while four bounded world-space value-noise bands, including a one-sample micro band, remain evaluated at full resolution. Step 2e proofs include the model Lipschitz interval, passage/refinement fallback, and full detail supremum; a local derivative bound permits sound proofs through landing-floor blends. The basin has a water-level parameter, but this field does not render or simulate water. The public API adds no reflected class layout. |
|
||||||
| `Private/Tests/VoxelForgeParameterizedGenerationTest.cpp` | Separate three-seed functional sweep for the step 2e field; passage landing air/floor brackets and arrival-to-exit walking routes are checked without changing the live-world tests. |
|
| `Private/Tests/VoxelForgeParameterizedGenerationTest.cpp` | Separate three-seed functional sweep for the step 2e field; passage landing air/floor brackets and arrival-to-exit walking routes are checked without changing the live-world tests. |
|
||||||
| `Private/Tests/VoxelForgeRedefinedDensityFieldTest.cpp` | Three-seed functional sweep for the research field: authored passage endpoints must bracket open air and solid floor, and each tested strate must have a walkable arrival-to-exit route. |
|
| `Private/Tests/VoxelForgeRedefinedDensityFieldTest.cpp` | Three-seed functional sweep for the research field: authored passage endpoints must bracket open air and solid floor, and each tested strate must have a walkable arrival-to-exit route. |
|
||||||
| `Public/VoxelGeometryHash.h` | Header-only geometry digest shared by commandlet export and runtime tile-hash dump; hashes mesh counts and the vertex/normal/UV/color/triangle arrays with the historical CRC order. |
|
| `Public/VoxelGeometryHash.h` | Header-only geometry digest shared by commandlet export and runtime tile-hash dump; hashes mesh counts and the vertex/normal/UV/color/triangle arrays with the historical CRC order. |
|
||||||
|
|||||||
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
@@ -0,0 +1,815 @@
|
|||||||
|
{
|
||||||
|
"status": "pass",
|
||||||
|
"pass": true,
|
||||||
|
"worst_profile_meets_600ms": true,
|
||||||
|
"seed": 0,
|
||||||
|
"ring_dimension": 259,
|
||||||
|
"ring_samples": 17373979,
|
||||||
|
"workers_requested": 6,
|
||||||
|
"world_prepare_ms_excluded": 134.9404975771904,
|
||||||
|
"old_live_ring_ms": 9188.3964985609055,
|
||||||
|
"old_live_ring_raw_float_hash": "cf1e3a48b3bc1bda",
|
||||||
|
"field_definition": "Seeded jittered XY chamber cells form a deterministic origin-rooted spanning tree; selected loops, horizontal tunnels and full-strate shafts open the network. Each chamber can add pillars, annular ledges, paired stalactites/stalagmites, floating rock masses and a bowl floor with an explicit water level. Passage pads and anchor tunnels join the authored inter-strate route to the generated network.",
|
||||||
|
"parameter_space": "Eight named profiles can be assigned per strate from a stable seed hash (-1 mode), or forced for measurement. Each profile supplies nominal room, tunnel, shaft, feature-probability and basin values. Per-cell hashes deterministically roll room jitter and feature presence. Profile minima and maxima are recorded below; room height is clamped to the strate span, room radii to 0.20-0.72/0.80 of pitch, loop probability to 0-0.8, probabilities and water level to 0-1, and basin depth to 0-48 voxels.",
|
||||||
|
"parameter_ranges_across_eight_profiles":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 96,
|
||||||
|
"maximum_across_profiles": 176
|
||||||
|
},
|
||||||
|
"room_radius_fraction_min":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.5,
|
||||||
|
"maximum_across_profiles": 0.62000000476837158
|
||||||
|
},
|
||||||
|
"room_radius_fraction_max":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.62000000476837158,
|
||||||
|
"maximum_across_profiles": 0.75999999046325684
|
||||||
|
},
|
||||||
|
"room_height_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 216,
|
||||||
|
"maximum_across_profiles": 340
|
||||||
|
},
|
||||||
|
"floor_relief_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 8,
|
||||||
|
"maximum_across_profiles": 20
|
||||||
|
},
|
||||||
|
"tunnel_radius_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 20,
|
||||||
|
"maximum_across_profiles": 40
|
||||||
|
},
|
||||||
|
"tunnel_half_height_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 22,
|
||||||
|
"maximum_across_profiles": 36
|
||||||
|
},
|
||||||
|
"loop_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.11999999731779099,
|
||||||
|
"maximum_across_profiles": 0.40000000596046448
|
||||||
|
},
|
||||||
|
"vertical_shaft_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.029999999329447746,
|
||||||
|
"maximum_across_profiles": 0.92000001668930054
|
||||||
|
},
|
||||||
|
"shaft_radius_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 14,
|
||||||
|
"maximum_across_profiles": 28
|
||||||
|
},
|
||||||
|
"pillar_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.039999999105930328,
|
||||||
|
"maximum_across_profiles": 0.72000002861022949
|
||||||
|
},
|
||||||
|
"ledge_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.079999998211860657,
|
||||||
|
"maximum_across_profiles": 0.8399999737739563
|
||||||
|
},
|
||||||
|
"floating_mass_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.019999999552965164,
|
||||||
|
"maximum_across_profiles": 0.72000002861022949
|
||||||
|
},
|
||||||
|
"stalactite_stalagmite_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.11999999731779099,
|
||||||
|
"maximum_across_profiles": 0.75
|
||||||
|
},
|
||||||
|
"basin_probability":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0,
|
||||||
|
"maximum_across_profiles": 0.85000002384185791
|
||||||
|
},
|
||||||
|
"basin_depth_voxels":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0,
|
||||||
|
"maximum_across_profiles": 48
|
||||||
|
},
|
||||||
|
"water_level_fraction":
|
||||||
|
{
|
||||||
|
"minimum_across_profiles": 0.30000001192092896,
|
||||||
|
"maximum_across_profiles": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resolution_contract": "One exact field sample per 25 cm lattice point. The four existing 8/4/2/1-sample detail bands are evaluated for every potentially surface-affecting point; no coarse field is interpolated onto the lattice. 4-cubed step 2e skips require the final macro field Lipschitz interval plus the full 5.25-unit detail supremum and marching-cubes halo.",
|
||||||
|
"finer_lattice_scaling": "For 12.5 cm voxels, double room pitch, room height, tunnel/feature dimensions and the broad-to-medium noise periods in sample units to preserve meter-scale shapes. Keep the 1-sample detail band or add a finer octave. The lattice grows 8x for a fixed world volume; surface bricks grow roughly with area while certified interior bricks remain cheap. This scale has not been timed.",
|
||||||
|
"variety_metric_method": "Open fraction uses every ring sample. Surface area estimates sign-changing lattice edges times 0.25 m squared. Nominal chamber-volume p10/p50/p90 values use the uniform per-cell radius roll and room height as circular-cylinder volumes. Tunnel-neck share and connected-component sizes use a 1 m downsampled six-neighbor occupancy grid. Verticality is the mean longest contiguous open run per XY column, with open-column coverage reported separately.",
|
||||||
|
"water_geometry_limit": "Basin profiles generate the bowl floor and water-level parameter; this density field does not render or simulate water.",
|
||||||
|
"worst_six_worker_ring_median_ms": 570.03279775381088,
|
||||||
|
"target_aim_ms": 350,
|
||||||
|
"hardest_profile": "HyperComplex",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"profile_index": 0,
|
||||||
|
"name": "OpenVaults",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 176,
|
||||||
|
"room_radius_fraction_min": 0.62000000476837158,
|
||||||
|
"room_radius_fraction_max": 0.75999999046325684,
|
||||||
|
"room_height_voxels": 340,
|
||||||
|
"floor_relief_voxels": 12,
|
||||||
|
"tunnel_radius_voxels": 40,
|
||||||
|
"tunnel_half_height_voxels": 36,
|
||||||
|
"loop_probability": 0.34999999403953552,
|
||||||
|
"vertical_shaft_probability": 0.14000000059604645,
|
||||||
|
"shaft_radius_voxels": 22,
|
||||||
|
"pillar_probability": 0.039999999105930328,
|
||||||
|
"ledge_probability": 0.11999999731779099,
|
||||||
|
"floating_mass_probability": 0.079999998211860657,
|
||||||
|
"stalactite_stalagmite_probability": 0.15000000596046448,
|
||||||
|
"basin_probability": 0,
|
||||||
|
"basin_depth_voxels": 0,
|
||||||
|
"water_level_fraction": 0.5
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 207803.41085068439,
|
||||||
|
"p50_m3": 246134.408195325,
|
||||||
|
"p90_m3": 287707.90649226471
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 404.54889833927155,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
403.37140113115311,
|
||||||
|
404.54889833927155,
|
||||||
|
422.8769987821579
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.97343389214410814,
|
||||||
|
"estimated_surface_area_m2": 33145,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.12209523218601795,
|
||||||
|
"vertical_air_adjacency_share": 0.33298452070631224,
|
||||||
|
"vertical_air_column_share": 1,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 241.88837375709963,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.014380675966669787,
|
||||||
|
"one_meter_connected_components": 22,
|
||||||
|
"largest_component_coarse_m3": 267001,
|
||||||
|
"components_1_to_8_coarse_m3": 21,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 213327,
|
||||||
|
"skipped_sample_fraction": 0.75428248186555302,
|
||||||
|
"evaluated_samples": 4269091,
|
||||||
|
"worker_cpu_seconds": 1.609375,
|
||||||
|
"brick_classification_worker_ms": 242.50604957342148,
|
||||||
|
"density_evaluation_worker_ms": 2076.3386078178883,
|
||||||
|
"uniform_fill_worker_ms": 53.428228944540024,
|
||||||
|
"longest_worker_ms": 399.43369850516319,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_00_openvaults"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 1,
|
||||||
|
"name": "TightNetwork",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 104,
|
||||||
|
"room_radius_fraction_min": 0.51999998092651367,
|
||||||
|
"room_radius_fraction_max": 0.63999998569488525,
|
||||||
|
"room_height_voxels": 256,
|
||||||
|
"floor_relief_voxels": 8,
|
||||||
|
"tunnel_radius_voxels": 20,
|
||||||
|
"tunnel_half_height_voxels": 22,
|
||||||
|
"loop_probability": 0.11999999731779099,
|
||||||
|
"vertical_shaft_probability": 0.029999999329447746,
|
||||||
|
"shaft_radius_voxels": 14,
|
||||||
|
"pillar_probability": 0.059999998658895493,
|
||||||
|
"ledge_probability": 0.079999998211860657,
|
||||||
|
"floating_mass_probability": 0.019999999552965164,
|
||||||
|
"stalactite_stalagmite_probability": 0.11999999731779099,
|
||||||
|
"basin_probability": 0,
|
||||||
|
"basin_depth_voxels": 0,
|
||||||
|
"water_level_fraction": 0.5
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 38468.015011234471,
|
||||||
|
"p50_m3": 45722.767008321418,
|
||||||
|
"p90_m3": 53603.828575098079
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 561.79890036582947,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
553.03480103611946,
|
||||||
|
561.79890036582947,
|
||||||
|
575.50980150699615
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.89594007221949556,
|
||||||
|
"estimated_surface_area_m2": 92336.125,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.34013578582085313,
|
||||||
|
"vertical_air_adjacency_share": 0.33327139189444377,
|
||||||
|
"vertical_air_column_share": 0.99737630625661511,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 210.41539496300726,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.039870522719675165,
|
||||||
|
"one_meter_connected_components": 109,
|
||||||
|
"largest_component_coarse_m3": 245133,
|
||||||
|
"components_1_to_8_coarse_m3": 106,
|
||||||
|
"components_9_to_64_coarse_m3": 2,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 142897,
|
||||||
|
"skipped_sample_fraction": 0.50734353943906574,
|
||||||
|
"evaluated_samples": 8559403,
|
||||||
|
"worker_cpu_seconds": 2.328125,
|
||||||
|
"brick_classification_worker_ms": 241.08080938458443,
|
||||||
|
"density_evaluation_worker_ms": 3046.3547222316265,
|
||||||
|
"uniform_fill_worker_ms": 35.994317382574081,
|
||||||
|
"longest_worker_ms": 557.83749744296074,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_01_tightnetwork"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 2,
|
||||||
|
"name": "ChamberHalls",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 144,
|
||||||
|
"room_radius_fraction_min": 0.55000001192092896,
|
||||||
|
"room_radius_fraction_max": 0.72000002861022949,
|
||||||
|
"room_height_voxels": 320,
|
||||||
|
"floor_relief_voxels": 18,
|
||||||
|
"tunnel_radius_voxels": 34,
|
||||||
|
"tunnel_half_height_voxels": 32,
|
||||||
|
"loop_probability": 0.2800000011920929,
|
||||||
|
"vertical_shaft_probability": 0.18000000715255737,
|
||||||
|
"shaft_radius_voxels": 22,
|
||||||
|
"pillar_probability": 0.079999998211860657,
|
||||||
|
"ledge_probability": 0.2199999988079071,
|
||||||
|
"floating_mass_probability": 0.10000000149011612,
|
||||||
|
"stalactite_stalagmite_probability": 0.2199999988079071,
|
||||||
|
"basin_probability": 0.05000000074505806,
|
||||||
|
"basin_depth_voxels": 20,
|
||||||
|
"water_level_fraction": 0.40000000596046448
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 104715.5070092809,
|
||||||
|
"p50_m3": 131338.58696522861,
|
||||||
|
"p90_m3": 160973.92909046411
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 505.73009997606277,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
465.90260043740273,
|
||||||
|
505.73009997606277,
|
||||||
|
545.07719725370407
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.92935711502816942,
|
||||||
|
"estimated_surface_area_m2": 57662.9375,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.21241121564611076,
|
||||||
|
"vertical_air_adjacency_share": 0.33303864616767592,
|
||||||
|
"vertical_air_column_share": 1,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 224.23037819949016,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.026658600207423239,
|
||||||
|
"one_meter_connected_components": 50,
|
||||||
|
"largest_component_coarse_m3": 254470,
|
||||||
|
"components_1_to_8_coarse_m3": 49,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 185011,
|
||||||
|
"skipped_sample_fraction": 0.6521041610560252,
|
||||||
|
"evaluated_samples": 6044335,
|
||||||
|
"worker_cpu_seconds": 1.78125,
|
||||||
|
"brick_classification_worker_ms": 237.52568662166595,
|
||||||
|
"density_evaluation_worker_ms": 2464.1959294676781,
|
||||||
|
"uniform_fill_worker_ms": 46.43239825963974,
|
||||||
|
"longest_worker_ms": 461.93370223045349,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_02_chamberhalls"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 3,
|
||||||
|
"name": "ShaftForest",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 128,
|
||||||
|
"room_radius_fraction_min": 0.5,
|
||||||
|
"room_radius_fraction_max": 0.62000000476837158,
|
||||||
|
"room_height_voxels": 272,
|
||||||
|
"floor_relief_voxels": 12,
|
||||||
|
"tunnel_radius_voxels": 26,
|
||||||
|
"tunnel_half_height_voxels": 28,
|
||||||
|
"loop_probability": 0.11999999731779099,
|
||||||
|
"vertical_shaft_probability": 0.92000001668930054,
|
||||||
|
"shaft_radius_voxels": 28,
|
||||||
|
"pillar_probability": 0.05000000074505806,
|
||||||
|
"ledge_probability": 0.18000000715255737,
|
||||||
|
"floating_mass_probability": 0.039999999105930328,
|
||||||
|
"stalactite_stalagmite_probability": 0.20000000298023224,
|
||||||
|
"basin_probability": 0,
|
||||||
|
"basin_depth_voxels": 0,
|
||||||
|
"water_level_fraction": 0.5
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 57345.410351032719,
|
||||||
|
"p50_m3": 68601.687643874015,
|
||||||
|
"p90_m3": 80865.989806275087
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 548.60490188002586,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
546.6328002512455,
|
||||||
|
548.60490188002586,
|
||||||
|
578.33020016551018
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.85949580116333746,
|
||||||
|
"estimated_surface_area_m2": 93586.625,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.34474221477993039,
|
||||||
|
"vertical_air_adjacency_share": 0.33316652784439366,
|
||||||
|
"vertical_air_column_share": 0.99175623499947829,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 202.98173701298703,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.043446839263699355,
|
||||||
|
"one_meter_connected_components": 100,
|
||||||
|
"largest_component_coarse_m3": 235109,
|
||||||
|
"components_1_to_8_coarse_m3": 99,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 149078,
|
||||||
|
"skipped_sample_fraction": 0.52414844060764665,
|
||||||
|
"evaluated_samples": 8267435,
|
||||||
|
"worker_cpu_seconds": 2.09375,
|
||||||
|
"brick_classification_worker_ms": 232.56969451904297,
|
||||||
|
"density_evaluation_worker_ms": 2963.2366858422756,
|
||||||
|
"uniform_fill_worker_ms": 37.121176719665527,
|
||||||
|
"longest_worker_ms": 542.60710254311562,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_03_shaftforest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 4,
|
||||||
|
"name": "FloatingArchipelago",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 136,
|
||||||
|
"room_radius_fraction_min": 0.55000001192092896,
|
||||||
|
"room_radius_fraction_max": 0.68000000715255737,
|
||||||
|
"room_height_voxels": 216,
|
||||||
|
"floor_relief_voxels": 10,
|
||||||
|
"tunnel_radius_voxels": 28,
|
||||||
|
"tunnel_half_height_voxels": 28,
|
||||||
|
"loop_probability": 0.15000000596046448,
|
||||||
|
"vertical_shaft_probability": 0.10000000149011612,
|
||||||
|
"shaft_radius_voxels": 16,
|
||||||
|
"pillar_probability": 0.05000000074505806,
|
||||||
|
"ledge_probability": 0.10000000149011612,
|
||||||
|
"floating_mass_probability": 0.72000002861022949,
|
||||||
|
"stalactite_stalagmite_probability": 0.2800000011920929,
|
||||||
|
"basin_probability": 0,
|
||||||
|
"basin_depth_voxels": 0,
|
||||||
|
"water_level_fraction": 0.5
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 62161.040291956291,
|
||||||
|
"p50_m3": 74174.001993180806,
|
||||||
|
"p90_m3": 87247.530713802553
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 559.36940014362335,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
556.77210167050362,
|
||||||
|
559.36940014362335,
|
||||||
|
564.77300077676773
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.81436451603861149,
|
||||||
|
"estimated_surface_area_m2": 77448.0625,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.285293081107097,
|
||||||
|
"vertical_air_adjacency_share": 0.3339729720652625,
|
||||||
|
"vertical_air_column_share": 0.98258821424844589,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 196.60781636399497,
|
||||||
|
"longest_vertical_air_run_voxels": 248,
|
||||||
|
"one_meter_tunnel_neck_share": 0.034649779794953671,
|
||||||
|
"one_meter_connected_components": 65,
|
||||||
|
"largest_component_coarse_m3": 222906,
|
||||||
|
"components_1_to_8_coarse_m3": 64,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 150891,
|
||||||
|
"skipped_sample_fraction": 0.53115961519235178,
|
||||||
|
"evaluated_samples": 8145623,
|
||||||
|
"worker_cpu_seconds": 2.359375,
|
||||||
|
"brick_classification_worker_ms": 269.87878605723381,
|
||||||
|
"density_evaluation_worker_ms": 2985.2445237338543,
|
||||||
|
"uniform_fill_worker_ms": 37.513568997383118,
|
||||||
|
"longest_worker_ms": 552.79690027236938,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_04_floatingarchipelago"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 5,
|
||||||
|
"name": "PillaredCathedral",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 160,
|
||||||
|
"room_radius_fraction_min": 0.55000001192092896,
|
||||||
|
"room_radius_fraction_max": 0.72000002861022949,
|
||||||
|
"room_height_voxels": 248,
|
||||||
|
"floor_relief_voxels": 12,
|
||||||
|
"tunnel_radius_voxels": 32,
|
||||||
|
"tunnel_half_height_voxels": 34,
|
||||||
|
"loop_probability": 0.25,
|
||||||
|
"vertical_shaft_probability": 0.079999998211860657,
|
||||||
|
"shaft_radius_voxels": 18,
|
||||||
|
"pillar_probability": 0.72000002861022949,
|
||||||
|
"ledge_probability": 0.30000001192092896,
|
||||||
|
"floating_mass_probability": 0.079999998211860657,
|
||||||
|
"stalactite_stalagmite_probability": 0.44999998807907104,
|
||||||
|
"basin_probability": 0,
|
||||||
|
"basin_depth_voxels": 0,
|
||||||
|
"water_level_fraction": 0.5
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 100190.76287925025,
|
||||||
|
"p50_m3": 125663.46283710146,
|
||||||
|
"p90_m3": 154018.26548778973
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 500.73060020804405,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
499.61259961128235,
|
||||||
|
500.73060020804405,
|
||||||
|
516.76810160279274
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.92515940073370639,
|
||||||
|
"estimated_surface_area_m2": 67416.5625,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.248340348517746,
|
||||||
|
"vertical_air_adjacency_share": 0.33307025414258157,
|
||||||
|
"vertical_air_column_share": 1,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 220.65106363948064,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.029466147835377512,
|
||||||
|
"one_meter_connected_components": 50,
|
||||||
|
"largest_component_coarse_m3": 253593,
|
||||||
|
"components_1_to_8_coarse_m3": 49,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 173832,
|
||||||
|
"skipped_sample_fraction": 0.61222175990888439,
|
||||||
|
"evaluated_samples": 6737251,
|
||||||
|
"worker_cpu_seconds": 2.0625,
|
||||||
|
"brick_classification_worker_ms": 249.71644952893257,
|
||||||
|
"density_evaluation_worker_ms": 2656.6633693873882,
|
||||||
|
"uniform_fill_worker_ms": 43.705981224775314,
|
||||||
|
"longest_worker_ms": 495.59580162167549,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_05_pillaredcathedral"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 6,
|
||||||
|
"name": "TerracedBasin",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 136,
|
||||||
|
"room_radius_fraction_min": 0.51999998092651367,
|
||||||
|
"room_radius_fraction_max": 0.64999997615814209,
|
||||||
|
"room_height_voxels": 264,
|
||||||
|
"floor_relief_voxels": 14,
|
||||||
|
"tunnel_radius_voxels": 28,
|
||||||
|
"tunnel_half_height_voxels": 30,
|
||||||
|
"loop_probability": 0.20000000298023224,
|
||||||
|
"vertical_shaft_probability": 0.10000000149011612,
|
||||||
|
"shaft_radius_voxels": 18,
|
||||||
|
"pillar_probability": 0.10000000149011612,
|
||||||
|
"ledge_probability": 0.8399999737739563,
|
||||||
|
"floating_mass_probability": 0.05000000074505806,
|
||||||
|
"stalactite_stalagmite_probability": 0.25,
|
||||||
|
"basin_probability": 0.85000002384185791,
|
||||||
|
"basin_depth_voxels": 48,
|
||||||
|
"water_level_fraction": 0.30000001192092896
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 68093.558179425308,
|
||||||
|
"p50_m3": 82028.230406505769,
|
||||||
|
"p90_m3": 97259.151212849523
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 570.03279775381088,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
564.51970338821411,
|
||||||
|
570.03279775381088,
|
||||||
|
573.95610213279724
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.83870016189152752,
|
||||||
|
"estimated_surface_area_m2": 94288.5625,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.34732792067954038,
|
||||||
|
"vertical_air_adjacency_share": 0.33312483627697398,
|
||||||
|
"vertical_air_column_share": 0.98552496235893916,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 182.00520344879746,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.048149240524996313,
|
||||||
|
"one_meter_connected_components": 88,
|
||||||
|
"largest_component_coarse_m3": 230451,
|
||||||
|
"components_1_to_8_coarse_m3": 87,
|
||||||
|
"components_9_to_64_coarse_m3": 0,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 145055,
|
||||||
|
"skipped_sample_fraction": 0.50965412125800313,
|
||||||
|
"evaluated_samples": 8519259,
|
||||||
|
"worker_cpu_seconds": 2.34375,
|
||||||
|
"brick_classification_worker_ms": 249.46653842926025,
|
||||||
|
"density_evaluation_worker_ms": 3080.0332017242908,
|
||||||
|
"uniform_fill_worker_ms": 36.166064441204071,
|
||||||
|
"longest_worker_ms": 564.91680070757866,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_06_terracedbasin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile_index": 7,
|
||||||
|
"name": "HyperComplex",
|
||||||
|
"parameters":
|
||||||
|
{
|
||||||
|
"room_pitch_voxels": 96,
|
||||||
|
"room_radius_fraction_min": 0.60000002384185791,
|
||||||
|
"room_radius_fraction_max": 0.74000000953674316,
|
||||||
|
"room_height_voxels": 280,
|
||||||
|
"floor_relief_voxels": 20,
|
||||||
|
"tunnel_radius_voxels": 30,
|
||||||
|
"tunnel_half_height_voxels": 28,
|
||||||
|
"loop_probability": 0.40000000596046448,
|
||||||
|
"vertical_shaft_probability": 0.55000001192092896,
|
||||||
|
"shaft_radius_voxels": 20,
|
||||||
|
"pillar_probability": 0.44999998807907104,
|
||||||
|
"ledge_probability": 0.68000000715255737,
|
||||||
|
"floating_mass_probability": 0.5,
|
||||||
|
"stalactite_stalagmite_probability": 0.75,
|
||||||
|
"basin_probability": 0.41999998688697815,
|
||||||
|
"basin_depth_voxels": 28,
|
||||||
|
"water_level_fraction": 0.40000000596046448
|
||||||
|
},
|
||||||
|
"nominal_chamber_volume_quantiles_m3":
|
||||||
|
{
|
||||||
|
"p10_m3": 47753.715763874934,
|
||||||
|
"p50_m3": 56861.724022144372,
|
||||||
|
"p90_m3": 66764.200185109366
|
||||||
|
},
|
||||||
|
"six_worker_ring_median_ms": 559.64479967951775,
|
||||||
|
"six_worker_ring_trials_ms": [
|
||||||
|
520.49140259623528,
|
||||||
|
559.64479967951775,
|
||||||
|
575.4614993929863
|
||||||
|
],
|
||||||
|
"open_air_fraction": 0.94705570900022384,
|
||||||
|
"estimated_surface_area_m2": 61014.1875,
|
||||||
|
"estimated_surface_area_per_volume_m_inv": 0.22475611372616486,
|
||||||
|
"vertical_air_adjacency_share": 0.33306194335010991,
|
||||||
|
"vertical_air_column_share": 1,
|
||||||
|
"mean_longest_vertical_air_run_voxels": 219.53374278856904,
|
||||||
|
"longest_vertical_air_run_voxels": 259,
|
||||||
|
"one_meter_tunnel_neck_share": 0.029053088791938297,
|
||||||
|
"one_meter_connected_components": 65,
|
||||||
|
"largest_component_coarse_m3": 259588,
|
||||||
|
"components_1_to_8_coarse_m3": 62,
|
||||||
|
"components_9_to_64_coarse_m3": 2,
|
||||||
|
"components_65_to_512_coarse_m3": 0,
|
||||||
|
"components_over_512_coarse_m3": 1,
|
||||||
|
"skipped_bricks": 165593,
|
||||||
|
"skipped_sample_fraction": 0.58573939798131447,
|
||||||
|
"evaluated_samples": 7197355,
|
||||||
|
"worker_cpu_seconds": 2.09375,
|
||||||
|
"brick_classification_worker_ms": 262.15906068682671,
|
||||||
|
"density_evaluation_worker_ms": 2771.4953608810902,
|
||||||
|
"uniform_fill_worker_ms": 41.310880333185196,
|
||||||
|
"longest_worker_ms": 516.51959866285324,
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_07_hypercomplex"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slices": [
|
||||||
|
{
|
||||||
|
"profile": "OpenVaults",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_00_openvaults/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "OpenVaults",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_00_openvaults/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "OpenVaults",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_00_openvaults/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "OpenVaults",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_00_openvaults/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TightNetwork",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_01_tightnetwork/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TightNetwork",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_01_tightnetwork/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TightNetwork",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_01_tightnetwork/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TightNetwork",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_01_tightnetwork/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ChamberHalls",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_02_chamberhalls/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ChamberHalls",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_02_chamberhalls/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ChamberHalls",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_02_chamberhalls/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ChamberHalls",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_02_chamberhalls/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ShaftForest",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_03_shaftforest/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ShaftForest",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_03_shaftforest/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ShaftForest",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_03_shaftforest/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "ShaftForest",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_03_shaftforest/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "FloatingArchipelago",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_04_floatingarchipelago/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "FloatingArchipelago",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_04_floatingarchipelago/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "FloatingArchipelago",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_04_floatingarchipelago/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "FloatingArchipelago",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_04_floatingarchipelago/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "PillaredCathedral",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_05_pillaredcathedral/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "PillaredCathedral",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_05_pillaredcathedral/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "PillaredCathedral",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_05_pillaredcathedral/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "PillaredCathedral",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_05_pillaredcathedral/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TerracedBasin",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_06_terracedbasin/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TerracedBasin",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_06_terracedbasin/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TerracedBasin",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_06_terracedbasin/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "TerracedBasin",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_06_terracedbasin/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "HyperComplex",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_07_hypercomplex/slice_xy_center.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "HyperComplex",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_07_hypercomplex/slice_xz_y0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "HyperComplex",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_07_hypercomplex/slice_yz_x0.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"profile": "HyperComplex",
|
||||||
|
"file": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30/set_07_hypercomplex/slice_xz_passage.png",
|
||||||
|
"layout": "today's live field on left; step 2e parameterized field on right; light=air, dark=solid, cyan=near zero"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slice_directory": "E:/Projet Unreal/VoxelM/Plugins/VoxelForge/Saved/Research/step2e/step2e_profiles_30",
|
||||||
|
"detail_check":
|
||||||
|
{
|
||||||
|
"live_surface_band_samples": 15515231,
|
||||||
|
"new_surface_band_samples": 4880019,
|
||||||
|
"live_curvature_rms_lag1": 6.248069730899255,
|
||||||
|
"new_curvature_rms_lag1": 8.9351827746107304,
|
||||||
|
"smooth_control_curvature_rms_lag1": 1.9552341792313939,
|
||||||
|
"live_curvature_rms_lag2": 8.6459817485493211,
|
||||||
|
"new_curvature_rms_lag2": 9.3960370724645941,
|
||||||
|
"smooth_control_curvature_rms_lag2": 3.2348563389313552,
|
||||||
|
"detail_raw_parity_samples": 8488,
|
||||||
|
"detail_raw_parity_max_error": 0,
|
||||||
|
"detail_at_least_live_spectrum": true,
|
||||||
|
"deliberate_zero_detail_smoothing_detected": true,
|
||||||
|
"direct_vs_brick_detail_parity": true
|
||||||
|
},
|
||||||
|
"boundary_artifact_check":
|
||||||
|
{
|
||||||
|
"brick_boundary_gradient_jump_rms": 4.0223860554078321,
|
||||||
|
"interior_gradient_jump_rms": 3.475720295663749,
|
||||||
|
"chunk_boundary_gradient_jump_rms": 3.3855279003366117,
|
||||||
|
"feature_cell_boundary_gradient_jump_rms": 3.3785618604833521,
|
||||||
|
"feature_cell_interior_gradient_jump_rms": 3.4366715251600706,
|
||||||
|
"boundary_artifact_check_pass": true,
|
||||||
|
"deliberate_seam_samples_mutated": 706718,
|
||||||
|
"deliberate_seam_failure_caught": true
|
||||||
|
},
|
||||||
|
"brick_bound_audit":
|
||||||
|
{
|
||||||
|
"correctly_skipped_bricks_audited": 109,
|
||||||
|
"final_field_samples_checked_including_halo": 91890,
|
||||||
|
"correct_proof_sign_violations": 0,
|
||||||
|
"first_violation_brick_x": 0,
|
||||||
|
"first_violation_brick_y": 0,
|
||||||
|
"first_violation_brick_z": 0,
|
||||||
|
"first_violation_brick_size_x": 0,
|
||||||
|
"first_violation_brick_size_y": 0,
|
||||||
|
"first_violation_brick_size_z": 0,
|
||||||
|
"first_violation_sample_x": 0,
|
||||||
|
"first_violation_sample_y": 0,
|
||||||
|
"first_violation_sample_z": 0,
|
||||||
|
"first_violation_density": 0,
|
||||||
|
"first_violation_center_macro": 0,
|
||||||
|
"first_violation_sample_macro": 0,
|
||||||
|
"first_violation_sample_detail": 0,
|
||||||
|
"first_violation_macro_delta_per_voxel": 0,
|
||||||
|
"first_violation_path_max_gradient": 0,
|
||||||
|
"first_violation_tiny_step_max_gradient": 0,
|
||||||
|
"first_violation_inside_proven_brick": false,
|
||||||
|
"first_violation_claimed_air": false,
|
||||||
|
"undersized_bound_claims_checked": 20328,
|
||||||
|
"wrong_sign_samples_caught_by_undersized_bound": 14547,
|
||||||
|
"sound_supremum_audit_pass": true,
|
||||||
|
"deliberate_undersized_bound_failure_caught": true
|
||||||
|
},
|
||||||
|
"determinism":
|
||||||
|
{
|
||||||
|
"six_worker_run_1_quantized": "77439101d77e7750",
|
||||||
|
"six_worker_run_2_quantized": "77439101d77e7750",
|
||||||
|
"one_worker_quantized": "77439101d77e7750",
|
||||||
|
"six_worker_run_1_raw_float": "65bdd30af60254e1",
|
||||||
|
"six_worker_run_2_raw_float": "65bdd30af60254e1",
|
||||||
|
"one_worker_raw_float": "65bdd30af60254e1",
|
||||||
|
"same_across_two_runs_and_1_vs_6_workers": true,
|
||||||
|
"deliberate_quantized_hash_mismatch_rejected": true
|
||||||
|
},
|
||||||
|
"entrance_exit_walkability_test_added": true,
|
||||||
|
"inter_strate_passage_open_space_test_added": true,
|
||||||
|
"functional_test_filter": "VoxelForge.ParameterizedGeneration.TraversalSeeds"
|
||||||
|
}
|
||||||
@@ -55,21 +55,21 @@ namespace
|
|||||||
};
|
};
|
||||||
|
|
||||||
const FParameterProfile GParameterProfiles[] = {
|
const FParameterProfile GParameterProfiles[] = {
|
||||||
{ TEXT("OpenVaults"), { 176.0f, 0.34f, 0.45f, 340.0f, 12.0f, 40.0f, 36.0f,
|
{ TEXT("OpenVaults"), { 176.0f, 0.62f, 0.76f, 340.0f, 12.0f, 40.0f, 36.0f,
|
||||||
0.35f, 0.14f, 22.0f, 0.04f, 0.12f, 0.08f, 0.15f, 0.00f, 0.0f, 0.50f } },
|
0.35f, 0.14f, 22.0f, 0.04f, 0.12f, 0.08f, 0.15f, 0.00f, 0.0f, 0.50f } },
|
||||||
{ TEXT("TightNetwork"), { 104.0f, 0.28f, 0.42f, 112.0f, 8.0f, 20.0f, 22.0f,
|
{ TEXT("TightNetwork"), { 104.0f, 0.52f, 0.64f, 256.0f, 8.0f, 20.0f, 22.0f,
|
||||||
0.12f, 0.03f, 14.0f, 0.06f, 0.08f, 0.02f, 0.12f, 0.00f, 0.0f, 0.50f } },
|
0.12f, 0.03f, 14.0f, 0.06f, 0.08f, 0.02f, 0.12f, 0.00f, 0.0f, 0.50f } },
|
||||||
{ TEXT("ChamberHalls"), { 144.0f, 0.38f, 0.45f, 320.0f, 18.0f, 34.0f, 32.0f,
|
{ TEXT("ChamberHalls"), { 144.0f, 0.55f, 0.72f, 320.0f, 18.0f, 34.0f, 32.0f,
|
||||||
0.28f, 0.18f, 22.0f, 0.08f, 0.22f, 0.10f, 0.22f, 0.05f, 20.0f, 0.40f } },
|
0.28f, 0.18f, 22.0f, 0.08f, 0.22f, 0.10f, 0.22f, 0.05f, 20.0f, 0.40f } },
|
||||||
{ TEXT("ShaftForest"), { 128.0f, 0.32f, 0.43f, 176.0f, 12.0f, 26.0f, 28.0f,
|
{ TEXT("ShaftForest"), { 128.0f, 0.50f, 0.62f, 272.0f, 12.0f, 26.0f, 28.0f,
|
||||||
0.12f, 0.55f, 20.0f, 0.05f, 0.18f, 0.04f, 0.20f, 0.00f, 0.0f, 0.50f } },
|
0.12f, 0.92f, 28.0f, 0.05f, 0.18f, 0.04f, 0.20f, 0.00f, 0.0f, 0.50f } },
|
||||||
{ TEXT("FloatingArchipelago"), { 136.0f, 0.37f, 0.45f, 192.0f, 10.0f, 28.0f, 28.0f,
|
{ TEXT("FloatingArchipelago"), { 136.0f, 0.55f, 0.68f, 216.0f, 10.0f, 28.0f, 28.0f,
|
||||||
0.15f, 0.10f, 16.0f, 0.05f, 0.10f, 0.72f, 0.28f, 0.00f, 0.0f, 0.50f } },
|
0.15f, 0.10f, 16.0f, 0.05f, 0.10f, 0.72f, 0.28f, 0.00f, 0.0f, 0.50f } },
|
||||||
{ TEXT("PillaredCathedral"), { 160.0f, 0.38f, 0.45f, 248.0f, 12.0f, 32.0f, 34.0f,
|
{ TEXT("PillaredCathedral"), { 160.0f, 0.55f, 0.72f, 248.0f, 12.0f, 32.0f, 34.0f,
|
||||||
0.25f, 0.08f, 18.0f, 0.72f, 0.30f, 0.08f, 0.45f, 0.00f, 0.0f, 0.50f } },
|
0.25f, 0.08f, 18.0f, 0.72f, 0.30f, 0.08f, 0.45f, 0.00f, 0.0f, 0.50f } },
|
||||||
{ TEXT("TerracedBasin"), { 136.0f, 0.34f, 0.45f, 216.0f, 14.0f, 28.0f, 30.0f,
|
{ TEXT("TerracedBasin"), { 136.0f, 0.52f, 0.65f, 264.0f, 14.0f, 28.0f, 30.0f,
|
||||||
0.20f, 0.10f, 18.0f, 0.10f, 0.84f, 0.05f, 0.25f, 0.85f, 48.0f, 0.30f } },
|
0.20f, 0.10f, 18.0f, 0.10f, 0.84f, 0.05f, 0.25f, 0.85f, 48.0f, 0.30f } },
|
||||||
{ TEXT("HyperComplex"), { 96.0f, 0.30f, 0.45f, 192.0f, 20.0f, 30.0f, 28.0f,
|
{ TEXT("HyperComplex"), { 96.0f, 0.60f, 0.74f, 280.0f, 20.0f, 30.0f, 28.0f,
|
||||||
0.40f, 0.55f, 20.0f, 0.45f, 0.68f, 0.50f, 0.75f, 0.42f, 28.0f, 0.40f } },
|
0.40f, 0.55f, 20.0f, 0.45f, 0.68f, 0.50f, 0.75f, 0.42f, 28.0f, 0.40f } },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,6 +82,11 @@ namespace
|
|||||||
float PadRadius = 0.0f;
|
float PadRadius = 0.0f;
|
||||||
float BlendRadius = LandingFloorBlendVoxels;
|
float BlendRadius = LandingFloorBlendVoxels;
|
||||||
FVector ApproachEnd = FVector::ZeroVector;
|
FVector ApproachEnd = FVector::ZeroVector;
|
||||||
|
bool bGeneratedAnchorPrepared = false;
|
||||||
|
FVector GeneratedAnchorStart = FVector::ZeroVector;
|
||||||
|
FVector GeneratedAnchorDelta = FVector::ZeroVector;
|
||||||
|
float GeneratedAnchorLengthSquared = 0.0f;
|
||||||
|
float GeneratedAnchorReach = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FVerticalShaftNode
|
struct FVerticalShaftNode
|
||||||
@@ -147,6 +152,8 @@ namespace
|
|||||||
TArray<FLandingSite> Landings;
|
TArray<FLandingSite> Landings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void PrepareParameterizedAnchors(FStratePlan& Plan);
|
||||||
|
|
||||||
struct FThreadPlanCache
|
struct FThreadPlanCache
|
||||||
{
|
{
|
||||||
const UVoxelStrateManager* Manager = nullptr;
|
const UVoxelStrateManager* Manager = nullptr;
|
||||||
@@ -159,6 +166,7 @@ namespace
|
|||||||
};
|
};
|
||||||
|
|
||||||
thread_local FThreadPlanCache GPlanCache;
|
thread_local FThreadPlanCache GPlanCache;
|
||||||
|
thread_local const FStratePlan* GParameterizedRoomCellCachePlan = nullptr;
|
||||||
thread_local FThreadShaftEdgeCache GShaftEdgeCache;
|
thread_local FThreadShaftEdgeCache GShaftEdgeCache;
|
||||||
|
|
||||||
FORCEINLINE uint32 Mix(uint32 Value)
|
FORCEINLINE uint32 Mix(uint32 Value)
|
||||||
@@ -477,6 +485,7 @@ namespace
|
|||||||
if (Manager == nullptr)
|
if (Manager == nullptr)
|
||||||
{
|
{
|
||||||
GPlanCache = FThreadPlanCache();
|
GPlanCache = FThreadPlanCache();
|
||||||
|
GParameterizedRoomCellCachePlan = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const uint64 Lifetime = Manager->GetCacheLifetimeId();
|
const uint64 Lifetime = Manager->GetCacheLifetimeId();
|
||||||
@@ -492,6 +501,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
GPlanCache = FThreadPlanCache();
|
GPlanCache = FThreadPlanCache();
|
||||||
|
GParameterizedRoomCellCachePlan = nullptr;
|
||||||
GPlanCache.Manager = Manager;
|
GPlanCache.Manager = Manager;
|
||||||
GPlanCache.ManagerLifetimeId = Lifetime;
|
GPlanCache.ManagerLifetimeId = Lifetime;
|
||||||
GPlanCache.LayoutVersion = Version;
|
GPlanCache.LayoutVersion = Version;
|
||||||
@@ -566,10 +576,10 @@ namespace
|
|||||||
Plan.Generation.RoomPitchVoxels = FMath::Max(
|
Plan.Generation.RoomPitchVoxels = FMath::Max(
|
||||||
Plan.Generation.RoomPitchVoxels, 80.0f);
|
Plan.Generation.RoomPitchVoxels, 80.0f);
|
||||||
Plan.Generation.MinimumRoomRadiusFraction = FMath::Clamp(
|
Plan.Generation.MinimumRoomRadiusFraction = FMath::Clamp(
|
||||||
Plan.Generation.MinimumRoomRadiusFraction, 0.20f, 0.41f);
|
Plan.Generation.MinimumRoomRadiusFraction, 0.20f, 0.72f);
|
||||||
Plan.Generation.MaximumRoomRadiusFraction = FMath::Clamp(
|
Plan.Generation.MaximumRoomRadiusFraction = FMath::Clamp(
|
||||||
Plan.Generation.MaximumRoomRadiusFraction,
|
Plan.Generation.MaximumRoomRadiusFraction,
|
||||||
Plan.Generation.MinimumRoomRadiusFraction, 0.45f);
|
Plan.Generation.MinimumRoomRadiusFraction, 0.80f);
|
||||||
Plan.Generation.LoopProbability = FMath::Clamp(
|
Plan.Generation.LoopProbability = FMath::Clamp(
|
||||||
Plan.Generation.LoopProbability, 0.0f, 0.8f);
|
Plan.Generation.LoopProbability, 0.0f, 0.8f);
|
||||||
Plan.Generation.VerticalShaftProbability = FMath::Clamp(
|
Plan.Generation.VerticalShaftProbability = FMath::Clamp(
|
||||||
@@ -718,7 +728,8 @@ namespace
|
|||||||
Plan.FloorZ = FMath::Clamp(
|
Plan.FloorZ = FMath::Clamp(
|
||||||
static_cast<float>(FloorSum / FloorCount), Bottom + 16.0f, Top - 72.0f);
|
static_cast<float>(FloorSum / FloorCount), Bottom + 16.0f, Top - 72.0f);
|
||||||
Plan.CeilingZ = Plan.FloorZ + MinimumCaveHeight;
|
Plan.CeilingZ = Plan.FloorZ + MinimumCaveHeight;
|
||||||
Plan.GenerationFloorZ = Plan.FloorZ;
|
// Parameterized chambers keep their profile-defined vertical span. The
|
||||||
|
// passage landing is connected into that graph by its generated anchor.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (FLandingSite& Site : Plan.Landings)
|
for (FLandingSite& Site : Plan.Landings)
|
||||||
@@ -765,6 +776,10 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (FStratePlan& Plan : GPlanCache.Strates)
|
||||||
|
{
|
||||||
|
PrepareParameterizedAnchors(Plan);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FGeneratedCaveCell
|
struct FGeneratedCaveCell
|
||||||
@@ -788,6 +803,30 @@ namespace
|
|||||||
float SpireLength = 0.0f;
|
float SpireLength = 0.0f;
|
||||||
float SpireRadius = 0.0f;
|
float SpireRadius = 0.0f;
|
||||||
uint8 FeatureFlags = 0;
|
uint8 FeatureFlags = 0;
|
||||||
|
uint8 OpenTunnelEdges = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FParameterizedColumnContext
|
||||||
|
{
|
||||||
|
FGeneratedCaveCell GeneratedCells[9];
|
||||||
|
const FGeneratedCaveCell* Cells[9] = {};
|
||||||
|
float RoomDistanceSquared[9] = {};
|
||||||
|
float RoomRadii[9] = {};
|
||||||
|
float RoomHorizontals[9] = {};
|
||||||
|
float RoomFloors[9] = {};
|
||||||
|
float PillarHorizontals[9] = {};
|
||||||
|
float FloatingXYDistanceSquared[9][2] = {};
|
||||||
|
float SpireBaseZ[9] = {};
|
||||||
|
float SpireTipZ[9] = {};
|
||||||
|
float SpireBaseTopZ[9] = {};
|
||||||
|
float SpireTipBottomZ[9] = {};
|
||||||
|
float TunnelT[4] = {};
|
||||||
|
float TunnelHorizontal[4] = {};
|
||||||
|
float LandingDistanceSquared[8] = {};
|
||||||
|
float LandingDistance[8] = {};
|
||||||
|
float LandingBridgeT[8] = {};
|
||||||
|
float LandingBridgeHorizontal[8] = {};
|
||||||
|
bool bHasLandingXYCache = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr uint8 HasPillarFlag = 1u << 0;
|
constexpr uint8 HasPillarFlag = 1u << 0;
|
||||||
@@ -795,6 +834,20 @@ namespace
|
|||||||
constexpr uint8 HasFloatingFlag = 1u << 2;
|
constexpr uint8 HasFloatingFlag = 1u << 2;
|
||||||
constexpr uint8 HasSpireFlag = 1u << 3;
|
constexpr uint8 HasSpireFlag = 1u << 3;
|
||||||
constexpr uint8 HasBasinFlag = 1u << 4;
|
constexpr uint8 HasBasinFlag = 1u << 4;
|
||||||
|
constexpr uint8 HasVerticalShaftFlag = 1u << 5;
|
||||||
|
constexpr uint8 TunnelToNegativeY = 1u << 0;
|
||||||
|
constexpr uint8 TunnelToPositiveY = 1u << 1;
|
||||||
|
constexpr uint8 TunnelToNegativeX = 1u << 2;
|
||||||
|
constexpr uint8 TunnelToPositiveX = 1u << 3;
|
||||||
|
|
||||||
|
thread_local TArray<FGeneratedCaveCell> GParameterizedRoomCellCache;
|
||||||
|
thread_local FIntPoint GParameterizedRoomCellCacheMin = FIntPoint::ZeroValue;
|
||||||
|
thread_local FIntPoint GParameterizedRoomCellCacheSize = FIntPoint::ZeroValue;
|
||||||
|
|
||||||
|
FIntPoint GeneratedParent(const FStratePlan& Plan, int32 CellX, int32 CellY);
|
||||||
|
bool IsGeneratedEdgeOpen(
|
||||||
|
const FStratePlan& Plan, int32 AX, int32 AY, int32 BX, int32 BY);
|
||||||
|
FORCEINLINE FIntPoint GenerationCellAt(const FStratePlan& Plan, float X, float Y);
|
||||||
|
|
||||||
FORCEINLINE float ParameterRoll(uint32 Hash, uint32 Salt)
|
FORCEINLINE float ParameterRoll(uint32 Hash, uint32 Salt)
|
||||||
{
|
{
|
||||||
@@ -829,6 +882,27 @@ namespace
|
|||||||
Cell.RadiusX = Pitch * RadiusFraction;
|
Cell.RadiusX = Pitch * RadiusFraction;
|
||||||
Cell.RadiusY = Cell.RadiusX * FMath::Lerp(
|
Cell.RadiusY = Cell.RadiusX * FMath::Lerp(
|
||||||
0.82f, 0.98f, ParameterRoll(Hash, 0x27C5u));
|
0.82f, 0.98f, ParameterRoll(Hash, 0x27C5u));
|
||||||
|
if (VoxelHash::ToFloat01(Hash3(CellX, CellY, 0x53, Plan.GenerationSeed))
|
||||||
|
< P.VerticalShaftProbability)
|
||||||
|
{
|
||||||
|
Cell.FeatureFlags |= HasVerticalShaftFlag;
|
||||||
|
}
|
||||||
|
if (IsGeneratedEdgeOpen(Plan, CellX, CellY, CellX, CellY - 1))
|
||||||
|
{
|
||||||
|
Cell.OpenTunnelEdges |= TunnelToNegativeY;
|
||||||
|
}
|
||||||
|
if (IsGeneratedEdgeOpen(Plan, CellX, CellY, CellX, CellY + 1))
|
||||||
|
{
|
||||||
|
Cell.OpenTunnelEdges |= TunnelToPositiveY;
|
||||||
|
}
|
||||||
|
if (IsGeneratedEdgeOpen(Plan, CellX, CellY, CellX - 1, CellY))
|
||||||
|
{
|
||||||
|
Cell.OpenTunnelEdges |= TunnelToNegativeX;
|
||||||
|
}
|
||||||
|
if (IsGeneratedEdgeOpen(Plan, CellX, CellY, CellX + 1, CellY))
|
||||||
|
{
|
||||||
|
Cell.OpenTunnelEdges |= TunnelToPositiveX;
|
||||||
|
}
|
||||||
Cell.FloorZ = Plan.GenerationFloorZ
|
Cell.FloorZ = Plan.GenerationFloorZ
|
||||||
+ (ParameterRoll(Hash, 0xF103u) * 2.0f - 1.0f) * P.FloorReliefVoxels;
|
+ (ParameterRoll(Hash, 0xF103u) * 2.0f - 1.0f) * P.FloorReliefVoxels;
|
||||||
Cell.CeilingZ = Cell.FloorZ + P.RoomHeightVoxels;
|
Cell.CeilingZ = Cell.FloorZ + P.RoomHeightVoxels;
|
||||||
@@ -880,6 +954,42 @@ namespace
|
|||||||
return Cell;
|
return Cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrepareParameterizedAnchors(FStratePlan& Plan)
|
||||||
|
{
|
||||||
|
const float AnchorReach = Plan.Generation.RoomPitchVoxels * 1.25f
|
||||||
|
+ FMath::Max(32.0f, Plan.Generation.TunnelRadiusVoxels);
|
||||||
|
for (FLandingSite& Site : Plan.Landings)
|
||||||
|
{
|
||||||
|
const FIntPoint LandingCell = GenerationCellAt(
|
||||||
|
Plan, Site.Position.X, Site.Position.Y);
|
||||||
|
FGeneratedCaveCell NearestCell;
|
||||||
|
float BestDistanceSquared = FLT_MAX;
|
||||||
|
for (int32 CellY = -1; CellY <= 1; ++CellY)
|
||||||
|
for (int32 CellX = -1; CellX <= 1; ++CellX)
|
||||||
|
{
|
||||||
|
const FGeneratedCaveCell Candidate = BuildGeneratedCell(
|
||||||
|
Plan, LandingCell.X + CellX, LandingCell.Y + CellY);
|
||||||
|
const float DX = Candidate.CenterX - Site.Position.X;
|
||||||
|
const float DY = Candidate.CenterY - Site.Position.Y;
|
||||||
|
const float DistanceSquared = DX * DX + DY * DY;
|
||||||
|
if (DistanceSquared < BestDistanceSquared)
|
||||||
|
{
|
||||||
|
BestDistanceSquared = DistanceSquared;
|
||||||
|
NearestCell = Candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Site.GeneratedAnchorStart = FVector(
|
||||||
|
Site.Position.X, Site.Position.Y, Site.FloorZ + 24.0f);
|
||||||
|
const FVector AnchorEnd(
|
||||||
|
NearestCell.CenterX, NearestCell.CenterY,
|
||||||
|
NearestCell.FloorZ + Plan.Generation.TunnelHalfHeightVoxels);
|
||||||
|
Site.GeneratedAnchorDelta = AnchorEnd - Site.GeneratedAnchorStart;
|
||||||
|
Site.GeneratedAnchorLengthSquared = Site.GeneratedAnchorDelta.SizeSquared();
|
||||||
|
Site.GeneratedAnchorReach = AnchorReach;
|
||||||
|
Site.bGeneratedAnchorPrepared = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FORCEINLINE float SmoothMinimum(float A, float B, float K)
|
FORCEINLINE float SmoothMinimum(float A, float B, float K)
|
||||||
{
|
{
|
||||||
const float H = FMath::Max(K - FMath::Abs(A - B), 0.0f) / K;
|
const float H = FMath::Max(K - FMath::Abs(A - B), 0.0f) / K;
|
||||||
@@ -903,72 +1013,81 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE float GeneratedRoomCell(
|
FORCEINLINE float GeneratedRoomCell(
|
||||||
const FStratePlan& Plan, const FGeneratedCaveCell& Cell,
|
const FGeneratedCaveCell& Cell,
|
||||||
float X, float Y, float Z)
|
float Z, float Radius, float Horizontal,
|
||||||
|
const FParameterizedColumnContext& Column, int32 CellIndex)
|
||||||
{
|
{
|
||||||
const float DX = X - Cell.CenterX;
|
const float FloorZ = Column.RoomFloors[CellIndex];
|
||||||
const float DY = Y - Cell.CenterY;
|
|
||||||
const float Radius = FMath::Sqrt(DX * DX + DY * DY);
|
|
||||||
const float Horizontal = Cell.RadiusX - Radius;
|
|
||||||
float FloorZ = Cell.FloorZ;
|
|
||||||
if ((Cell.FeatureFlags & HasBasinFlag) != 0)
|
|
||||||
{
|
|
||||||
FloorZ += Plan.Generation.BasinDepthVoxels
|
|
||||||
* FMath::Clamp(Radius / FMath::Max(Cell.RadiusX, 1.0f), 0.0f, 1.0f);
|
|
||||||
}
|
|
||||||
const float Vertical = FMath::Min(Z - FloorZ, Cell.CeilingZ - Z);
|
const float Vertical = FMath::Min(Z - FloorZ, Cell.CeilingZ - Z);
|
||||||
float Room = SmoothMinimum(Horizontal, Vertical, 8.0f);
|
float Room = SmoothMinimum(Horizontal, Vertical, 8.0f);
|
||||||
if (Room > 0.0f && (Cell.FeatureFlags & HasPillarFlag) != 0)
|
if ((Cell.FeatureFlags & HasPillarFlag) != 0 && Room > -14.0f)
|
||||||
{
|
{
|
||||||
const float PX = X - Cell.PillarX;
|
|
||||||
const float PY = Y - Cell.PillarY;
|
|
||||||
const float Pillar = FMath::Max3(
|
const float Pillar = FMath::Max3(
|
||||||
FMath::Sqrt(PX * PX + PY * PY) - Cell.PillarRadius,
|
Column.PillarHorizontals[CellIndex],
|
||||||
Cell.FloorZ - Z, Z - Cell.CeilingZ);
|
Cell.FloorZ - Z, Z - Cell.CeilingZ);
|
||||||
Room = FMath::Min(Room, Pillar);
|
if (Pillar < Room)
|
||||||
|
{
|
||||||
|
Room = Pillar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((Cell.FeatureFlags & HasLedgeFlag) != 0
|
if ((Cell.FeatureFlags & HasLedgeFlag) != 0)
|
||||||
&& Horizontal >= -2.0f && FMath::Abs(Z - Cell.LedgeZ) <= 3.0f)
|
|
||||||
{
|
{
|
||||||
const float Inner = Cell.RadiusX * 0.58f;
|
const float Inner = Cell.RadiusX * 0.58f;
|
||||||
const float Outer = Cell.RadiusX + 1.0f;
|
const float Outer = Cell.RadiusX + 1.0f;
|
||||||
const float Ledge = FMath::Max3(
|
const float Ledge = FMath::Max3(
|
||||||
Inner - Radius, Radius - Outer, FMath::Abs(Z - Cell.LedgeZ) - 2.5f);
|
Inner - Radius, Radius - Outer, FMath::Abs(Z - Cell.LedgeZ) - 2.5f);
|
||||||
Room = FMath::Min(Room, Ledge);
|
if (Ledge < Room)
|
||||||
|
{
|
||||||
|
Room = Ledge;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Room > 0.0f && (Cell.FeatureFlags & HasFloatingFlag) != 0)
|
if ((Cell.FeatureFlags & HasFloatingFlag) != 0)
|
||||||
{
|
{
|
||||||
for (int32 Blob = 0; Blob < 2; ++Blob)
|
for (int32 Blob = 0; Blob < 2; ++Blob)
|
||||||
{
|
{
|
||||||
const float BX = X - Cell.FloatingX[Blob];
|
if (Room <= -Cell.FloatingRadius[Blob])
|
||||||
const float BY = Y - Cell.FloatingY[Blob];
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const float BZ = Z - Cell.FloatingZ[Blob];
|
const float BZ = Z - Cell.FloatingZ[Blob];
|
||||||
const float BlobSolid = FMath::Sqrt(BX * BX + BY * BY + BZ * BZ)
|
const float BlobSolid = FMath::Sqrt(
|
||||||
|
Column.FloatingXYDistanceSquared[CellIndex][Blob] + BZ * BZ)
|
||||||
- Cell.FloatingRadius[Blob];
|
- Cell.FloatingRadius[Blob];
|
||||||
Room = FMath::Min(Room, BlobSolid);
|
if (BlobSolid < Room)
|
||||||
|
{
|
||||||
|
Room = BlobSolid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Room > 0.0f && (Cell.FeatureFlags & HasSpireFlag) != 0)
|
if ((Cell.FeatureFlags & HasSpireFlag) != 0 && Room > -14.0f)
|
||||||
{
|
{
|
||||||
const float BaseZ = Cell.FloorZ + 2.0f;
|
const float BaseZ = Column.SpireBaseZ[CellIndex];
|
||||||
const float TipZ = FMath::Min(Cell.CeilingZ - 2.0f, BaseZ + Cell.SpireLength);
|
const float TipZ = Column.SpireTipZ[CellIndex];
|
||||||
if (Z >= BaseZ && Z <= TipZ)
|
if (Z >= BaseZ || BaseZ - Z < Room)
|
||||||
{
|
{
|
||||||
const float T = (Z - BaseZ) / FMath::Max(TipZ - BaseZ, 1.0f);
|
const float T = FMath::Clamp(
|
||||||
|
(Z - BaseZ) / FMath::Max(TipZ - BaseZ, 1.0f), 0.0f, 1.0f);
|
||||||
const float RadiusAtZ = FMath::Lerp(Cell.SpireRadius, 1.25f, T);
|
const float RadiusAtZ = FMath::Lerp(Cell.SpireRadius, 1.25f, T);
|
||||||
const float Spire = FMath::Max3(
|
const float Spire = FMath::Max3(
|
||||||
Radius - RadiusAtZ, BaseZ - Z, Z - TipZ);
|
Radius - RadiusAtZ, BaseZ - Z, Z - TipZ);
|
||||||
Room = FMath::Min(Room, Spire);
|
if (Spire < Room)
|
||||||
|
{
|
||||||
|
Room = Spire;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const float BaseTop = Cell.CeilingZ - 2.0f;
|
const float BaseTop = Column.SpireBaseTopZ[CellIndex];
|
||||||
const float TipBottom = FMath::Max(Cell.FloorZ + 2.0f, BaseTop - Cell.SpireLength);
|
const float TipBottom = Column.SpireTipBottomZ[CellIndex];
|
||||||
if (Z >= TipBottom && Z <= BaseTop)
|
if (Z <= BaseTop || Z - BaseTop < Room)
|
||||||
{
|
{
|
||||||
const float T = (BaseTop - Z) / FMath::Max(BaseTop - TipBottom, 1.0f);
|
const float T = FMath::Clamp(
|
||||||
|
(BaseTop - Z) / FMath::Max(BaseTop - TipBottom, 1.0f), 0.0f, 1.0f);
|
||||||
const float RadiusAtZ = FMath::Lerp(Cell.SpireRadius, 1.25f, T);
|
const float RadiusAtZ = FMath::Lerp(Cell.SpireRadius, 1.25f, T);
|
||||||
const float Stalactite = FMath::Max3(
|
const float Stalactite = FMath::Max3(
|
||||||
Radius - RadiusAtZ, Z - BaseTop, TipBottom - Z);
|
Radius - RadiusAtZ, Z - BaseTop, TipBottom - Z);
|
||||||
Room = FMath::Min(Room, Stalactite);
|
if (Stalactite < Room)
|
||||||
|
{
|
||||||
|
Room = Stalactite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Room;
|
return Room;
|
||||||
@@ -1018,18 +1137,8 @@ namespace
|
|||||||
FORCEINLINE float GeneratedTunnelEdge(
|
FORCEINLINE float GeneratedTunnelEdge(
|
||||||
const FStratePlan& Plan,
|
const FStratePlan& Plan,
|
||||||
const FGeneratedCaveCell& A, const FGeneratedCaveCell& B,
|
const FGeneratedCaveCell& A, const FGeneratedCaveCell& B,
|
||||||
float X, float Y, float Z)
|
float Z, float T, float Horizontal)
|
||||||
{
|
{
|
||||||
if (!IsGeneratedEdgeOpen(Plan, A.CellX, A.CellY, B.CellX, B.CellY))
|
|
||||||
{
|
|
||||||
return -FLT_MAX;
|
|
||||||
}
|
|
||||||
const float T = SegmentParameterXY(X, Y,
|
|
||||||
FVector(A.CenterX, A.CenterY, 0.0f), FVector(B.CenterX, B.CenterY, 0.0f));
|
|
||||||
const float Horizontal = Plan.Generation.TunnelRadiusVoxels
|
|
||||||
- FMath::Sqrt(DistanceSquaredToSegmentXY(
|
|
||||||
X, Y, FVector(A.CenterX, A.CenterY, 0.0f),
|
|
||||||
FVector(B.CenterX, B.CenterY, 0.0f)));
|
|
||||||
const float FloorZ = FMath::Lerp(A.FloorZ, B.FloorZ, T);
|
const float FloorZ = FMath::Lerp(A.FloorZ, B.FloorZ, T);
|
||||||
const float Vertical = FMath::Min(
|
const float Vertical = FMath::Min(
|
||||||
Z - FloorZ,
|
Z - FloorZ,
|
||||||
@@ -1037,66 +1146,267 @@ namespace
|
|||||||
return SmoothMinimum(Horizontal, Vertical, 5.0f);
|
return SmoothMinimum(Horizontal, Vertical, 5.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float EvaluateParameterizedMacro(
|
const FGeneratedCaveCell* FindParameterizedBrickRoomCell(
|
||||||
const FStratePlan& Plan, float X, float Y, float Z, float* OutDetailScale)
|
const FStratePlan& Plan, const FParameterizedBrickContext* Context,
|
||||||
|
int32 CellX, int32 CellY)
|
||||||
|
{
|
||||||
|
if (Context == nullptr || Context->PlanToken != &Plan
|
||||||
|
|| Context->RoomCellCacheToken != GParameterizedRoomCellCache.GetData()
|
||||||
|
|| GParameterizedRoomCellCachePlan != &Plan
|
||||||
|
|| CellX < Context->RoomCellCacheMin.X
|
||||||
|
|| CellY < Context->RoomCellCacheMin.Y
|
||||||
|
|| CellX >= Context->RoomCellCacheMin.X + Context->RoomCellCacheSize.X
|
||||||
|
|| CellY >= Context->RoomCellCacheMin.Y + Context->RoomCellCacheSize.Y)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const int32 Index = (CellY - Context->RoomCellCacheMin.Y)
|
||||||
|
* Context->RoomCellCacheSize.X + CellX - Context->RoomCellCacheMin.X;
|
||||||
|
return GParameterizedRoomCellCache.IsValidIndex(Index)
|
||||||
|
? &GParameterizedRoomCellCache[Index] : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildParameterizedColumnContext(
|
||||||
|
const FStratePlan& Plan, float X, float Y,
|
||||||
|
const FParameterizedBrickContext* Context,
|
||||||
|
FParameterizedColumnContext& OutColumn)
|
||||||
{
|
{
|
||||||
const FIntPoint BaseCell = GenerationCellAt(Plan, X, Y);
|
const FIntPoint BaseCell = GenerationCellAt(Plan, X, Y);
|
||||||
FGeneratedCaveCell Cells[9];
|
const bool bHasRoomCellCache = Context != nullptr
|
||||||
|
&& Context->PlanToken == &Plan
|
||||||
|
&& Context->RoomCellCacheToken == GParameterizedRoomCellCache.GetData()
|
||||||
|
&& GParameterizedRoomCellCachePlan == &Plan;
|
||||||
for (int32 CellY = -1; CellY <= 1; ++CellY)
|
for (int32 CellY = -1; CellY <= 1; ++CellY)
|
||||||
for (int32 CellX = -1; CellX <= 1; ++CellX)
|
for (int32 CellX = -1; CellX <= 1; ++CellX)
|
||||||
{
|
{
|
||||||
const int32 Index = (CellY + 1) * 3 + CellX + 1;
|
const int32 Index = (CellY + 1) * 3 + CellX + 1;
|
||||||
Cells[Index] = BuildGeneratedCell(
|
const int32 GeneratedX = BaseCell.X + CellX;
|
||||||
Plan, BaseCell.X + CellX, BaseCell.Y + CellY);
|
const int32 GeneratedY = BaseCell.Y + CellY;
|
||||||
|
if (bHasRoomCellCache)
|
||||||
|
{
|
||||||
|
const int32 CacheX = GeneratedX - Context->RoomCellCacheMin.X;
|
||||||
|
const int32 CacheY = GeneratedY - Context->RoomCellCacheMin.Y;
|
||||||
|
if (CacheX >= 0 && CacheY >= 0
|
||||||
|
&& CacheX < Context->RoomCellCacheSize.X
|
||||||
|
&& CacheY < Context->RoomCellCacheSize.Y)
|
||||||
|
{
|
||||||
|
const int32 CacheIndex = CacheY * Context->RoomCellCacheSize.X + CacheX;
|
||||||
|
if (GParameterizedRoomCellCache.IsValidIndex(CacheIndex))
|
||||||
|
{
|
||||||
|
OutColumn.Cells[Index] = &GParameterizedRoomCellCache[CacheIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutColumn.Cells[Index] = FindParameterizedBrickRoomCell(
|
||||||
|
Plan, Context, GeneratedX, GeneratedY);
|
||||||
|
}
|
||||||
|
if (OutColumn.Cells[Index] == nullptr)
|
||||||
|
{
|
||||||
|
OutColumn.GeneratedCells[Index] = BuildGeneratedCell(
|
||||||
|
Plan, GeneratedX, GeneratedY);
|
||||||
|
OutColumn.Cells[Index] = &OutColumn.GeneratedCells[Index];
|
||||||
|
}
|
||||||
|
const float DX = X - OutColumn.Cells[Index]->CenterX;
|
||||||
|
const float DY = Y - OutColumn.Cells[Index]->CenterY;
|
||||||
|
const float DistanceSquared = DX * DX + DY * DY;
|
||||||
|
OutColumn.RoomDistanceSquared[Index] = DistanceSquared;
|
||||||
|
OutColumn.RoomRadii[Index] = FMath::Sqrt(DistanceSquared);
|
||||||
|
OutColumn.RoomHorizontals[Index] = OutColumn.Cells[Index]->RadiusX
|
||||||
|
- OutColumn.RoomRadii[Index];
|
||||||
|
|
||||||
|
const FGeneratedCaveCell& Cell = *OutColumn.Cells[Index];
|
||||||
|
OutColumn.RoomFloors[Index] = Cell.FloorZ;
|
||||||
|
if ((Cell.FeatureFlags & HasBasinFlag) != 0)
|
||||||
|
{
|
||||||
|
OutColumn.RoomFloors[Index] += Plan.Generation.BasinDepthVoxels
|
||||||
|
* FMath::Clamp(OutColumn.RoomRadii[Index]
|
||||||
|
/ FMath::Max(Cell.RadiusX, 1.0f), 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
if ((Cell.FeatureFlags & HasPillarFlag) != 0)
|
||||||
|
{
|
||||||
|
const float PX = X - Cell.PillarX;
|
||||||
|
const float PY = Y - Cell.PillarY;
|
||||||
|
OutColumn.PillarHorizontals[Index] = FMath::Sqrt(PX * PX + PY * PY)
|
||||||
|
- Cell.PillarRadius;
|
||||||
|
}
|
||||||
|
if ((Cell.FeatureFlags & HasFloatingFlag) != 0)
|
||||||
|
{
|
||||||
|
for (int32 Blob = 0; Blob < 2; ++Blob)
|
||||||
|
{
|
||||||
|
const float BX = X - Cell.FloatingX[Blob];
|
||||||
|
const float BY = Y - Cell.FloatingY[Blob];
|
||||||
|
OutColumn.FloatingXYDistanceSquared[Index][Blob] = BX * BX + BY * BY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((Cell.FeatureFlags & HasSpireFlag) != 0)
|
||||||
|
{
|
||||||
|
OutColumn.SpireBaseZ[Index] = Cell.FloorZ + 2.0f;
|
||||||
|
OutColumn.SpireTipZ[Index] = FMath::Min(
|
||||||
|
Cell.CeilingZ - 2.0f,
|
||||||
|
OutColumn.SpireBaseZ[Index] + Cell.SpireLength);
|
||||||
|
OutColumn.SpireBaseTopZ[Index] = Cell.CeilingZ - 2.0f;
|
||||||
|
OutColumn.SpireTipBottomZ[Index] = FMath::Max(
|
||||||
|
Cell.FloorZ + 2.0f,
|
||||||
|
OutColumn.SpireBaseTopZ[Index] - Cell.SpireLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FGeneratedCaveCell& Centre = *OutColumn.Cells[4];
|
||||||
|
const int32 EdgeIndices[] = {1, 7, 3, 5};
|
||||||
|
const uint8 EdgeFlags[] = {
|
||||||
|
TunnelToNegativeY, TunnelToPositiveY,
|
||||||
|
TunnelToNegativeX, TunnelToPositiveX};
|
||||||
|
for (int32 EdgeIndex = 0; EdgeIndex < UE_ARRAY_COUNT(EdgeIndices); ++EdgeIndex)
|
||||||
|
{
|
||||||
|
OutColumn.TunnelHorizontal[EdgeIndex] = -FLT_MAX;
|
||||||
|
if ((Centre.OpenTunnelEdges & EdgeFlags[EdgeIndex]) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const FGeneratedCaveCell& Next = *OutColumn.Cells[EdgeIndices[EdgeIndex]];
|
||||||
|
const float ABX = Next.CenterX - Centre.CenterX;
|
||||||
|
const float ABY = Next.CenterY - Centre.CenterY;
|
||||||
|
const float LengthSquared = ABX * ABX + ABY * ABY;
|
||||||
|
const float T = LengthSquared > 1.0e-8f
|
||||||
|
? FMath::Clamp(((X - Centre.CenterX) * ABX
|
||||||
|
+ (Y - Centre.CenterY) * ABY) / LengthSquared, 0.0f, 1.0f)
|
||||||
|
: 0.0f;
|
||||||
|
const float DX = X - (Centre.CenterX + T * ABX);
|
||||||
|
const float DY = Y - (Centre.CenterY + T * ABY);
|
||||||
|
OutColumn.TunnelT[EdgeIndex] = T;
|
||||||
|
OutColumn.TunnelHorizontal[EdgeIndex] = Plan.Generation.TunnelRadiusVoxels
|
||||||
|
- FMath::Sqrt(DX * DX + DY * DY);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutColumn.bHasLandingXYCache = Plan.Landings.Num() <= UE_ARRAY_COUNT(
|
||||||
|
OutColumn.LandingDistanceSquared);
|
||||||
|
if (OutColumn.bHasLandingXYCache)
|
||||||
|
{
|
||||||
|
const FLandingSite* Hub = Plan.LandingHubIndex != INDEX_NONE
|
||||||
|
? &Plan.Landings[Plan.LandingHubIndex] : nullptr;
|
||||||
|
for (int32 SiteIndex = 0; SiteIndex < Plan.Landings.Num(); ++SiteIndex)
|
||||||
|
{
|
||||||
|
const FLandingSite& Site = Plan.Landings[SiteIndex];
|
||||||
|
const float DX = X - Site.Position.X;
|
||||||
|
const float DY = Y - Site.Position.Y;
|
||||||
|
const float DistanceSquared = DX * DX + DY * DY;
|
||||||
|
OutColumn.LandingDistanceSquared[SiteIndex] = DistanceSquared;
|
||||||
|
OutColumn.LandingDistance[SiteIndex] = FMath::Sqrt(DistanceSquared);
|
||||||
|
OutColumn.LandingBridgeT[SiteIndex] = 0.0f;
|
||||||
|
OutColumn.LandingBridgeHorizontal[SiteIndex] = -FLT_MAX;
|
||||||
|
if (Hub != nullptr && Plan.Landings.Num() > 1
|
||||||
|
&& SiteIndex != Plan.LandingHubIndex)
|
||||||
|
{
|
||||||
|
OutColumn.LandingBridgeT[SiteIndex] = SegmentParameterXY(
|
||||||
|
X, Y, Site.Position, Hub->Position);
|
||||||
|
OutColumn.LandingBridgeHorizontal[SiteIndex] = LandingBridgeRadius
|
||||||
|
- FMath::Sqrt(DistanceSquaredToSegmentXY(
|
||||||
|
X, Y, Site.Position, Hub->Position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float EvaluateParameterizedMacro(
|
||||||
|
const FStratePlan& Plan, float X, float Y, float Z, float* OutDetailScale,
|
||||||
|
const FParameterizedBrickContext* Context = nullptr,
|
||||||
|
const FParameterizedColumnContext* ColumnContext = nullptr)
|
||||||
|
{
|
||||||
|
FParameterizedColumnContext LocalColumn;
|
||||||
|
if (ColumnContext == nullptr)
|
||||||
|
{
|
||||||
|
BuildParameterizedColumnContext(Plan, X, Y, Context, LocalColumn);
|
||||||
|
ColumnContext = &LocalColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Macro = -FLT_MAX;
|
float Macro = -FLT_MAX;
|
||||||
for (const FGeneratedCaveCell& Cell : Cells)
|
|
||||||
{
|
|
||||||
const float DX = X - Cell.CenterX;
|
|
||||||
const float DY = Y - Cell.CenterY;
|
|
||||||
const float Horizontal = Cell.RadiusX - FMath::Sqrt(DX * DX + DY * DY);
|
|
||||||
if (Macro > -FLT_MAX * 0.5f && Horizontal < Macro - 6.0f)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Macro = SmoothMaximum(Macro,
|
|
||||||
GeneratedRoomCell(Plan, Cell, X, Y, Z), 6.0f);
|
|
||||||
}
|
|
||||||
const FGeneratedCaveCell& Centre = Cells[4];
|
|
||||||
const int32 EdgeIndices[] = {1, 7, 3, 5};
|
|
||||||
for (const int32 EdgeIndex : EdgeIndices)
|
|
||||||
{
|
|
||||||
Macro = SmoothMaximum(Macro,
|
|
||||||
GeneratedTunnelEdge(Plan, Centre, Cells[EdgeIndex], X, Y, Z), 5.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float Bottom = static_cast<float>(Plan.MinChunkZ * CHUNK_SIZE) + 8.0f;
|
const float Bottom = static_cast<float>(Plan.MinChunkZ * CHUNK_SIZE) + 8.0f;
|
||||||
const float Top = static_cast<float>(Plan.MaxChunkZExclusive * CHUNK_SIZE) - 8.0f;
|
const float Top = static_cast<float>(Plan.MaxChunkZExclusive * CHUNK_SIZE) - 8.0f;
|
||||||
for (const FGeneratedCaveCell& Cell : Cells)
|
static constexpr int32 CellEvaluationOrder[] = {4, 1, 3, 5, 7, 0, 2, 6, 8};
|
||||||
|
for (int32 OrderIndex = 0;
|
||||||
|
OrderIndex < UE_ARRAY_COUNT(CellEvaluationOrder); ++OrderIndex)
|
||||||
{
|
{
|
||||||
const uint32 ShaftHash = Hash3(
|
const int32 Index = CellEvaluationOrder[OrderIndex];
|
||||||
Cell.CellX, Cell.CellY, 0x53, Plan.GenerationSeed);
|
const FGeneratedCaveCell& Cell = *ColumnContext->Cells[Index];
|
||||||
if (VoxelHash::ToFloat01(ShaftHash) >= Plan.Generation.VerticalShaftProbability)
|
const float DistanceSquared = ColumnContext->RoomDistanceSquared[Index];
|
||||||
|
if (Macro > -FLT_MAX * 0.5f)
|
||||||
|
{
|
||||||
|
const float MaximumDistance = Cell.RadiusX - Macro + 6.0f;
|
||||||
|
if (MaximumDistance < 0.0f
|
||||||
|
|| DistanceSquared > FMath::Square(MaximumDistance + 1.0e-3f))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float VerticalUpperBound = FMath::Min(
|
||||||
|
Z - ColumnContext->RoomFloors[Index], Cell.CeilingZ - Z);
|
||||||
|
if (VerticalUpperBound <= Macro - 6.0f)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Macro = SmoothMaximum(Macro,
|
||||||
|
GeneratedRoomCell(Cell, Z,
|
||||||
|
ColumnContext->RoomRadii[Index],
|
||||||
|
ColumnContext->RoomHorizontals[Index],
|
||||||
|
*ColumnContext, Index), 6.0f);
|
||||||
|
}
|
||||||
|
const FGeneratedCaveCell& Centre = *ColumnContext->Cells[4];
|
||||||
|
const int32 EdgeIndices[] = {1, 7, 3, 5};
|
||||||
|
const uint8 EdgeFlags[] = {
|
||||||
|
TunnelToNegativeY, TunnelToPositiveY,
|
||||||
|
TunnelToNegativeX, TunnelToPositiveX};
|
||||||
|
for (int32 EdgeIndex = 0; EdgeIndex < UE_ARRAY_COUNT(EdgeIndices); ++EdgeIndex)
|
||||||
|
{
|
||||||
|
if ((Centre.OpenTunnelEdges & EdgeFlags[EdgeIndex]) != 0)
|
||||||
|
{
|
||||||
|
Macro = SmoothMaximum(Macro, GeneratedTunnelEdge(
|
||||||
|
Plan, Centre, *ColumnContext->Cells[EdgeIndices[EdgeIndex]], Z,
|
||||||
|
ColumnContext->TunnelT[EdgeIndex],
|
||||||
|
ColumnContext->TunnelHorizontal[EdgeIndex]), 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 Index = 0; Index < UE_ARRAY_COUNT(ColumnContext->Cells); ++Index)
|
||||||
|
{
|
||||||
|
const FGeneratedCaveCell& Cell = *ColumnContext->Cells[Index];
|
||||||
|
if ((Cell.FeatureFlags & HasVerticalShaftFlag) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float DistanceSquared = ColumnContext->RoomDistanceSquared[Index];
|
||||||
|
const float MaximumDistance = Plan.Generation.ShaftRadiusVoxels - Macro + 5.0f;
|
||||||
|
if (MaximumDistance < 0.0f
|
||||||
|
|| DistanceSquared > FMath::Square(MaximumDistance + 1.0e-3f))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const float DX = X - Cell.CenterX;
|
|
||||||
const float DY = Y - Cell.CenterY;
|
|
||||||
const float Horizontal = Plan.Generation.ShaftRadiusVoxels
|
const float Horizontal = Plan.Generation.ShaftRadiusVoxels
|
||||||
- FMath::Sqrt(DX * DX + DY * DY);
|
- ColumnContext->RoomRadii[Index];
|
||||||
const float Vertical = FMath::Min(Z - Bottom, Top - Z);
|
const float Vertical = FMath::Min(Z - Bottom, Top - Z);
|
||||||
Macro = SmoothMaximum(Macro,
|
Macro = SmoothMaximum(Macro,
|
||||||
SmoothMinimum(Horizontal, Vertical, 5.0f), 5.0f);
|
SmoothMinimum(Horizontal, Vertical, 5.0f), 5.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float DetailFade = 1.0f;
|
float DetailFade = 1.0f;
|
||||||
for (const FLandingSite& Site : Plan.Landings)
|
for (int32 SiteIndex = 0; SiteIndex < Plan.Landings.Num(); ++SiteIndex)
|
||||||
{
|
{
|
||||||
const float DX = X - Site.Position.X;
|
const FLandingSite& Site = Plan.Landings[SiteIndex];
|
||||||
const float DY = Y - Site.Position.Y;
|
float DistanceSquared = 0.0f;
|
||||||
const float DistanceSquared = DX * DX + DY * DY;
|
float Distance = 0.0f;
|
||||||
const float Distance = FMath::Sqrt(DistanceSquared);
|
if (ColumnContext->bHasLandingXYCache)
|
||||||
|
{
|
||||||
|
DistanceSquared = ColumnContext->LandingDistanceSquared[SiteIndex];
|
||||||
|
Distance = ColumnContext->LandingDistance[SiteIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const float DX = X - Site.Position.X;
|
||||||
|
const float DY = Y - Site.Position.Y;
|
||||||
|
DistanceSquared = DX * DX + DY * DY;
|
||||||
|
Distance = FMath::Sqrt(DistanceSquared);
|
||||||
|
}
|
||||||
const float RoomAir = FMath::Min(
|
const float RoomAir = FMath::Min(
|
||||||
Site.PadRadius - Distance,
|
Site.PadRadius - Distance,
|
||||||
FMath::Min(Z - Site.FloorZ, Site.FloorZ + MinimumCaveHeight - Z));
|
FMath::Min(Z - Site.FloorZ, Site.FloorZ + MinimumCaveHeight - Z));
|
||||||
@@ -1106,39 +1416,20 @@ namespace
|
|||||||
DetailFade = 0.0f;
|
DetailFade = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float AnchorReach = Plan.Generation.RoomPitchVoxels * 1.25f
|
if (!Site.bGeneratedAnchorPrepared
|
||||||
+ FMath::Max(32.0f, Plan.Generation.TunnelRadiusVoxels);
|
|| DistanceSquared > FMath::Square(Site.GeneratedAnchorReach))
|
||||||
if (DistanceSquared > FMath::Square(AnchorReach))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const FIntPoint LandingCell = GenerationCellAt(Plan, Site.Position.X, Site.Position.Y);
|
|
||||||
FGeneratedCaveCell NearestCell;
|
|
||||||
float BestDistanceSq = FLT_MAX;
|
|
||||||
for (int32 CellY = -1; CellY <= 1; ++CellY)
|
|
||||||
for (int32 CellX = -1; CellX <= 1; ++CellX)
|
|
||||||
{
|
|
||||||
const FGeneratedCaveCell Candidate = BuildGeneratedCell(
|
|
||||||
Plan, LandingCell.X + CellX, LandingCell.Y + CellY);
|
|
||||||
const float CandidateDistanceSq = FMath::Square(Candidate.CenterX - Site.Position.X)
|
|
||||||
+ FMath::Square(Candidate.CenterY - Site.Position.Y);
|
|
||||||
if (CandidateDistanceSq < BestDistanceSq)
|
|
||||||
{
|
|
||||||
BestDistanceSq = CandidateDistanceSq;
|
|
||||||
NearestCell = Candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const FVector AnchorA(Site.Position.X, Site.Position.Y, Site.FloorZ + 24.0f);
|
|
||||||
const FVector AnchorB(NearestCell.CenterX, NearestCell.CenterY,
|
|
||||||
NearestCell.FloorZ + Plan.Generation.TunnelHalfHeightVoxels);
|
|
||||||
const FVector Segment = AnchorB - AnchorA;
|
|
||||||
const float SegmentLengthSq = Segment.SizeSquared();
|
|
||||||
const FVector Point(X, Y, Z);
|
const FVector Point(X, Y, Z);
|
||||||
const float T = SegmentLengthSq > 1.0e-8f
|
const float T = Site.GeneratedAnchorLengthSquared > 1.0e-8f
|
||||||
? FMath::Clamp(FVector::DotProduct(Point - AnchorA, Segment) / SegmentLengthSq,
|
? FMath::Clamp(FVector::DotProduct(
|
||||||
0.0f, 1.0f) : 0.0f;
|
Point - Site.GeneratedAnchorStart, Site.GeneratedAnchorDelta)
|
||||||
|
/ Site.GeneratedAnchorLengthSquared, 0.0f, 1.0f) : 0.0f;
|
||||||
|
const FVector AnchorDelta = Point
|
||||||
|
- (Site.GeneratedAnchorStart + Site.GeneratedAnchorDelta * T);
|
||||||
const float Anchor = FMath::Max(32.0f, Plan.Generation.TunnelRadiusVoxels)
|
const float Anchor = FMath::Max(32.0f, Plan.Generation.TunnelRadiusVoxels)
|
||||||
- (Point - (AnchorA + Segment * T)).Size();
|
- AnchorDelta.Size();
|
||||||
Macro = SmoothMaximum(Macro, Anchor, 5.0f);
|
Macro = SmoothMaximum(Macro, Anchor, 5.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,9 +1443,13 @@ namespace
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const FLandingSite& Site = Plan.Landings[SiteIndex];
|
const FLandingSite& Site = Plan.Landings[SiteIndex];
|
||||||
const float Horizontal = LandingBridgeRadius - FMath::Sqrt(
|
const float Horizontal = ColumnContext->bHasLandingXYCache
|
||||||
DistanceSquaredToSegmentXY(X, Y, Site.Position, Hub.Position));
|
? ColumnContext->LandingBridgeHorizontal[SiteIndex]
|
||||||
const float T = SegmentParameterXY(X, Y, Site.Position, Hub.Position);
|
: LandingBridgeRadius - FMath::Sqrt(
|
||||||
|
DistanceSquaredToSegmentXY(X, Y, Site.Position, Hub.Position));
|
||||||
|
const float T = ColumnContext->bHasLandingXYCache
|
||||||
|
? ColumnContext->LandingBridgeT[SiteIndex]
|
||||||
|
: SegmentParameterXY(X, Y, Site.Position, Hub.Position);
|
||||||
const float FloorZ = FMath::Lerp(Site.FloorZ, Hub.FloorZ, T);
|
const float FloorZ = FMath::Lerp(Site.FloorZ, Hub.FloorZ, T);
|
||||||
const float Vertical = FMath::Min(
|
const float Vertical = FMath::Min(
|
||||||
Z - FloorZ, FloorZ + MinimumCaveHeight - Z);
|
Z - FloorZ, FloorZ + MinimumCaveHeight - Z);
|
||||||
@@ -1455,6 +1750,10 @@ void ResetThreadCache()
|
|||||||
{
|
{
|
||||||
GPlanCache = FThreadPlanCache();
|
GPlanCache = FThreadPlanCache();
|
||||||
GShaftEdgeCache = FThreadShaftEdgeCache();
|
GShaftEdgeCache = FThreadShaftEdgeCache();
|
||||||
|
GParameterizedRoomCellCache.Reset();
|
||||||
|
GParameterizedRoomCellCacheMin = FIntPoint::ZeroValue;
|
||||||
|
GParameterizedRoomCellCacheSize = FIntPoint::ZeroValue;
|
||||||
|
GParameterizedRoomCellCachePlan = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float EvaluateInternal(const UVoxelGenerator& Generator,
|
static float EvaluateInternal(const UVoxelGenerator& Generator,
|
||||||
@@ -1462,7 +1761,8 @@ static float EvaluateInternal(const UVoxelGenerator& Generator,
|
|||||||
float* OutPreEditDensity, float DetailScale,
|
float* OutPreEditDensity, float DetailScale,
|
||||||
const FBrickEvaluationContext* Context = nullptr,
|
const FBrickEvaluationContext* Context = nullptr,
|
||||||
bool bParameterized = false,
|
bool bParameterized = false,
|
||||||
const FParameterizedBrickContext* ParameterizedContext = nullptr)
|
const FParameterizedBrickContext* ParameterizedContext = nullptr,
|
||||||
|
const FParameterizedColumnContext* ParameterizedColumnContext = nullptr)
|
||||||
{
|
{
|
||||||
if (Context == nullptr && ParameterizedContext == nullptr)
|
if (Context == nullptr && ParameterizedContext == nullptr)
|
||||||
{
|
{
|
||||||
@@ -1509,7 +1809,8 @@ static float EvaluateInternal(const UVoxelGenerator& Generator,
|
|||||||
{
|
{
|
||||||
float DetailFade = 1.0f;
|
float DetailFade = 1.0f;
|
||||||
const float Macro = bParameterized
|
const float Macro = bParameterized
|
||||||
? EvaluateParameterizedMacro(*Plan, WorldX, WorldY, WorldZ, &DetailFade)
|
? EvaluateParameterizedMacro(*Plan, WorldX, WorldY, WorldZ, &DetailFade,
|
||||||
|
ParameterizedContext, ParameterizedColumnContext)
|
||||||
: (Context != nullptr && Context->bMacroXYPrecomputed
|
: (Context != nullptr && Context->bMacroXYPrecomputed
|
||||||
? EvaluateMacroFromBrick(*Plan, *Context, WorldX, WorldY, WorldZ, &DetailFade)
|
? EvaluateMacroFromBrick(*Plan, *Context, WorldX, WorldY, WorldZ, &DetailFade)
|
||||||
: EvaluateMacro(*Plan, WorldX, WorldY, WorldZ, &DetailFade));
|
: EvaluateMacro(*Plan, WorldX, WorldY, WorldZ, &DetailFade));
|
||||||
@@ -1635,6 +1936,51 @@ float EvaluateParameterizedWithDetailValue(const UVoxelGenerator& Generator,
|
|||||||
OutPreEditDensity, DetailScale, nullptr, true, Context);
|
OutPreEditDensity, DetailScale, nullptr, true, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EvaluateParameterizedColumnWithDetailValues(
|
||||||
|
const UVoxelGenerator& Generator, float WorldX, float WorldY, float WorldZStart,
|
||||||
|
const float* DetailValues, int32 DetailStride, int32 Count, float* OutValues,
|
||||||
|
const FParameterizedBrickContext* Context, float DetailScale)
|
||||||
|
{
|
||||||
|
if (DetailValues == nullptr || OutValues == nullptr || Count <= 0 || DetailStride <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const FIntVector Chunk(
|
||||||
|
FMath::FloorToInt(WorldX / CHUNK_SIZE),
|
||||||
|
FMath::FloorToInt(WorldY / CHUNK_SIZE),
|
||||||
|
FMath::FloorToInt(WorldZStart / CHUNK_SIZE));
|
||||||
|
const FStratePlan* Plan = Context != nullptr && Context->bPlanResolved
|
||||||
|
? static_cast<const FStratePlan*>(Context->PlanToken) : nullptr;
|
||||||
|
if (Plan == nullptr)
|
||||||
|
{
|
||||||
|
EnsurePlan(Generator);
|
||||||
|
Plan = FindStrate(Chunk);
|
||||||
|
}
|
||||||
|
const int32 EndChunkZ = FMath::FloorToInt(
|
||||||
|
(WorldZStart + static_cast<float>(Count - 1)) / CHUNK_SIZE);
|
||||||
|
if (Plan == nullptr || Chunk.Z != EndChunkZ)
|
||||||
|
{
|
||||||
|
for (int32 Z = 0; Z < Count; ++Z)
|
||||||
|
{
|
||||||
|
OutValues[Z] = EvaluateInternal(
|
||||||
|
Generator, WorldX, WorldY, WorldZStart + static_cast<float>(Z),
|
||||||
|
DetailValues[Z * DetailStride], true, nullptr, DetailScale,
|
||||||
|
nullptr, true, Context);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FParameterizedColumnContext ColumnContext;
|
||||||
|
BuildParameterizedColumnContext(*Plan, WorldX, WorldY, Context, ColumnContext);
|
||||||
|
for (int32 Z = 0; Z < Count; ++Z)
|
||||||
|
{
|
||||||
|
OutValues[Z] = EvaluateInternal(
|
||||||
|
Generator, WorldX, WorldY, WorldZStart + static_cast<float>(Z),
|
||||||
|
DetailValues[Z * DetailStride], true, nullptr, DetailScale,
|
||||||
|
nullptr, true, Context, &ColumnContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BuildParameterizedBrickContext(
|
void BuildParameterizedBrickContext(
|
||||||
const UVoxelGenerator& Generator, FIntVector OriginVoxels, FIntVector Size,
|
const UVoxelGenerator& Generator, FIntVector OriginVoxels, FIntVector Size,
|
||||||
FParameterizedBrickContext& OutContext)
|
FParameterizedBrickContext& OutContext)
|
||||||
@@ -1674,6 +2020,58 @@ void BuildParameterizedBrickContext(
|
|||||||
static_cast<float>(OriginVoxels.Z + Size.Z));
|
static_cast<float>(OriginVoxels.Z + Size.Z));
|
||||||
FindPassageCandidates(FBox(Min, Max), OutContext.PassageCandidates);
|
FindPassageCandidates(FBox(Min, Max), OutContext.PassageCandidates);
|
||||||
OutContext.bMayContainPassage = !OutContext.PassageCandidates.IsEmpty();
|
OutContext.bMayContainPassage = !OutContext.PassageCandidates.IsEmpty();
|
||||||
|
|
||||||
|
if (Plan != nullptr && bStableStrate && !OutContext.bIsGapChunk
|
||||||
|
&& Size.X > 0 && Size.Y > 0)
|
||||||
|
{
|
||||||
|
FIntPoint MinimumBaseCell(MAX_int32, MAX_int32);
|
||||||
|
FIntPoint MaximumBaseCell(MIN_int32, MIN_int32);
|
||||||
|
const int32 CornerX[] = {OriginVoxels.X, End.X};
|
||||||
|
const int32 CornerY[] = {OriginVoxels.Y, End.Y};
|
||||||
|
for (const int32 WorldY : CornerY)
|
||||||
|
for (const int32 WorldX : CornerX)
|
||||||
|
{
|
||||||
|
const FIntPoint Cell = GenerationCellAt(
|
||||||
|
*Plan, static_cast<float>(WorldX), static_cast<float>(WorldY));
|
||||||
|
MinimumBaseCell.X = FMath::Min(MinimumBaseCell.X, Cell.X);
|
||||||
|
MinimumBaseCell.Y = FMath::Min(MinimumBaseCell.Y, Cell.Y);
|
||||||
|
MaximumBaseCell.X = FMath::Max(MaximumBaseCell.X, Cell.X);
|
||||||
|
MaximumBaseCell.Y = FMath::Max(MaximumBaseCell.Y, Cell.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FIntPoint NeededMin = MinimumBaseCell - FIntPoint(1, 1);
|
||||||
|
const FIntPoint NeededMax = MaximumBaseCell + FIntPoint(1, 1);
|
||||||
|
const bool bCacheContainsNeededCells = GParameterizedRoomCellCachePlan == Plan
|
||||||
|
&& GParameterizedRoomCellCacheMin.X <= NeededMin.X
|
||||||
|
&& GParameterizedRoomCellCacheMin.Y <= NeededMin.Y
|
||||||
|
&& GParameterizedRoomCellCacheMin.X + GParameterizedRoomCellCacheSize.X - 1
|
||||||
|
>= NeededMax.X
|
||||||
|
&& GParameterizedRoomCellCacheMin.Y + GParameterizedRoomCellCacheSize.Y - 1
|
||||||
|
>= NeededMax.Y;
|
||||||
|
if (!bCacheContainsNeededCells)
|
||||||
|
{
|
||||||
|
// Keep one extra generated-cell layer beyond the 3x3 query halo so adjacent
|
||||||
|
// proof bricks reuse their deterministic room and edge rolls.
|
||||||
|
GParameterizedRoomCellCacheMin = MinimumBaseCell - FIntPoint(2, 2);
|
||||||
|
GParameterizedRoomCellCacheSize = MaximumBaseCell - MinimumBaseCell
|
||||||
|
+ FIntPoint(5, 5);
|
||||||
|
const int32 RoomCellCount = GParameterizedRoomCellCacheSize.X
|
||||||
|
* GParameterizedRoomCellCacheSize.Y;
|
||||||
|
GParameterizedRoomCellCache.SetNumUninitialized(RoomCellCount);
|
||||||
|
int32 RoomCellIndex = 0;
|
||||||
|
for (int32 CellY = 0; CellY < GParameterizedRoomCellCacheSize.Y; ++CellY)
|
||||||
|
for (int32 CellX = 0; CellX < GParameterizedRoomCellCacheSize.X; ++CellX)
|
||||||
|
{
|
||||||
|
GParameterizedRoomCellCache[RoomCellIndex++] = BuildGeneratedCell(
|
||||||
|
*Plan, GParameterizedRoomCellCacheMin.X + CellX,
|
||||||
|
GParameterizedRoomCellCacheMin.Y + CellY);
|
||||||
|
}
|
||||||
|
GParameterizedRoomCellCachePlan = Plan;
|
||||||
|
}
|
||||||
|
OutContext.RoomCellCacheMin = GParameterizedRoomCellCacheMin;
|
||||||
|
OutContext.RoomCellCacheSize = GParameterizedRoomCellCacheSize;
|
||||||
|
OutContext.RoomCellCacheToken = GParameterizedRoomCellCache.GetData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildDetailBrick(const UVoxelGenerator& Generator, FIntVector OriginVoxels,
|
void BuildDetailBrick(const UVoxelGenerator& Generator, FIntVector OriginVoxels,
|
||||||
@@ -1879,22 +2277,47 @@ void BuildDetailBrick(const UVoxelGenerator& Generator, FIntVector OriginVoxels,
|
|||||||
MinCellX + X, MinCellY + Y, MinCellZ + Z, BandSeed);
|
MinCellX + X, MinCellY + Y, MinCellZ + Z, BandSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32 Z = 0; Z < Size.Z; ++Z)
|
int32 CellX[8];
|
||||||
for (int32 Y = 0; Y < Size.Y; ++Y)
|
int32 CellY[8];
|
||||||
|
int32 CellZ[8];
|
||||||
|
float FadeX[8];
|
||||||
|
float FadeY[8];
|
||||||
|
float FadeZ[8];
|
||||||
for (int32 X = 0; X < Size.X; ++X)
|
for (int32 X = 0; X < Size.X; ++X)
|
||||||
{
|
{
|
||||||
const float SX = static_cast<float>(OriginVoxels.X + X)
|
const float SX = static_cast<float>(OriginVoxels.X + X)
|
||||||
/ static_cast<float>(CellSize);
|
/ static_cast<float>(CellSize);
|
||||||
|
const int32 Cell = FMath::FloorToInt(SX);
|
||||||
|
CellX[X] = Cell - MinCellX;
|
||||||
|
FadeX[X] = Fade(SX - static_cast<float>(Cell));
|
||||||
|
}
|
||||||
|
for (int32 Y = 0; Y < Size.Y; ++Y)
|
||||||
|
{
|
||||||
const float SY = static_cast<float>(OriginVoxels.Y + Y)
|
const float SY = static_cast<float>(OriginVoxels.Y + Y)
|
||||||
/ static_cast<float>(CellSize);
|
/ static_cast<float>(CellSize);
|
||||||
|
const int32 Cell = FMath::FloorToInt(SY);
|
||||||
|
CellY[Y] = Cell - MinCellY;
|
||||||
|
FadeY[Y] = Fade(SY - static_cast<float>(Cell));
|
||||||
|
}
|
||||||
|
for (int32 Z = 0; Z < Size.Z; ++Z)
|
||||||
|
{
|
||||||
const float SZ = static_cast<float>(OriginVoxels.Z + Z)
|
const float SZ = static_cast<float>(OriginVoxels.Z + Z)
|
||||||
/ static_cast<float>(CellSize);
|
/ static_cast<float>(CellSize);
|
||||||
const int32 IX = FMath::FloorToInt(SX) - MinCellX;
|
const int32 Cell = FMath::FloorToInt(SZ);
|
||||||
const int32 IY = FMath::FloorToInt(SY) - MinCellY;
|
CellZ[Z] = Cell - MinCellZ;
|
||||||
const int32 IZ = FMath::FloorToInt(SZ) - MinCellZ;
|
FadeZ[Z] = Fade(SZ - static_cast<float>(Cell));
|
||||||
const float AX = Fade(SX - static_cast<float>(FMath::FloorToInt(SX)));
|
}
|
||||||
const float AY = Fade(SY - static_cast<float>(FMath::FloorToInt(SY)));
|
|
||||||
const float AZ = Fade(SZ - static_cast<float>(FMath::FloorToInt(SZ)));
|
for (int32 Z = 0; Z < Size.Z; ++Z)
|
||||||
|
for (int32 Y = 0; Y < Size.Y; ++Y)
|
||||||
|
for (int32 X = 0; X < Size.X; ++X)
|
||||||
|
{
|
||||||
|
const int32 IX = CellX[X];
|
||||||
|
const int32 IY = CellY[Y];
|
||||||
|
const int32 IZ = CellZ[Z];
|
||||||
|
const float AX = FadeX[X];
|
||||||
|
const float AY = FadeY[Y];
|
||||||
|
const float AZ = FadeZ[Z];
|
||||||
const int32 Index = (IZ * GridY + IY) * GridX + IX;
|
const int32 Index = (IZ * GridY + IY) * GridX + IX;
|
||||||
const float Value = CellSize == 1
|
const float Value = CellSize == 1
|
||||||
? Grid[Index]
|
? Grid[Index]
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ namespace VoxelForgeRedefinedDensityField
|
|||||||
struct FParameterizedBrickContext
|
struct FParameterizedBrickContext
|
||||||
{
|
{
|
||||||
const void* PlanToken = nullptr;
|
const void* PlanToken = nullptr;
|
||||||
|
const void* RoomCellCacheToken = nullptr;
|
||||||
bool bPlanResolved = false;
|
bool bPlanResolved = false;
|
||||||
bool bChunkResolved = false;
|
bool bChunkResolved = false;
|
||||||
bool bIsGapChunk = false;
|
bool bIsGapChunk = false;
|
||||||
@@ -74,6 +75,8 @@ namespace VoxelForgeRedefinedDensityField
|
|||||||
FIntVector BrickOrigin = FIntVector::ZeroValue;
|
FIntVector BrickOrigin = FIntVector::ZeroValue;
|
||||||
FIntVector BrickSize = FIntVector::ZeroValue;
|
FIntVector BrickSize = FIntVector::ZeroValue;
|
||||||
FIntVector Chunk = FIntVector::ZeroValue;
|
FIntVector Chunk = FIntVector::ZeroValue;
|
||||||
|
FIntPoint RoomCellCacheMin = FIntPoint::ZeroValue;
|
||||||
|
FIntPoint RoomCellCacheSize = FIntPoint::ZeroValue;
|
||||||
TArray<int32> PassageCandidates;
|
TArray<int32> PassageCandidates;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,6 +120,12 @@ namespace VoxelForgeRedefinedDensityField
|
|||||||
float DetailValue, float* OutPreEditDensity = nullptr, float DetailScale = 1.0f,
|
float DetailValue, float* OutPreEditDensity = nullptr, float DetailScale = 1.0f,
|
||||||
const FParameterizedBrickContext* Context = nullptr);
|
const FParameterizedBrickContext* Context = nullptr);
|
||||||
|
|
||||||
|
/** Evaluate a Z column while reusing its XY-dependent room graph data. */
|
||||||
|
VOXELFORGE_API void EvaluateParameterizedColumnWithDetailValues(
|
||||||
|
const UVoxelGenerator& Generator, float WorldX, float WorldY, float WorldZStart,
|
||||||
|
const float* DetailValues, int32 DetailStride, int32 Count, float* OutValues,
|
||||||
|
const FParameterizedBrickContext* Context = nullptr, float DetailScale = 1.0f);
|
||||||
|
|
||||||
VOXELFORGE_API bool TryClassifyParameterizedBrick(
|
VOXELFORGE_API bool TryClassifyParameterizedBrick(
|
||||||
const UVoxelGenerator& Generator, FIntVector OriginVoxels, FIntVector Size,
|
const UVoxelGenerator& Generator, FIntVector OriginVoxels, FIntVector Size,
|
||||||
bool& bOutAir, float DetailScale = 1.0f,
|
bool& bOutAir, float DetailScale = 1.0f,
|
||||||
|
|||||||
@@ -2545,6 +2545,18 @@ struct FStep2dBrickProofAudit
|
|||||||
uint64 CorrectlySkippedBricksAudited = 0;
|
uint64 CorrectlySkippedBricksAudited = 0;
|
||||||
uint64 CorrectProofSamplesChecked = 0;
|
uint64 CorrectProofSamplesChecked = 0;
|
||||||
uint64 CorrectProofViolations = 0;
|
uint64 CorrectProofViolations = 0;
|
||||||
|
FIntVector FirstViolationBrickOrigin = FIntVector::ZeroValue;
|
||||||
|
FIntVector FirstViolationBrickSize = FIntVector::ZeroValue;
|
||||||
|
FIntVector FirstViolationSample = FIntVector::ZeroValue;
|
||||||
|
float FirstViolationDensity = 0.0f;
|
||||||
|
float FirstViolationCenterMacro = 0.0f;
|
||||||
|
float FirstViolationSampleMacro = 0.0f;
|
||||||
|
float FirstViolationSampleDetail = 0.0f;
|
||||||
|
float FirstViolationMacroDeltaPerVoxel = 0.0f;
|
||||||
|
float FirstViolationPathMaxGradient = 0.0f;
|
||||||
|
float FirstViolationTinyStepMaxGradient = 0.0f;
|
||||||
|
bool bFirstViolationWasInsideBrick = false;
|
||||||
|
bool bFirstViolationClaimedAir = false;
|
||||||
uint64 DeliberatelyUndersizedBoundClaimsChecked = 0;
|
uint64 DeliberatelyUndersizedBoundClaimsChecked = 0;
|
||||||
uint64 DeliberateBoundDisagreements = 0;
|
uint64 DeliberateBoundDisagreements = 0;
|
||||||
};
|
};
|
||||||
@@ -2608,6 +2620,88 @@ FStep2dBrickProofAudit AuditStep2dBrickProofs(
|
|||||||
++Result.CorrectProofSamplesChecked;
|
++Result.CorrectProofSamplesChecked;
|
||||||
if ((Density > 0.0f) != bProvenAir)
|
if ((Density > 0.0f) != bProvenAir)
|
||||||
{
|
{
|
||||||
|
if (Result.CorrectProofViolations == 0)
|
||||||
|
{
|
||||||
|
Result.FirstViolationBrickOrigin = BrickOrigin;
|
||||||
|
Result.FirstViolationBrickSize = Size;
|
||||||
|
Result.FirstViolationSample = BrickOrigin + FIntVector(X, Y, Z);
|
||||||
|
Result.FirstViolationDensity = Density;
|
||||||
|
const FVector ProofMin(
|
||||||
|
static_cast<float>(BrickOrigin.X - 1),
|
||||||
|
static_cast<float>(BrickOrigin.Y - 1),
|
||||||
|
static_cast<float>(BrickOrigin.Z - 1));
|
||||||
|
const FVector ProofMax(
|
||||||
|
static_cast<float>(BrickOrigin.X + Size.X),
|
||||||
|
static_cast<float>(BrickOrigin.Y + Size.Y),
|
||||||
|
static_cast<float>(BrickOrigin.Z + Size.Z));
|
||||||
|
const FVector ProofCentre = (ProofMin + ProofMax) * 0.5f;
|
||||||
|
const FVector SamplePoint(
|
||||||
|
static_cast<float>(BrickOrigin.X + X),
|
||||||
|
static_cast<float>(BrickOrigin.Y + Y),
|
||||||
|
static_cast<float>(BrickOrigin.Z + Z));
|
||||||
|
Result.FirstViolationCenterMacro = bParameterized
|
||||||
|
? VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||||
|
Generator, ProofCentre.X, ProofCentre.Y, ProofCentre.Z,
|
||||||
|
nullptr, 0.0f)
|
||||||
|
: VoxelForgeRedefinedDensityField::Evaluate(
|
||||||
|
Generator, ProofCentre.X, ProofCentre.Y, ProofCentre.Z,
|
||||||
|
nullptr, 0.0f);
|
||||||
|
Result.FirstViolationSampleMacro = bParameterized
|
||||||
|
? VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||||
|
Generator, SamplePoint.X, SamplePoint.Y, SamplePoint.Z,
|
||||||
|
nullptr, 0.0f)
|
||||||
|
: VoxelForgeRedefinedDensityField::Evaluate(
|
||||||
|
Generator, SamplePoint.X, SamplePoint.Y, SamplePoint.Z,
|
||||||
|
nullptr, 0.0f);
|
||||||
|
Result.FirstViolationSampleDetail = Density
|
||||||
|
- Result.FirstViolationSampleMacro;
|
||||||
|
const float CentreDistance = (SamplePoint - ProofCentre).Size();
|
||||||
|
Result.FirstViolationMacroDeltaPerVoxel = CentreDistance > 1.0e-6f
|
||||||
|
? FMath::Abs(Result.FirstViolationCenterMacro
|
||||||
|
- Result.FirstViolationSampleMacro) / CentreDistance
|
||||||
|
: 0.0f;
|
||||||
|
if (CentreDistance > 1.0e-6f)
|
||||||
|
{
|
||||||
|
constexpr int32 PathSteps = 32;
|
||||||
|
float PreviousMacro = Result.FirstViolationSampleMacro;
|
||||||
|
for (int32 PathStep = 1; PathStep <= PathSteps; ++PathStep)
|
||||||
|
{
|
||||||
|
const float Alpha = static_cast<float>(PathStep) / PathSteps;
|
||||||
|
const FVector Point = FMath::Lerp(
|
||||||
|
SamplePoint, ProofCentre, Alpha);
|
||||||
|
const float PathMacro = bParameterized
|
||||||
|
? VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||||
|
Generator, Point.X, Point.Y, Point.Z, nullptr, 0.0f)
|
||||||
|
: VoxelForgeRedefinedDensityField::Evaluate(
|
||||||
|
Generator, Point.X, Point.Y, Point.Z, nullptr, 0.0f);
|
||||||
|
Result.FirstViolationPathMaxGradient = FMath::Max(
|
||||||
|
Result.FirstViolationPathMaxGradient,
|
||||||
|
FMath::Abs(PathMacro - PreviousMacro)
|
||||||
|
* PathSteps / CentreDistance);
|
||||||
|
PreviousMacro = PathMacro;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constexpr float TinyStep = 0.01f;
|
||||||
|
for (int32 Axis = 0; Axis < 3; ++Axis)
|
||||||
|
for (int32 SignIndex = 0; SignIndex < 2; ++SignIndex)
|
||||||
|
{
|
||||||
|
const int32 Sign = SignIndex == 0 ? -1 : 1;
|
||||||
|
FVector Point = SamplePoint;
|
||||||
|
Point[Axis] += static_cast<float>(Sign) * TinyStep;
|
||||||
|
const float NeighborMacro = bParameterized
|
||||||
|
? VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||||
|
Generator, Point.X, Point.Y, Point.Z, nullptr, 0.0f)
|
||||||
|
: VoxelForgeRedefinedDensityField::Evaluate(
|
||||||
|
Generator, Point.X, Point.Y, Point.Z, nullptr, 0.0f);
|
||||||
|
Result.FirstViolationTinyStepMaxGradient = FMath::Max(
|
||||||
|
Result.FirstViolationTinyStepMaxGradient,
|
||||||
|
FMath::Abs(NeighborMacro - Result.FirstViolationSampleMacro)
|
||||||
|
/ TinyStep);
|
||||||
|
}
|
||||||
|
Result.bFirstViolationWasInsideBrick = X >= 0 && X < Size.X
|
||||||
|
&& Y >= 0 && Y < Size.Y && Z >= 0 && Z < Size.Z;
|
||||||
|
Result.bFirstViolationClaimedAir = bProvenAir;
|
||||||
|
}
|
||||||
++Result.CorrectProofViolations;
|
++Result.CorrectProofViolations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2805,6 +2899,17 @@ FStep2dBoundaryStats ComputeStep2dBoundaryStats(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Step2eBoundaryStatsPass(const FStep2dBoundaryStats& Stats)
|
||||||
|
{
|
||||||
|
return Stats.BrickBoundarySamples > 0
|
||||||
|
&& Stats.InteriorSamples > 0
|
||||||
|
&& Stats.ChunkBoundarySamples > 0
|
||||||
|
&& Stats.FeatureCellBoundarySamples > 0
|
||||||
|
&& Stats.BrickJumpRms <= Stats.InteriorJumpRms * 2.0 + 0.25
|
||||||
|
&& Stats.ChunkBoundaryJumpRms <= Stats.InteriorJumpRms * 2.0 + 0.25
|
||||||
|
&& Stats.FeatureCellJumpRms <= Stats.FeatureCellInteriorJumpRms * 2.0 + 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
FColor Step2dDensityColor(float Density)
|
FColor Step2dDensityColor(float Density)
|
||||||
{
|
{
|
||||||
if (FMath::Abs(Density) < 1.0f)
|
if (FMath::Abs(Density) < 1.0f)
|
||||||
@@ -2868,6 +2973,9 @@ struct FStep2eVarietyMetrics
|
|||||||
double SurfaceAreaSquareMeters = 0.0;
|
double SurfaceAreaSquareMeters = 0.0;
|
||||||
double SurfaceAreaPerVolume = 0.0;
|
double SurfaceAreaPerVolume = 0.0;
|
||||||
double VerticalAdjacencyShare = 0.0;
|
double VerticalAdjacencyShare = 0.0;
|
||||||
|
double VerticalAirColumnShare = 0.0;
|
||||||
|
double MeanLongestVerticalAirRunVoxels = 0.0;
|
||||||
|
int32 LongestVerticalAirRunVoxels = 0;
|
||||||
double TunnelNeckShare = 0.0;
|
double TunnelNeckShare = 0.0;
|
||||||
int32 ConnectedComponentsAtOneMeter = 0;
|
int32 ConnectedComponentsAtOneMeter = 0;
|
||||||
int64 LargestComponentCubicMeters = 0;
|
int64 LargestComponentCubicMeters = 0;
|
||||||
@@ -2886,6 +2994,11 @@ FStep2eVarietyMetrics ComputeStep2eVarietyMetrics(
|
|||||||
uint64 SurfaceEdgeCount = 0;
|
uint64 SurfaceEdgeCount = 0;
|
||||||
uint64 HorizontalAdjacencies = 0;
|
uint64 HorizontalAdjacencies = 0;
|
||||||
uint64 VerticalAdjacencies = 0;
|
uint64 VerticalAdjacencies = 0;
|
||||||
|
const int32 ColumnCount = Dimension * Dimension;
|
||||||
|
TArray<int32> CurrentVerticalRun;
|
||||||
|
CurrentVerticalRun.SetNumZeroed(ColumnCount);
|
||||||
|
TArray<int32> LongestVerticalRun;
|
||||||
|
LongestVerticalRun.SetNumZeroed(ColumnCount);
|
||||||
for (int32 Z = 0; Z < Dimension; ++Z)
|
for (int32 Z = 0; Z < Dimension; ++Z)
|
||||||
for (int32 Y = 0; Y < Dimension; ++Y)
|
for (int32 Y = 0; Y < Dimension; ++Y)
|
||||||
for (int32 X = 0; X < Dimension; ++X)
|
for (int32 X = 0; X < Dimension; ++X)
|
||||||
@@ -2893,6 +3006,10 @@ FStep2eVarietyMetrics ComputeStep2eVarietyMetrics(
|
|||||||
const int32 Index = (Z * Dimension + Y) * Dimension + X;
|
const int32 Index = (Z * Dimension + Y) * Dimension + X;
|
||||||
const bool bAir = Density[Index] > 0.0f;
|
const bool bAir = Density[Index] > 0.0f;
|
||||||
AirCount += bAir ? 1 : 0;
|
AirCount += bAir ? 1 : 0;
|
||||||
|
const int32 ColumnIndex = Y * Dimension + X;
|
||||||
|
CurrentVerticalRun[ColumnIndex] = bAir ? CurrentVerticalRun[ColumnIndex] + 1 : 0;
|
||||||
|
LongestVerticalRun[ColumnIndex] = FMath::Max(
|
||||||
|
LongestVerticalRun[ColumnIndex], CurrentVerticalRun[ColumnIndex]);
|
||||||
if (X + 1 < Dimension)
|
if (X + 1 < Dimension)
|
||||||
{
|
{
|
||||||
const bool bNextAir = Density[Index + 1] > 0.0f;
|
const bool bNextAir = Density[Index + 1] > 0.0f;
|
||||||
@@ -2922,6 +3039,22 @@ FStep2eVarietyMetrics ComputeStep2eVarietyMetrics(
|
|||||||
const uint64 AllAdjacencies = HorizontalAdjacencies + VerticalAdjacencies;
|
const uint64 AllAdjacencies = HorizontalAdjacencies + VerticalAdjacencies;
|
||||||
Result.VerticalAdjacencyShare = AllAdjacencies > 0
|
Result.VerticalAdjacencyShare = AllAdjacencies > 0
|
||||||
? static_cast<double>(VerticalAdjacencies) / AllAdjacencies : 0.0;
|
? static_cast<double>(VerticalAdjacencies) / AllAdjacencies : 0.0;
|
||||||
|
uint64 ColumnsWithAir = 0;
|
||||||
|
uint64 TotalLongestRunVoxels = 0;
|
||||||
|
for (const int32 LongestRun : LongestVerticalRun)
|
||||||
|
{
|
||||||
|
if (LongestRun > 0)
|
||||||
|
{
|
||||||
|
++ColumnsWithAir;
|
||||||
|
TotalLongestRunVoxels += static_cast<uint64>(LongestRun);
|
||||||
|
Result.LongestVerticalAirRunVoxels = FMath::Max(
|
||||||
|
Result.LongestVerticalAirRunVoxels, LongestRun);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result.VerticalAirColumnShare = ColumnCount > 0
|
||||||
|
? static_cast<double>(ColumnsWithAir) / ColumnCount : 0.0;
|
||||||
|
Result.MeanLongestVerticalAirRunVoxels = ColumnsWithAir > 0
|
||||||
|
? static_cast<double>(TotalLongestRunVoxels) / ColumnsWithAir : 0.0;
|
||||||
|
|
||||||
constexpr int32 CoarseStep = 4;
|
constexpr int32 CoarseStep = 4;
|
||||||
const int32 CoarseDimension = (Dimension - 1) / CoarseStep + 1;
|
const int32 CoarseDimension = (Dimension - 1) / CoarseStep + 1;
|
||||||
@@ -3056,6 +3189,90 @@ TSharedRef<FJsonObject> Step2eParametersJson(
|
|||||||
return Json;
|
return Json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSharedRef<FJsonObject> Step2eChamberVolumeQuantilesJson(
|
||||||
|
const VoxelForgeRedefinedDensityField::FGenerationParameters& P)
|
||||||
|
{
|
||||||
|
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
|
||||||
|
constexpr double Pi = 3.14159265358979323846;
|
||||||
|
constexpr double CubicMetersPerVoxel = 0.25 * 0.25 * 0.25;
|
||||||
|
const double Quantiles[] = {0.10, 0.50, 0.90};
|
||||||
|
const TCHAR* Names[] = {TEXT("p10_m3"), TEXT("p50_m3"), TEXT("p90_m3")};
|
||||||
|
for (int32 Index = 0; Index < UE_ARRAY_COUNT(Quantiles); ++Index)
|
||||||
|
{
|
||||||
|
const double RadiusFraction = FMath::Lerp(
|
||||||
|
static_cast<double>(P.MinimumRoomRadiusFraction),
|
||||||
|
static_cast<double>(P.MaximumRoomRadiusFraction), Quantiles[Index]);
|
||||||
|
const double RadiusVoxels = RadiusFraction * P.RoomPitchVoxels;
|
||||||
|
const double VolumeCubicVoxels = Pi * RadiusVoxels * RadiusVoxels
|
||||||
|
* P.RoomHeightVoxels;
|
||||||
|
Json->SetNumberField(Names[Index], VolumeCubicVoxels * CubicMetersPerVoxel);
|
||||||
|
}
|
||||||
|
return Json;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedRef<FJsonObject> Step2eParameterRangesJson()
|
||||||
|
{
|
||||||
|
using FParameters = VoxelForgeRedefinedDensityField::FGenerationParameters;
|
||||||
|
struct FParameterRange
|
||||||
|
{
|
||||||
|
const TCHAR* Name;
|
||||||
|
float FParameters::*Value;
|
||||||
|
};
|
||||||
|
static const FParameterRange Fields[] = {
|
||||||
|
{TEXT("room_pitch_voxels"), &FParameters::RoomPitchVoxels},
|
||||||
|
{TEXT("room_radius_fraction_min"), &FParameters::MinimumRoomRadiusFraction},
|
||||||
|
{TEXT("room_radius_fraction_max"), &FParameters::MaximumRoomRadiusFraction},
|
||||||
|
{TEXT("room_height_voxels"), &FParameters::RoomHeightVoxels},
|
||||||
|
{TEXT("floor_relief_voxels"), &FParameters::FloorReliefVoxels},
|
||||||
|
{TEXT("tunnel_radius_voxels"), &FParameters::TunnelRadiusVoxels},
|
||||||
|
{TEXT("tunnel_half_height_voxels"), &FParameters::TunnelHalfHeightVoxels},
|
||||||
|
{TEXT("loop_probability"), &FParameters::LoopProbability},
|
||||||
|
{TEXT("vertical_shaft_probability"), &FParameters::VerticalShaftProbability},
|
||||||
|
{TEXT("shaft_radius_voxels"), &FParameters::ShaftRadiusVoxels},
|
||||||
|
{TEXT("pillar_probability"), &FParameters::PillarProbability},
|
||||||
|
{TEXT("ledge_probability"), &FParameters::LedgeProbability},
|
||||||
|
{TEXT("floating_mass_probability"), &FParameters::FloatingMassProbability},
|
||||||
|
{TEXT("stalactite_stalagmite_probability"), &FParameters::SpireProbability},
|
||||||
|
{TEXT("basin_probability"), &FParameters::BasinProbability},
|
||||||
|
{TEXT("basin_depth_voxels"), &FParameters::BasinDepthVoxels},
|
||||||
|
{TEXT("water_level_fraction"), &FParameters::WaterLevelFraction},
|
||||||
|
};
|
||||||
|
|
||||||
|
TSharedRef<FJsonObject> Result = MakeShared<FJsonObject>();
|
||||||
|
for (const FParameterRange& Field : Fields)
|
||||||
|
{
|
||||||
|
float Minimum = FLT_MAX;
|
||||||
|
float Maximum = -FLT_MAX;
|
||||||
|
for (int32 ProfileIndex = 0;
|
||||||
|
ProfileIndex < VoxelForgeRedefinedDensityField::GetParameterSetCount();
|
||||||
|
++ProfileIndex)
|
||||||
|
{
|
||||||
|
const TCHAR* Name = nullptr;
|
||||||
|
FParameters Parameters;
|
||||||
|
if (!VoxelForgeRedefinedDensityField::GetParameterSetInfo(
|
||||||
|
ProfileIndex, Name, Parameters))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float Value = Parameters.*(Field.Value);
|
||||||
|
Minimum = FMath::Min(Minimum, Value);
|
||||||
|
Maximum = FMath::Max(Maximum, Value);
|
||||||
|
}
|
||||||
|
TSharedRef<FJsonObject> Bounds = MakeShared<FJsonObject>();
|
||||||
|
Bounds->SetNumberField(TEXT("minimum_across_profiles"), Minimum);
|
||||||
|
Bounds->SetNumberField(TEXT("maximum_across_profiles"), Maximum);
|
||||||
|
Result->SetObjectField(Field.Name, Bounds);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Step2eSameWorkerRun(
|
||||||
|
const VoxelForgeRegionEval::FTiming& A,
|
||||||
|
const VoxelForgeRegionEval::FTiming& B)
|
||||||
|
{
|
||||||
|
return A.QuantizedHash == B.QuantizedHash && A.RawFloatHash == B.RawFloatHash;
|
||||||
|
}
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Step2dTimingJson(const VoxelForgeRegionEval::FTiming& Timing)
|
TSharedRef<FJsonObject> Step2dTimingJson(const VoxelForgeRegionEval::FTiming& Timing)
|
||||||
{
|
{
|
||||||
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
|
||||||
@@ -3653,6 +3870,8 @@ int32 RunStep2e(const FString& Params)
|
|||||||
Row->SetNumberField(TEXT("profile_index"), Profile);
|
Row->SetNumberField(TEXT("profile_index"), Profile);
|
||||||
Row->SetStringField(TEXT("name"), ProfileName);
|
Row->SetStringField(TEXT("name"), ProfileName);
|
||||||
Row->SetObjectField(TEXT("parameters"), Step2eParametersJson(ProfileParameters));
|
Row->SetObjectField(TEXT("parameters"), Step2eParametersJson(ProfileParameters));
|
||||||
|
Row->SetObjectField(TEXT("nominal_chamber_volume_quantiles_m3"),
|
||||||
|
Step2eChamberVolumeQuantilesJson(ProfileParameters));
|
||||||
Row->SetNumberField(TEXT("six_worker_ring_median_ms"), MedianMs);
|
Row->SetNumberField(TEXT("six_worker_ring_median_ms"), MedianMs);
|
||||||
TArray<TSharedPtr<FJsonValue>> TrialValues;
|
TArray<TSharedPtr<FJsonValue>> TrialValues;
|
||||||
TrialValues.Add(MakeShared<FJsonValueNumber>(Times[0]));
|
TrialValues.Add(MakeShared<FJsonValueNumber>(Times[0]));
|
||||||
@@ -3664,6 +3883,11 @@ int32 RunStep2e(const FString& Params)
|
|||||||
Row->SetNumberField(TEXT("estimated_surface_area_per_volume_m_inv"),
|
Row->SetNumberField(TEXT("estimated_surface_area_per_volume_m_inv"),
|
||||||
Variety.SurfaceAreaPerVolume);
|
Variety.SurfaceAreaPerVolume);
|
||||||
Row->SetNumberField(TEXT("vertical_air_adjacency_share"), Variety.VerticalAdjacencyShare);
|
Row->SetNumberField(TEXT("vertical_air_adjacency_share"), Variety.VerticalAdjacencyShare);
|
||||||
|
Row->SetNumberField(TEXT("vertical_air_column_share"), Variety.VerticalAirColumnShare);
|
||||||
|
Row->SetNumberField(TEXT("mean_longest_vertical_air_run_voxels"),
|
||||||
|
Variety.MeanLongestVerticalAirRunVoxels);
|
||||||
|
Row->SetNumberField(TEXT("longest_vertical_air_run_voxels"),
|
||||||
|
Variety.LongestVerticalAirRunVoxels);
|
||||||
Row->SetNumberField(TEXT("one_meter_tunnel_neck_share"), Variety.TunnelNeckShare);
|
Row->SetNumberField(TEXT("one_meter_tunnel_neck_share"), Variety.TunnelNeckShare);
|
||||||
Row->SetNumberField(TEXT("one_meter_connected_components"),
|
Row->SetNumberField(TEXT("one_meter_connected_components"),
|
||||||
Variety.ConnectedComponentsAtOneMeter);
|
Variety.ConnectedComponentsAtOneMeter);
|
||||||
@@ -3675,6 +3899,17 @@ int32 RunStep2e(const FString& Params)
|
|||||||
Row->SetNumberField(TEXT("skipped_bricks"), static_cast<double>(LastTiming.SkippedBricks));
|
Row->SetNumberField(TEXT("skipped_bricks"), static_cast<double>(LastTiming.SkippedBricks));
|
||||||
Row->SetNumberField(TEXT("skipped_sample_fraction"), LastTiming.SampleCount > 0
|
Row->SetNumberField(TEXT("skipped_sample_fraction"), LastTiming.SampleCount > 0
|
||||||
? static_cast<double>(LastTiming.SkippedSamples) / LastTiming.SampleCount : 0.0);
|
? static_cast<double>(LastTiming.SkippedSamples) / LastTiming.SampleCount : 0.0);
|
||||||
|
Row->SetNumberField(TEXT("evaluated_samples"),
|
||||||
|
static_cast<double>(LastTiming.EvaluatedSamples));
|
||||||
|
Row->SetNumberField(TEXT("worker_cpu_seconds"), LastTiming.WorkerCpuSeconds);
|
||||||
|
Row->SetNumberField(TEXT("brick_classification_worker_ms"),
|
||||||
|
LastTiming.BrickClassificationSeconds * 1000.0);
|
||||||
|
Row->SetNumberField(TEXT("density_evaluation_worker_ms"),
|
||||||
|
LastTiming.DensityEvaluationSeconds * 1000.0);
|
||||||
|
Row->SetNumberField(TEXT("uniform_fill_worker_ms"),
|
||||||
|
LastTiming.UniformFillSeconds * 1000.0);
|
||||||
|
Row->SetNumberField(TEXT("longest_worker_ms"),
|
||||||
|
LastTiming.LongestWorkerWallSeconds * 1000.0);
|
||||||
|
|
||||||
FString SafeName(ProfileName);
|
FString SafeName(ProfileName);
|
||||||
SafeName.ToLowerInline();
|
SafeName.ToLowerInline();
|
||||||
@@ -3778,26 +4013,41 @@ int32 RunStep2e(const FString& Params)
|
|||||||
const FStep2dBoundaryStats BoundaryStats = ComputeStep2dBoundaryStats(
|
const FStep2dBoundaryStats BoundaryStats = ComputeStep2dBoundaryStats(
|
||||||
HardestFullDensity, Dimension, Origin,
|
HardestFullDensity, Dimension, Origin,
|
||||||
FMath::RoundToInt(HardestParameters.RoomPitchVoxels));
|
FMath::RoundToInt(HardestParameters.RoomPitchVoxels));
|
||||||
|
TArray<float> SeamFailureDensity = HardestFullDensity;
|
||||||
|
int64 DeliberateSeamSamplesMutated = 0;
|
||||||
|
for (int32 Z = 1; Z < Dimension - 1; ++Z)
|
||||||
|
for (int32 Y = 1; Y < Dimension - 1; ++Y)
|
||||||
|
for (int32 X = 1; X < Dimension - 1; ++X)
|
||||||
|
{
|
||||||
|
const int32 Index = (Z * Dimension + Y) * Dimension + X;
|
||||||
|
if (((Origin.X + X) % 8) == 0 && FMath::Abs(HardestFullDensity[Index]) <= 12.0f)
|
||||||
|
{
|
||||||
|
SeamFailureDensity[Index + 1] += 64.0f;
|
||||||
|
++DeliberateSeamSamplesMutated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const FStep2dBoundaryStats SeamFailureStats = ComputeStep2dBoundaryStats(
|
||||||
|
SeamFailureDensity, Dimension, Origin,
|
||||||
|
FMath::RoundToInt(HardestParameters.RoomPitchVoxels));
|
||||||
const FStep2dBrickProofAudit ProofAudit = AuditStep2dBrickProofs(
|
const FStep2dBrickProofAudit ProofAudit = AuditStep2dBrickProofs(
|
||||||
*World.Generator, Origin, Dimension, true);
|
*World.Generator, Origin, Dimension, true);
|
||||||
const uint64 HardestHash = VoxelForgeRegionEval::HashQuantized(HardestFullDensity);
|
const uint64 HardestHash = VoxelForgeRegionEval::HashQuantized(HardestFullDensity);
|
||||||
const uint64 RepeatHash = VoxelForgeRegionEval::HashQuantized(RepeatFullDensity);
|
const uint64 RepeatHash = VoxelForgeRegionEval::HashQuantized(RepeatFullDensity);
|
||||||
const uint64 OneWorkerHash = VoxelForgeRegionEval::HashQuantized(OneWorkerDensity);
|
const uint64 OneWorkerHash = VoxelForgeRegionEval::HashQuantized(OneWorkerDensity);
|
||||||
const bool bDeterminism = HardestHash == RepeatHash && HardestHash == OneWorkerHash
|
const bool bDeterminism = HardestHash == RepeatHash && HardestHash == OneWorkerHash
|
||||||
&& HardestFullTiming.RawFloatHash == RepeatTiming.RawFloatHash
|
&& Step2eSameWorkerRun(HardestFullTiming, RepeatTiming)
|
||||||
&& HardestFullTiming.RawFloatHash == OneWorkerTiming.RawFloatHash;
|
&& Step2eSameWorkerRun(HardestFullTiming, OneWorkerTiming);
|
||||||
|
VoxelForgeRegionEval::FTiming DeliberateMismatch = HardestFullTiming;
|
||||||
|
DeliberateMismatch.QuantizedHash ^= 1u;
|
||||||
|
const bool bDeliberateDeterminismMismatchCaught =
|
||||||
|
!Step2eSameWorkerRun(HardestFullTiming, DeliberateMismatch);
|
||||||
const bool bDetailAtLeastLive = NewSpectrum.RMSLag1 >= OldSpectrum.RMSLag1
|
const bool bDetailAtLeastLive = NewSpectrum.RMSLag1 >= OldSpectrum.RMSLag1
|
||||||
&& NewSpectrum.RMSLag2 >= OldSpectrum.RMSLag2;
|
&& NewSpectrum.RMSLag2 >= OldSpectrum.RMSLag2;
|
||||||
const bool bSmoothingControlCaught = SmoothSpectrum.RMSLag1 < NewSpectrum.RMSLag1 * 0.80
|
const bool bSmoothingControlCaught = SmoothSpectrum.RMSLag1 < NewSpectrum.RMSLag1 * 0.80
|
||||||
|| SmoothSpectrum.RMSLag2 < NewSpectrum.RMSLag2 * 0.80;
|
|| SmoothSpectrum.RMSLag2 < NewSpectrum.RMSLag2 * 0.80;
|
||||||
const bool bBoundaryPass = BoundaryStats.BrickBoundarySamples > 0
|
const bool bBoundaryPass = Step2eBoundaryStatsPass(BoundaryStats);
|
||||||
&& BoundaryStats.InteriorSamples > 0
|
const bool bDeliberateSeamFailureCaught = DeliberateSeamSamplesMutated > 0
|
||||||
&& BoundaryStats.ChunkBoundarySamples > 0
|
&& !Step2eBoundaryStatsPass(SeamFailureStats);
|
||||||
&& BoundaryStats.FeatureCellBoundarySamples > 0
|
|
||||||
&& BoundaryStats.BrickJumpRms <= BoundaryStats.InteriorJumpRms * 2.0 + 0.25
|
|
||||||
&& BoundaryStats.ChunkBoundaryJumpRms <= BoundaryStats.InteriorJumpRms * 2.0 + 0.25
|
|
||||||
&& BoundaryStats.FeatureCellJumpRms
|
|
||||||
<= BoundaryStats.FeatureCellInteriorJumpRms * 2.0 + 0.25;
|
|
||||||
const bool bBoundAudit = ProofAudit.CorrectlySkippedBricksAudited > 0
|
const bool bBoundAudit = ProofAudit.CorrectlySkippedBricksAudited > 0
|
||||||
&& ProofAudit.CorrectProofSamplesChecked > 0
|
&& ProofAudit.CorrectProofSamplesChecked > 0
|
||||||
&& ProofAudit.CorrectProofViolations == 0;
|
&& ProofAudit.CorrectProofViolations == 0;
|
||||||
@@ -3810,6 +4060,7 @@ int32 RunStep2e(const FString& Params)
|
|||||||
const bool bSpeedPass = Workers == 6 && bProfilePasses && WorstMedianMs <= 600.0;
|
const bool bSpeedPass = Workers == 6 && bProfilePasses && WorstMedianMs <= 600.0;
|
||||||
const bool bPassed = bSpeedPass && bDeterminism && bDetailAtLeastLive
|
const bool bPassed = bSpeedPass && bDeterminism && bDetailAtLeastLive
|
||||||
&& bSmoothingControlCaught && bDetailParity && bBoundaryPass
|
&& bSmoothingControlCaught && bDetailParity && bBoundaryPass
|
||||||
|
&& bDeliberateSeamFailureCaught && bDeliberateDeterminismMismatchCaught
|
||||||
&& bBoundAudit && bUndersizedBoundCaught
|
&& bBoundAudit && bUndersizedBoundCaught
|
||||||
&& HardestFullTiming.NonFiniteSamples == 0;
|
&& HardestFullTiming.NonFiniteSamples == 0;
|
||||||
|
|
||||||
@@ -3832,13 +4083,19 @@ int32 RunStep2e(const FString& Params)
|
|||||||
"rock masses and a bowl floor with an explicit water level. Passage pads and anchor "
|
"rock masses and a bowl floor with an explicit water level. Passage pads and anchor "
|
||||||
"tunnels join the authored inter-strate route to the generated network."));
|
"tunnels join the authored inter-strate route to the generated network."));
|
||||||
Report->SetStringField(TEXT("parameter_space"),
|
Report->SetStringField(TEXT("parameter_space"),
|
||||||
TEXT("Eight named profiles can be assigned per strate from a seed hash (-1 mode), or "
|
TEXT("Eight named profiles can be assigned per strate from a stable seed hash (-1 mode), "
|
||||||
"forced for measurement. Each profile rolls cell placement and feature choices from "
|
"or forced for measurement. Each profile supplies nominal room, tunnel, shaft, "
|
||||||
"the world seed and strate index; see parameters and documented ranges in the report."));
|
"feature-probability and basin values. Per-cell hashes deterministically roll room "
|
||||||
|
"jitter and feature presence. Profile minima and maxima are recorded below; room "
|
||||||
|
"height is clamped to the strate span, room radii to 0.20-0.72/0.80 of pitch, "
|
||||||
|
"loop probability to 0-0.8, probabilities and water level to 0-1, and basin depth "
|
||||||
|
"to 0-48 voxels."));
|
||||||
|
Report->SetObjectField(TEXT("parameter_ranges_across_eight_profiles"),
|
||||||
|
Step2eParameterRangesJson());
|
||||||
Report->SetStringField(TEXT("resolution_contract"),
|
Report->SetStringField(TEXT("resolution_contract"),
|
||||||
TEXT("One exact field sample per 25 cm lattice point. The four existing 8/4/2/1-sample "
|
TEXT("One exact field sample per 25 cm lattice point. The four existing 8/4/2/1-sample "
|
||||||
"detail bands are evaluated for every potentially surface-affecting point; no coarse "
|
"detail bands are evaluated for every potentially surface-affecting point; no coarse "
|
||||||
"field is interpolated onto the lattice. 8-cubed skips require the final macro field "
|
"field is interpolated onto the lattice. 4-cubed step 2e skips require the final macro field "
|
||||||
"Lipschitz interval plus the full 5.25-unit detail supremum and marching-cubes halo."));
|
"Lipschitz interval plus the full 5.25-unit detail supremum and marching-cubes halo."));
|
||||||
Report->SetStringField(TEXT("finer_lattice_scaling"),
|
Report->SetStringField(TEXT("finer_lattice_scaling"),
|
||||||
TEXT("For 12.5 cm voxels, double room pitch, room height, tunnel/feature dimensions and "
|
TEXT("For 12.5 cm voxels, double room pitch, room height, tunnel/feature dimensions and "
|
||||||
@@ -3848,9 +4105,11 @@ int32 RunStep2e(const FString& Params)
|
|||||||
"remain cheap. This scale has not been timed."));
|
"remain cheap. This scale has not been timed."));
|
||||||
Report->SetStringField(TEXT("variety_metric_method"),
|
Report->SetStringField(TEXT("variety_metric_method"),
|
||||||
TEXT("Open fraction uses every ring sample. Surface area estimates sign-changing lattice "
|
TEXT("Open fraction uses every ring sample. Surface area estimates sign-changing lattice "
|
||||||
"edges times 0.25 m squared. Chamber-size bins, connected components and tunnel-neck "
|
"edges times 0.25 m squared. Nominal chamber-volume p10/p50/p90 values use the "
|
||||||
"share use a 1 m downsampled six-neighbor occupancy grid; verticality is the share of "
|
"uniform per-cell radius roll and room height as circular-cylinder volumes. Tunnel-neck "
|
||||||
"open 1-cell adjacencies that point vertically."));
|
"share and connected-component sizes use a 1 m downsampled six-neighbor occupancy grid. "
|
||||||
|
"Verticality is the mean longest contiguous open run per XY column, with open-column "
|
||||||
|
"coverage reported separately."));
|
||||||
Report->SetStringField(TEXT("water_geometry_limit"),
|
Report->SetStringField(TEXT("water_geometry_limit"),
|
||||||
TEXT("Basin profiles generate the bowl floor and water-level parameter; this density field "
|
TEXT("Basin profiles generate the bowl floor and water-level parameter; this density field "
|
||||||
"does not render or simulate water."));
|
"does not render or simulate water."));
|
||||||
@@ -3884,6 +4143,10 @@ int32 RunStep2e(const FString& Params)
|
|||||||
Boundary->SetNumberField(TEXT("feature_cell_boundary_gradient_jump_rms"), BoundaryStats.FeatureCellJumpRms);
|
Boundary->SetNumberField(TEXT("feature_cell_boundary_gradient_jump_rms"), BoundaryStats.FeatureCellJumpRms);
|
||||||
Boundary->SetNumberField(TEXT("feature_cell_interior_gradient_jump_rms"), BoundaryStats.FeatureCellInteriorJumpRms);
|
Boundary->SetNumberField(TEXT("feature_cell_interior_gradient_jump_rms"), BoundaryStats.FeatureCellInteriorJumpRms);
|
||||||
Boundary->SetBoolField(TEXT("boundary_artifact_check_pass"), bBoundaryPass);
|
Boundary->SetBoolField(TEXT("boundary_artifact_check_pass"), bBoundaryPass);
|
||||||
|
Boundary->SetNumberField(TEXT("deliberate_seam_samples_mutated"),
|
||||||
|
static_cast<double>(DeliberateSeamSamplesMutated));
|
||||||
|
Boundary->SetBoolField(TEXT("deliberate_seam_failure_caught"),
|
||||||
|
bDeliberateSeamFailureCaught);
|
||||||
Report->SetObjectField(TEXT("boundary_artifact_check"), Boundary);
|
Report->SetObjectField(TEXT("boundary_artifact_check"), Boundary);
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Proofs = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> Proofs = MakeShared<FJsonObject>();
|
||||||
@@ -3893,6 +4156,32 @@ int32 RunStep2e(const FString& Params)
|
|||||||
static_cast<double>(ProofAudit.CorrectProofSamplesChecked));
|
static_cast<double>(ProofAudit.CorrectProofSamplesChecked));
|
||||||
Proofs->SetNumberField(TEXT("correct_proof_sign_violations"),
|
Proofs->SetNumberField(TEXT("correct_proof_sign_violations"),
|
||||||
static_cast<double>(ProofAudit.CorrectProofViolations));
|
static_cast<double>(ProofAudit.CorrectProofViolations));
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_x"), ProofAudit.FirstViolationBrickOrigin.X);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_y"), ProofAudit.FirstViolationBrickOrigin.Y);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_z"), ProofAudit.FirstViolationBrickOrigin.Z);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_size_x"), ProofAudit.FirstViolationBrickSize.X);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_size_y"), ProofAudit.FirstViolationBrickSize.Y);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_brick_size_z"), ProofAudit.FirstViolationBrickSize.Z);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_sample_x"), ProofAudit.FirstViolationSample.X);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_sample_y"), ProofAudit.FirstViolationSample.Y);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_sample_z"), ProofAudit.FirstViolationSample.Z);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_density"), ProofAudit.FirstViolationDensity);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_center_macro"),
|
||||||
|
ProofAudit.FirstViolationCenterMacro);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_sample_macro"),
|
||||||
|
ProofAudit.FirstViolationSampleMacro);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_sample_detail"),
|
||||||
|
ProofAudit.FirstViolationSampleDetail);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_macro_delta_per_voxel"),
|
||||||
|
ProofAudit.FirstViolationMacroDeltaPerVoxel);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_path_max_gradient"),
|
||||||
|
ProofAudit.FirstViolationPathMaxGradient);
|
||||||
|
Proofs->SetNumberField(TEXT("first_violation_tiny_step_max_gradient"),
|
||||||
|
ProofAudit.FirstViolationTinyStepMaxGradient);
|
||||||
|
Proofs->SetBoolField(TEXT("first_violation_inside_proven_brick"),
|
||||||
|
ProofAudit.bFirstViolationWasInsideBrick);
|
||||||
|
Proofs->SetBoolField(TEXT("first_violation_claimed_air"),
|
||||||
|
ProofAudit.bFirstViolationClaimedAir);
|
||||||
Proofs->SetNumberField(TEXT("undersized_bound_claims_checked"),
|
Proofs->SetNumberField(TEXT("undersized_bound_claims_checked"),
|
||||||
static_cast<double>(ProofAudit.DeliberatelyUndersizedBoundClaimsChecked));
|
static_cast<double>(ProofAudit.DeliberatelyUndersizedBoundClaimsChecked));
|
||||||
Proofs->SetNumberField(TEXT("wrong_sign_samples_caught_by_undersized_bound"),
|
Proofs->SetNumberField(TEXT("wrong_sign_samples_caught_by_undersized_bound"),
|
||||||
@@ -3915,6 +4204,8 @@ int32 RunStep2e(const FString& Params)
|
|||||||
Determinism->SetStringField(TEXT("one_worker_raw_float"), FString::Printf(
|
Determinism->SetStringField(TEXT("one_worker_raw_float"), FString::Printf(
|
||||||
TEXT("%016llx"), static_cast<unsigned long long>(OneWorkerTiming.RawFloatHash)));
|
TEXT("%016llx"), static_cast<unsigned long long>(OneWorkerTiming.RawFloatHash)));
|
||||||
Determinism->SetBoolField(TEXT("same_across_two_runs_and_1_vs_6_workers"), bDeterminism);
|
Determinism->SetBoolField(TEXT("same_across_two_runs_and_1_vs_6_workers"), bDeterminism);
|
||||||
|
Determinism->SetBoolField(TEXT("deliberate_quantized_hash_mismatch_rejected"),
|
||||||
|
bDeliberateDeterminismMismatchCaught);
|
||||||
Report->SetObjectField(TEXT("determinism"), Determinism);
|
Report->SetObjectField(TEXT("determinism"), Determinism);
|
||||||
Report->SetBoolField(TEXT("entrance_exit_walkability_test_added"), true);
|
Report->SetBoolField(TEXT("entrance_exit_walkability_test_added"), true);
|
||||||
Report->SetBoolField(TEXT("inter_strate_passage_open_space_test_added"), true);
|
Report->SetBoolField(TEXT("inter_strate_passage_open_space_test_added"), true);
|
||||||
|
|||||||
@@ -181,27 +181,30 @@ namespace VoxelForgeRegionEval
|
|||||||
TArray<FResearchBrick> Bricks;
|
TArray<FResearchBrick> Bricks;
|
||||||
const FIntVector Last = OriginVoxels
|
const FIntVector Last = OriginVoxels
|
||||||
+ FIntVector(Dimension - 1, Dimension - 1, Dimension - 1);
|
+ FIntVector(Dimension - 1, Dimension - 1, Dimension - 1);
|
||||||
|
const FIntVector ProofBrickSize = bParameterized
|
||||||
|
? FIntVector(4, 4, 4) : FIntVector(8, 8, 8);
|
||||||
const FIntVector FirstBrick(
|
const FIntVector FirstBrick(
|
||||||
FMath::FloorToInt(static_cast<float>(OriginVoxels.X) / 8.0f),
|
FMath::FloorToInt(static_cast<float>(OriginVoxels.X) / ProofBrickSize.X),
|
||||||
FMath::FloorToInt(static_cast<float>(OriginVoxels.Y) / 8.0f),
|
FMath::FloorToInt(static_cast<float>(OriginVoxels.Y) / ProofBrickSize.Y),
|
||||||
FMath::FloorToInt(static_cast<float>(OriginVoxels.Z) / 8.0f));
|
FMath::FloorToInt(static_cast<float>(OriginVoxels.Z) / ProofBrickSize.Z));
|
||||||
const FIntVector LastBrick(
|
const FIntVector LastBrick(
|
||||||
FMath::FloorToInt(static_cast<float>(Last.X) / 8.0f),
|
FMath::FloorToInt(static_cast<float>(Last.X) / ProofBrickSize.X),
|
||||||
FMath::FloorToInt(static_cast<float>(Last.Y) / 8.0f),
|
FMath::FloorToInt(static_cast<float>(Last.Y) / ProofBrickSize.Y),
|
||||||
FMath::FloorToInt(static_cast<float>(Last.Z) / 8.0f));
|
FMath::FloorToInt(static_cast<float>(Last.Z) / ProofBrickSize.Z));
|
||||||
Bricks.Reserve((LastBrick.X - FirstBrick.X + 1)
|
Bricks.Reserve((LastBrick.X - FirstBrick.X + 1)
|
||||||
* (LastBrick.Y - FirstBrick.Y + 1) * (LastBrick.Z - FirstBrick.Z + 1));
|
* (LastBrick.Y - FirstBrick.Y + 1) * (LastBrick.Z - FirstBrick.Z + 1));
|
||||||
for (int32 BZ = FirstBrick.Z; BZ <= LastBrick.Z; ++BZ)
|
for (int32 BZ = FirstBrick.Z; BZ <= LastBrick.Z; ++BZ)
|
||||||
for (int32 BY = FirstBrick.Y; BY <= LastBrick.Y; ++BY)
|
for (int32 BY = FirstBrick.Y; BY <= LastBrick.Y; ++BY)
|
||||||
for (int32 BX = FirstBrick.X; BX <= LastBrick.X; ++BX)
|
for (int32 BX = FirstBrick.X; BX <= LastBrick.X; ++BX)
|
||||||
{
|
{
|
||||||
const FIntVector BrickWorldMin(BX * 8, BY * 8, BZ * 8);
|
const FIntVector BrickWorldMin(
|
||||||
|
BX * ProofBrickSize.X, BY * ProofBrickSize.Y, BZ * ProofBrickSize.Z);
|
||||||
FResearchBrick& Brick = Bricks.AddDefaulted_GetRef();
|
FResearchBrick& Brick = Bricks.AddDefaulted_GetRef();
|
||||||
Brick.Origin = FIntVector(
|
Brick.Origin = FIntVector(
|
||||||
FMath::Max(OriginVoxels.X, BrickWorldMin.X),
|
FMath::Max(OriginVoxels.X, BrickWorldMin.X),
|
||||||
FMath::Max(OriginVoxels.Y, BrickWorldMin.Y),
|
FMath::Max(OriginVoxels.Y, BrickWorldMin.Y),
|
||||||
FMath::Max(OriginVoxels.Z, BrickWorldMin.Z));
|
FMath::Max(OriginVoxels.Z, BrickWorldMin.Z));
|
||||||
const FIntVector BrickEnd = BrickWorldMin + FIntVector(8, 8, 8);
|
const FIntVector BrickEnd = BrickWorldMin + ProofBrickSize;
|
||||||
const FIntVector RingEnd = OriginVoxels
|
const FIntVector RingEnd = OriginVoxels
|
||||||
+ FIntVector(Dimension, Dimension, Dimension);
|
+ FIntVector(Dimension, Dimension, Dimension);
|
||||||
const FIntVector End(
|
const FIntVector End(
|
||||||
@@ -315,28 +318,62 @@ namespace VoxelForgeRegionEval
|
|||||||
VoxelForgeRedefinedDensityField::BuildParameterizedBrickContext(
|
VoxelForgeRedefinedDensityField::BuildParameterizedBrickContext(
|
||||||
Generator, Brick.Origin, Brick.Size, ParameterizedBrickContext);
|
Generator, Brick.Origin, Brick.Size, ParameterizedBrickContext);
|
||||||
}
|
}
|
||||||
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
|
if (bParameterized)
|
||||||
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
|
|
||||||
for (int32 X = 0; X < Brick.Size.X; ++X)
|
|
||||||
{
|
{
|
||||||
const int32 WorldX = Brick.Origin.X + X;
|
const int32 DetailStride = Brick.Size.X * Brick.Size.Y;
|
||||||
const int32 WorldY = Brick.Origin.Y + Y;
|
float ColumnValues[8] = {};
|
||||||
const int32 WorldZ = Brick.Origin.Z + Z;
|
float ParameterizedBrickValues[8 * 8 * 8];
|
||||||
const int64 LatticeIndex = LinearIndex(
|
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
|
||||||
Brick.Lattice.X + X, Brick.Lattice.Y + Y,
|
for (int32 X = 0; X < Brick.Size.X; ++X)
|
||||||
Brick.Lattice.Z + Z, Dimension);
|
{
|
||||||
const float DetailValue = BrickDetail[
|
const int32 DetailBase = Y * Brick.Size.X + X;
|
||||||
(Z * Brick.Size.Y + Y) * Brick.Size.X + X];
|
VoxelForgeRedefinedDensityField::EvaluateParameterizedColumnWithDetailValues(
|
||||||
OutDensities[static_cast<int32>(LatticeIndex)] = bParameterized
|
Generator, static_cast<float>(Brick.Origin.X + X),
|
||||||
? VoxelForgeRedefinedDensityField::EvaluateParameterizedWithDetailValue(
|
static_cast<float>(Brick.Origin.Y + Y),
|
||||||
Generator, static_cast<float>(WorldX), static_cast<float>(WorldY),
|
static_cast<float>(Brick.Origin.Z),
|
||||||
static_cast<float>(WorldZ), DetailValue, nullptr, DetailScale,
|
BrickDetail.GetData() + DetailBase, DetailStride,
|
||||||
&ParameterizedBrickContext)
|
Brick.Size.Z, ColumnValues,
|
||||||
: VoxelForgeRedefinedDensityField::EvaluateWithDetailValue(
|
&ParameterizedBrickContext, DetailScale);
|
||||||
Generator, static_cast<float>(WorldX), static_cast<float>(WorldY),
|
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
|
||||||
static_cast<float>(WorldZ), DetailValue,
|
{
|
||||||
nullptr, DetailScale, &BrickContext);
|
ParameterizedBrickValues[(Z * Brick.Size.Y + Y)
|
||||||
++WorkerEvaluated[WorkerIndex];
|
* Brick.Size.X + X] = ColumnValues[Z];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
|
||||||
|
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
|
||||||
|
{
|
||||||
|
const int64 LatticeIndex = LinearIndex(
|
||||||
|
Brick.Lattice.X, Brick.Lattice.Y + Y,
|
||||||
|
Brick.Lattice.Z + Z, Dimension);
|
||||||
|
const int32 LocalIndex = (Z * Brick.Size.Y + Y) * Brick.Size.X;
|
||||||
|
FMemory::Memcpy(OutDensities.GetData() + LatticeIndex,
|
||||||
|
ParameterizedBrickValues + LocalIndex,
|
||||||
|
static_cast<SIZE_T>(Brick.Size.X) * sizeof(float));
|
||||||
|
}
|
||||||
|
WorkerEvaluated[WorkerIndex] += static_cast<uint64>(Brick.SampleCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int32 Z = 0; Z < Brick.Size.Z; ++Z)
|
||||||
|
for (int32 Y = 0; Y < Brick.Size.Y; ++Y)
|
||||||
|
for (int32 X = 0; X < Brick.Size.X; ++X)
|
||||||
|
{
|
||||||
|
const int32 WorldX = Brick.Origin.X + X;
|
||||||
|
const int32 WorldY = Brick.Origin.Y + Y;
|
||||||
|
const int32 WorldZ = Brick.Origin.Z + Z;
|
||||||
|
const int64 LatticeIndex = LinearIndex(
|
||||||
|
Brick.Lattice.X + X, Brick.Lattice.Y + Y,
|
||||||
|
Brick.Lattice.Z + Z, Dimension);
|
||||||
|
const float DetailValue = BrickDetail[
|
||||||
|
(Z * Brick.Size.Y + Y) * Brick.Size.X + X];
|
||||||
|
OutDensities[static_cast<int32>(LatticeIndex)] =
|
||||||
|
VoxelForgeRedefinedDensityField::EvaluateWithDetailValue(
|
||||||
|
Generator, static_cast<float>(WorldX), static_cast<float>(WorldY),
|
||||||
|
static_cast<float>(WorldZ), DetailValue,
|
||||||
|
nullptr, DetailScale, &BrickContext);
|
||||||
|
++WorkerEvaluated[WorkerIndex];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WorkerEvaluate[WorkerIndex] += FPlatformTime::Seconds() - EvaluationStart;
|
WorkerEvaluate[WorkerIndex] += FPlatformTime::Seconds() - EvaluationStart;
|
||||||
}
|
}
|
||||||
|
|||||||