@woosh/meep-engine 3.60.4 → 3.60.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2621 -0
- package/CONTRIBUTING.md +7 -0
- package/MIGRATION_2_TO_3.md +136 -0
- package/SECURITY.md +4 -0
- package/editor/EditorCameraNavigation.d.ts +2 -1
- package/editor/EditorCameraNavigation.d.ts.map +1 -1
- package/editor/EditorCameraNavigation.js +51 -57
- package/package.json +6 -2
- package/src/engine/EngineHarness.d.ts +3 -9
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +6 -8
- package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
- package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
- package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
- package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
- package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
- package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
- package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
- package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
- package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
- package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
- package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/Water.js +8 -0
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +731 -734
- package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
- package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
- package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
- package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
- package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
- package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
- package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
- package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
- package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
- package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
- package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
- package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
- package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
- package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
- package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
- package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
- package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
- package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
- package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
- package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
- package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
- package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
- package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
- package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/water_refraction/README.md +5 -6
- package/src/shade/playground/water_refraction/index.html +1 -1
- package/src/shade/renderer/Renderer.d.ts +11 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +50 -6
- package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
- package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
- package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
- package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
- package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
- package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
- package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
- package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
- package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
- package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
- package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
- package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
- package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
- package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
- package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
- package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
- package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
- package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
- package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
- package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +22 -13
- package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water_avboit.js +7 -7
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
- package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
- package/editor/REWORK_PLAN_2026_08.md +0 -692
- package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
- package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
- package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
- package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
- package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
- package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
- package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
- package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
- package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
- package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
- package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
- package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
- package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
- package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
- package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
- package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
- package/src/REVIEW_2026_08_06/adv-core.md +0 -511
- package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
- package/src/REVIEW_2026_08_06/adv-view.md +0 -446
- package/src/REVIEW_2026_08_06/api-core.md +0 -296
- package/src/REVIEW_2026_08_06/api-engine.md +0 -195
- package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
- package/src/REVIEW_2026_08_06/core-binary.md +0 -348
- package/src/REVIEW_2026_08_06/core-collection.md +0 -376
- package/src/REVIEW_2026_08_06/core-math.md +0 -221
- package/src/REVIEW_2026_08_06/core-process.md +0 -266
- package/src/REVIEW_2026_08_06/core-science.md +0 -223
- package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
- package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
- package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
- package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
- package/src/REVIEW_2026_08_06/engine-input.md +0 -197
- package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
- package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
- package/src/REVIEW_2026_08_06/generation.md +0 -176
- package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
- package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
- package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
- package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
- package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
- package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
- package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
- package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
- package/src/REVIEW_2026_08_06/view.md +0 -667
- package/src/REVIEW_2026_08_06.md +0 -610
- package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
- package/src/core/bvh2/bvh3/NOTES.md +0 -2
- package/src/core/bvh8/NOTES.md +0 -63
- package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
- package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
- package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
- package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
- package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
- package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
- package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
- package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
- package/src/core/geom/3d/gjk/NOTES.md +0 -8
- package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
- package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
- package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
- package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
- package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
- package/src/engine/REVIEW_2026_07_03.md +0 -211
- package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
- package/src/engine/control/first-person/DESIGN.md +0 -658
- package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
- package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
- package/src/engine/control/first-person/TODO.md +0 -160
- package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
- package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
- package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
- package/src/engine/ecs/ik/PLAN.md +0 -179
- package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
- package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
- package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
- package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
- package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
- package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
- package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
- package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
- package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
- package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
- package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
- package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
- package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
- package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
- package/src/engine/network/CONGESTION_CONTROL.md +0 -87
- package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
- package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
- package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
- package/src/engine/physics/cloth/PLAN.md +0 -3056
- package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
- package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
- package/src/engine/physics/fluid/solver/NOTES.md +0 -46
- package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
- package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
- package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
- package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
- package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
- package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
- package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
- package/src/format/image/avif/DECISIONS.md +0 -545
- package/src/format/image/jpeg/NOTES.md +0 -3
- package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
- package/src/generation/COORDINATES.md +0 -54
- package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
- package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
- package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
- package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
- package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
- package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
- package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
- package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
- package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
- package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
- package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
- package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
- package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
- package/src/shade/RENDERER_CONTRACT.md +0 -697
- package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
- package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
- package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
- package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
- package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
- package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
- package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
- package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
- package/src/shade/renderer/NOTES.md +0 -78
- package/src/shade/renderer/PLAN.md +0 -8
- package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
- package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
- package/src/shade/renderer/atmosphere/NOTES.md +0 -6
- package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
- package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
- package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
- package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
- package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
- package/src/shade/renderer/camera/orbital/README.md +0 -81
- package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
- package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
- package/src/shade/renderer/camera/orbital/index.js +0 -9
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
- package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
- package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
- package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
- package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
- package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
- package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
- package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
- package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
- package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
- package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
- package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
- package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
- package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
- package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
- package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
- package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
- package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
- package/src/shade/renderer/hiz/NOTES.md +0 -3
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
- package/src/shade/renderer/light/cluster/NOTES.md +0 -11
- package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
- package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
- package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
- package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
- package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
- package/src/shade/renderer/particles/DESIGN.md +0 -1011
- package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
- package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
- package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
- package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
- package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
- package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
- package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
- package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
- package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
- package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
- package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
- package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
- package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
- package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
- package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
- package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
- package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
- package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
- package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
- package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
- package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
- package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
- package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
- package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
- package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
- package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
- package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
- package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
- package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
- package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
- package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
- package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
- package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
- package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
- package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
- package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
- package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
- package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
- package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
- package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
- package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
- package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
- package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
- package/src/shade/wgsl/NOTES.md +0 -4
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
# Plan — Ray-traced reflection IR (probe-baked geometry reverb)
|
|
2
|
-
|
|
3
|
-
> The keystone upgrade: replace `bakeReverb`'s single-hit mean-free-path heuristic with a true
|
|
4
|
-
> ray-traced, time-binned, **per-band** reflection IR, reusing the engine's Monte-Carlo path tracer.
|
|
5
|
-
> Closes the Steam-Audio *reflections* gap (early reflections + room timbre), replaces the hand-tuned
|
|
6
|
-
> `DECAY_PER_METRE` constant with measured per-band RT60, and makes `scattering` / `absorption[3]` live
|
|
7
|
-
> data.
|
|
8
|
-
>
|
|
9
|
-
> **Status (2026-06-20): COMPLETE — the keystone is LANDED + committed + green.** The foundation
|
|
10
|
-
> (**P1a/P1b** shape-raycast index, the **§0.5** `RowFirstTable`/`CSRGraph`/BVH data structures, the **P4
|
|
11
|
-
> TLAS**) and now the reflection-IR bake itself — **P1c → P2 → P3** — are all in. `bakeReverb`'s single-hit
|
|
12
|
-
> heuristic + `DECAY_PER_METRE` are gone; reverb RT60 is now *measured* per band from multi-bounce ray
|
|
13
|
-
> tracing, validated against an analytic Sabine box, and rendered as a per-band decaying-noise IR.
|
|
14
|
-
>
|
|
15
|
-
> **One deviation from this plan, for correctness:** the trace terminates by ENERGY THRESHOLD, **not**
|
|
16
|
-
> Russian roulette (§1 step 5 / §4 said RR). Fixed-probability RR is the wrong estimator for acoustic
|
|
17
|
-
> reflectance — a survivor at bounce *n* carries energy `(1−α)^n` but is scaled by `2^n`, so for a live
|
|
18
|
-
> room (`1−α > ½`) the survivor weight grows as `(2(1−α))^n` and rare deep survivors swamp exactly the
|
|
19
|
-
> late bins the RT60 slope is fitted to. Deterministic decay-to-floor is unbiased for the fit window and
|
|
20
|
-
> far lower variance.
|
|
21
|
-
|
|
22
|
-
The structural blueprint is **`engine/graphics/sh3/lpv/LightProbeVolumeBaker.js`** + its
|
|
23
|
-
`PathTracerProbeRenderer` — a near-1:1 analogue (probe-volume baking against scene geometry via the path
|
|
24
|
-
tracer). We mirror its baker ↔ probe-renderer split and `TaskGroup` orchestration; we swap the
|
|
25
|
-
accumulator from SH-of-radiance to **energy-over-time per band**.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 0. What is baked vs. runtime — the source-agnostic guarantee (answers the dynamic-sources question)
|
|
30
|
-
|
|
31
|
-
**The bake NEVER encodes sound sources. It encodes SPACE: (a) per-region reverberation profile and
|
|
32
|
-
(b) region connectivity.** Sources are 100% runtime. There is no restriction to static/fixed sources.
|
|
33
|
-
|
|
34
|
-
| Concern | Baked? | What's baked | Source / geometry dynamics |
|
|
35
|
-
|---|---|---|---|
|
|
36
|
-
| Direct path: occlusion, transmission, air, distance | **never** — real-time ray-trace every frame against the live `AcousticOccluderIndex` | nothing | **sources AND moving occluders fully dynamic** |
|
|
37
|
-
| Reverb (reflection IR / per-band RT60) | yes, per **probe** | the SPACE's reverberation response at that point (room geometry + materials), source-agnostic | **sources fully dynamic** — any source routes into the reverb selected by the **listener's** position; geometry assumed mostly-static |
|
|
38
|
-
| Pathing (corner-leakage) | yes | inter-probe **visibility graph** (the space's connectivity), source-agnostic | **sources fully dynamic** — the path source↔listener is solved at runtime from live positions; geometry static-assumed (+ live recheck below) |
|
|
39
|
-
|
|
40
|
-
**Why reverb is source-agnostic** — "reverb = reflections with the source at the listener." The
|
|
41
|
-
late/diffuse reverberant field of a room is approximately uniform and a property of the room (volume +
|
|
42
|
-
surface absorption), not of where the source is. So one **listener-centric** reverb per probe serves
|
|
43
|
-
every source in that room: `ProbeReverbRenderer` already selects by the *listener's* nearest probe, and
|
|
44
|
-
all sources send into that one shared reverb bus. A source can move anywhere — it never indexes the bake.
|
|
45
|
-
|
|
46
|
-
**Early reflections are the one source-position-dependent part.** The per-probe envelope bakes them
|
|
47
|
-
listener-centric (correct when source ≈ listener; and when the source is far, the position-independent
|
|
48
|
-
late tail dominates anyway). True per-source early reflections would be a separate real-time pass —
|
|
49
|
-
deferred; the direct-path occlusion machinery already does per-source real-time work, and the late tail
|
|
50
|
-
is the dominant reverb cue.
|
|
51
|
-
|
|
52
|
-
**Moving objects (dynamic geometry):**
|
|
53
|
-
- **Occlusion / transmission — fully live.** The occluder index is dynamic (O(1) `setTransform`), so a
|
|
54
|
-
closing door / moving platform correctly blocks the *direct* path in real-time. No bake involved.
|
|
55
|
-
- **Baked reverb + baked visibility — encode bake-time geometry.** A mover that changes acoustic
|
|
56
|
-
*topology* (a door sealing a room) is not in the bake. Policy, in order of cost:
|
|
57
|
-
1. Most reverb-affecting geometry is static (walls/floors); small movers barely shift RT60 → accept.
|
|
58
|
-
2. **Pathing live recheck** (cheap, from the review): re-verify the chosen exit edge with a single
|
|
59
|
-
`anyHit` ray each frame against live geometry — a closed door re-blocks the leak instantly even
|
|
60
|
-
though the baked graph still has the edge. One ray per pathed source.
|
|
61
|
-
3. **Opt-in door variants** for big dynamic dividers (vault door, portcullis gating a whole area's
|
|
62
|
-
reverb): bake open/closed variants for the affected probes and blend on door state (Steam Audio's
|
|
63
|
-
"dynamic geometry" approach) — per set-piece, not the default.
|
|
64
|
-
4. **Re-bake affected probes** on major static-set changes (level streaming) — offline, rare.
|
|
65
|
-
|
|
66
|
-
This is the standard **real-time-direct / baked-indirect** split (Steam Audio's exact model): live where
|
|
67
|
-
source + geometry move, baked where it is expensive and mostly-static, with targeted live rechecks for
|
|
68
|
-
the dynamic cases that matter.
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## 0.5 Foundation data structures (owner-directed, resolved)
|
|
73
|
-
|
|
74
|
-
These replace the v1 POJO/array structures across the existing + new probe code with the engine's
|
|
75
|
-
binary-backed primitives.
|
|
76
|
-
|
|
77
|
-
1. **ProbeField store → `RowFirstTable`** (`core/collection/table/`), **not** `BinaryElementPool`. Probes
|
|
78
|
-
are baked **write-once** and read by integer row index, so a fixed-schema columnar binary table fits
|
|
79
|
-
exactly: one allocation, cache-friendly, no per-probe JS object. (`BinaryElementPool`'s alloc/free
|
|
80
|
-
pool semantics are for churny dynamic elements — unneeded here.) Schema via `RowFirstTableSpec`:
|
|
81
|
-
`x, y, z` (f32) · `reverbDecayLow/Mid/High` (f32, widened from the v1 scalar) · `bvhLeaf` (u32). The
|
|
82
|
-
`AcousticProbe` class becomes a thin row cursor/accessor (or is dropped for row-index access).
|
|
83
|
-
|
|
84
|
-
2. **Pathing connectivity → `CSRGraph`** (`core/graph/csr/`), replacing `AcousticPathGraph.#adjacency`
|
|
85
|
-
(array-of-arrays). Baked once ⇒ CSR is the ideal static-graph form — `edge_addresses` (row pointers) +
|
|
86
|
-
`adjacency` + `edge_weights` in one buffer, with the cache-friendly `for (k=xadj[v]; k<xadj[v+1]; k++)`
|
|
87
|
-
walk that `computeExitField`/Dijkstra want. `edge_weights` is **`Float32Array`** (owner-updated — its
|
|
88
|
-
doc now cites "acoustic coupling"), so path distances go in **directly**, no quantization.
|
|
89
|
-
`bakeVisibility` builds it two-pass (count degrees → prefix-sum `edge_addresses` → fill) or via
|
|
90
|
-
`CSRGraph.fromArrays`.
|
|
91
|
-
|
|
92
|
-
3. **Probe nearest → BVH + `bvh_query_user_data_nearest_to_point`** (`core/bvh2/bvh3/query/`), replacing
|
|
93
|
-
`ProbeField.nearest`'s linear scan. `ProbeField` builds a `BVH` of probe point-AABBs (leaf `user_data`
|
|
94
|
-
= row index) once after baking (the `SpatialAudioIndex` precedent); `nearest(x,y,z)` = one query →
|
|
95
|
-
row index, O(log n). This matters under the bake (`bakeVisibility` is O(probes²) nearest-style work)
|
|
96
|
-
and per-frame (`computeExitField` snaps listener + every pathed source to a probe).
|
|
97
|
-
|
|
98
|
-
4. **`AcousticOccluderIndex` body → class** (replacing the `#bodies` POJO): a real `OccluderBody` holding
|
|
99
|
-
`shape, material, matrix, inverse, localAABB, worldAABB` (the triangle `blas/indices/positions` of this
|
|
100
|
-
v1 sketch are gone — §0.6 below raycasts the `shape` directly, so only meshes carry an internal BLAS).
|
|
101
|
-
`matrix` (the **forward** world transform) maps the local hit position + normal back to world space.
|
|
102
|
-
|
|
103
|
-
5. **`body.inverse` mandatory — no `null` polymorphism.** `addBody`'s matrix defaults to `M4_IDENTITY`
|
|
104
|
-
and the inverse is **always** computed; `#localizeRay` always transforms (drop the `inverse === null`
|
|
105
|
-
fast-path). Uniform flow per [[feedback_uniform_flow]]. Production cost is nil — real occluder bodies
|
|
106
|
-
always carry a `Transform` matrix anyway; the identity fast-path was a test-only convenience.
|
|
107
|
-
|
|
108
|
-
**Landing:** (4)+(5)+the stored forward matrix = the foundation of **P1a/P1b**. (1)+(3) = part of the
|
|
109
|
-
**P2** probe refactor (the probe schema widens for per-band decay there regardless). (2) = a pathing
|
|
110
|
-
refactor that can ride with P2 or land standalone first.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 0.6 Raycast shapes directly — drop the triangulation (owner-directed)
|
|
115
|
-
|
|
116
|
-
The v1 `acoustic_geometry_from_shape` triangulates collider shapes (box → 12 tris, …) into mesh soup —
|
|
117
|
-
counter-productive: lossy for primitives, more triangles, a per-body BLAS for a 2-tri wall. **Replace it
|
|
118
|
-
with a first-class `AbstractShape3D.raycast`**, so the occluder index stores **shapes** and raycasts them
|
|
119
|
-
exactly (closed-form for primitives, an internal BLAS only for meshes).
|
|
120
|
-
|
|
121
|
-
**Contract:** `AbstractShape3D.raycast(hit: Float32Array, ray: Ray3) → boolean`, shape at its LOCAL
|
|
122
|
-
origin (the caller localises the ray), `hit = [px, py, pz, nx, ny, nz]` (local surface point + unit
|
|
123
|
-
normal). The hit distance `t` is recovered by the caller as `(hitPoint − origin)·dir` (unit dir).
|
|
124
|
-
|
|
125
|
-
**It is mostly glue** — the narrowphase already factored the local math into core functions that
|
|
126
|
-
`refine_ray_hit` dispatches to:
|
|
127
|
-
- `SphereShape3D` → `core/geom/3d/sphere/sphere_raycast.js`
|
|
128
|
-
- `BoxShape3D` → `core/geom/3d/box/box3_raycast.js`
|
|
129
|
-
- `CapsuleShape3D` → `core/geom/3d/capsule/capsule_raycast.js`
|
|
130
|
-
- `MeshShape3D` → an **internal lazy ebvh BLAS** (`ebvh_build_for_geometry_morton` +
|
|
131
|
-
`ebvh_geometry_query_nearest_triangle_ray` + `construct_ray_hit_from_geometry`); the normal is
|
|
132
|
-
normalised and flipped to face the incoming ray. (Owner-approved: MeshShape3D gains an internal BLAS.)
|
|
133
|
-
|
|
134
|
-
`AcousticOccluderIndex` then holds `shape + material + matrix + inverse` per body; `closestHit`/`anyHit`
|
|
135
|
-
localise the world ray into body space and call `shape.raycast`, transforming the hit point (by the
|
|
136
|
-
forward matrix) and normal (by the rotation) back to world. **`acoustic_geometry_from_shape` is deleted**;
|
|
137
|
-
`AcousticBody`/`AcousticSimulationSystem` pass the `Collider.shape` straight through. (Could later let
|
|
138
|
-
the physics `refine_ray_concave` share `MeshShape3D.raycast` — out of scope.)
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## 1. Model — acoustic ray-tracing energy histogram
|
|
143
|
-
|
|
144
|
-
From a probe (source = listener), shoot N rays over the sphere. Each ray carries a **per-band energy
|
|
145
|
-
throughput** `[low, mid, high]`, init `1`. Bounce loop (modeled on `PathTracer.path_trace`):
|
|
146
|
-
|
|
147
|
-
1. `index.closestHit` → `t`, world hit position + **normal** (P1a).
|
|
148
|
-
2. `pathLength += t`; deposit current energy into `histogram[band][bin]`, `bin = floor(pathLength / c / binSeconds)` (`c` = speed of sound).
|
|
149
|
-
3. fold absorption: `energy[band] *= (1 − material.absorption[band])`.
|
|
150
|
-
4. scatter: with prob `material.scattering` → diffuse (`getBiasedNormalSample`, cosine lobe about the normal); else specular (reflect direction about the normal).
|
|
151
|
-
5. `shiftForward(SELF_OCCLUSION_OFFSET · max(1,|origin|))`; Russian-roulette terminate (unbiased survivor scaling) after `min_bounce`.
|
|
152
|
-
6. miss (escaped to open sky) → stop.
|
|
153
|
-
|
|
154
|
-
Per probe: the per-band histogram (the **reflectogram**) → **per-band RT60** (decay slope, via Schroeder
|
|
155
|
-
integration) + the early bins (room signature). This is the classic CATT/ODEON statistical method, and
|
|
156
|
-
the same energy model Steam Audio's baked reflections use.
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## 2. Phases
|
|
161
|
-
|
|
162
|
-
**P1 — Foundation (geometry-only tests).**
|
|
163
|
-
- **✓ LANDED — P1a — `AbstractShape3D.raycast(hit, ray)`** (§0.6) on Sphere / Box / Capsule / Mesh — glue over the
|
|
164
|
-
narrowphase `*_raycast` core functions + an internal mesh BLAS. Engine-wide, generally useful, purely
|
|
165
|
-
additive to the shape classes. Test: known ray-vs-sphere/box/capsule/mesh hits (position + normal) and
|
|
166
|
-
misses, in the shape's local frame.
|
|
167
|
-
- **✓ LANDED — P1b — `OccluderBody` class + occluder-index refactor to shapes** (§0.5 (4)(5), §0.6). Bodies hold
|
|
168
|
-
`shape + material + matrix + inverse` (inverse mandatory, identity default); `closestHit`/`anyHit`
|
|
169
|
-
localise the ray + `shape.raycast`, transform hit point (forward matrix) + normal (rotation) to world,
|
|
170
|
-
recover `t` for cross-body ordering; world-AABB broadphase from `shape.compute_bounding_box`. **Delete
|
|
171
|
-
`acoustic_geometry_from_shape`**; `AcousticBody`/`AcousticSimulationSystem` pass `Collider.shape`
|
|
172
|
-
through; `RayHit` gains world position + normal. Update the dependent specs (they currently feed
|
|
173
|
-
triangle soup). Test: occlusion/ray behaviour unchanged on shape colliders; hit normal correct.
|
|
174
|
-
- **✓ LANDED — P1c — scatter + offset primitives**: `v3_reflect` (core, new) for the specular bounce;
|
|
175
|
-
the cosine-diffuse scatter reuses `getBiasedNormalSample` and the magnitude-scaled self-occlusion offset
|
|
176
|
-
reuses `Ray3.shiftForward` directly (both already existed — no wrappers needed). Tested: reflection law
|
|
177
|
-
(angle in = angle out, parallel-to-surface unchanged, unit-length preserved).
|
|
178
|
-
|
|
179
|
-
**✓ LANDED — P2 — Bake core (no WebAudio).** `acoustic_trace_energy` (one ray's multi-bounce per-band
|
|
180
|
-
deposit into a time-binned echogram — energy-threshold termination, not RR; see the deviation note up
|
|
181
|
-
top) + `echogram_band_rt60` (Schroeder + ISO 3382 T30 slope) + `bakeReverbBands` (N rays → per-band
|
|
182
|
-
RT60); `AcousticProbe` widened to `reverbDecay[3]` (scalar kept as the derived mean) + `ProbeField`
|
|
183
|
-
table widened. **Sabine box gate passes** (baked cube RT60 ≈ 0.161·V/(S·α)). `bakeReverb` deleted.
|
|
184
|
-
- `acoustic_trace_energy(index, origin, dir, …, histogram)` — one ray's multi-bounce energy deposit
|
|
185
|
-
(allocation-free, seeded).
|
|
186
|
-
- `ReflectionProbeRenderer.bake(pos, probe)` — N rays → per-band histogram → per-band RT60 + early
|
|
187
|
-
envelope (mirrors `PathTracerProbeRenderer.bake`).
|
|
188
|
-
- `AcousticReverbBaker.bake(probeField, ecd)` → `TaskGroup` (chunked over probes via `countTask`, like the
|
|
189
|
-
LPV baker; logs ms/probe).
|
|
190
|
-
- **Widen `AcousticProbe`**: `reverbDecaySeconds` scalar → `reverbDecay[3]` (per-band) + optionally a short
|
|
191
|
-
early-reflection envelope; **keep the scalar derived from the bands** so the existing
|
|
192
|
-
`reverbImpulseResponse` / `ProbeReverbRenderer` path stays valid as a regression gate until the new path
|
|
193
|
-
is proven. Update `toJSON`/`fromJSON` + `bakeProbeField`.
|
|
194
|
-
- **Validation gate — analytic Sabine box:** a closed box with known absorption has a known
|
|
195
|
-
RT60 (`0.161·V/(S·α)`); assert the baked late-slope matches within tolerance. Plus: per-band absorption
|
|
196
|
-
→ per-band RT60 differs; open scene → ~no tail.
|
|
197
|
-
|
|
198
|
-
**✓ LANDED — P3 — Render upgrade.**
|
|
199
|
-
- `reverbImpulseResponse` shapes **per-band** decaying noise from `reverbDecay[3]` (each band's tail =
|
|
200
|
-
its RT60), summed → a geometry-derived IR with room *timbre*. `ProbeReverbRenderer` consumes the
|
|
201
|
-
widened probe. Test (`MockAudioContext`): IR band content reflects the per-band decays; crossfade still
|
|
202
|
-
click-safe.
|
|
203
|
-
|
|
204
|
-
**P4 — Optional, measure-first (not the keystone).**
|
|
205
|
-
- NEE-to-source (deposit `source→wall→listener` paths for a cleaner early-reflection IR at lower ray
|
|
206
|
-
count) — only if random-bounce variance is shown to be a problem.
|
|
207
|
-
- **✓ LANDED — Body-level TLAS** over `AcousticOccluderIndex` — a dynamic BVH over the bodies' world AABBs,
|
|
208
|
-
gather via `bvh_query_user_data_ray_segment` (leaf user-data = handle, `BvhClient` refit on
|
|
209
|
-
`setTransform`). Landed early on owner request rather than waiting on the bake bench; `closestHit` /
|
|
210
|
-
`anyHit` are now O(log n + hits).
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 3. Reuse map
|
|
215
|
-
|
|
216
|
-
| Lifted **verbatim** (engine primitives) | Adapted / new (acoustic) |
|
|
217
|
-
|---|---|
|
|
218
|
-
| `getBiasedNormalSample` (cosine scatter), `construct_ray_hit_from_geometry` (hit normal), `random_point_on_sphere`, `Ray3.shiftForward` + scale-aware offset, the RR survivor-scaling pattern, `TaskGroup`/`countTask`, the baker ↔ probe-renderer split | the bounce loop (energy-time histogram vs radiance/SH), absorption-throughput fold, specular/diffuse split by `scattering`, Schroeder → RT60 reduction, per-band IR shaping |
|
|
219
|
-
|
|
220
|
-
Keep the binary **`ebvh`** as the BLAS leaf (do not fork `BufferedGeometryBVH`'s inlined raycast). **Skip
|
|
221
|
-
BVH8** (no CPU traversal kernel; lost to `ebvh` for 2-tri walls).
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
## 4. Key decisions
|
|
226
|
-
|
|
227
|
-
- **Dx — source-agnostic space bake (see §0).** The bake = per-region reverb profile + connectivity;
|
|
228
|
-
sources are fully runtime; reverb is selected by the *listener*; pathing is solved at runtime. Moving
|
|
229
|
-
geometry is live for occlusion, static-assumed for baked indirect, with a live path-edge `anyHit`
|
|
230
|
-
recheck + opt-in door variants. **No restriction to static sources, ever.**
|
|
231
|
-
- **Statistical (energy-histogram) reverb**, one shared listener-centric IR per probe — affordable for
|
|
232
|
-
WebAudio; not per-source convolution.
|
|
233
|
-
- **Per-band throughout** (collapsing to a scalar is the regression we are fixing).
|
|
234
|
-
- **Unbiased & leak-free**: RR survivor scaling is mandatory; the scale-aware self-occlusion offset is
|
|
235
|
-
mandatory (a fixed epsilon silently leaks energy through walls at large world coords).
|
|
236
|
-
- **Back-compat scalar path kept as the regression gate** until the per-band path validates against
|
|
237
|
-
Sabine — *correctness-first, no bandaid*.
|
|
238
|
-
- **Skip wetness/humidity** (owner-agreed) and the wet-JCA physics.
|
|
239
|
-
|
|
240
|
-
---
|
|
241
|
-
|
|
242
|
-
## 5. Testing
|
|
243
|
-
|
|
244
|
-
Core (`core/` + `probe/`) is WebAudio-free → geometry-only tests, no audio mock. The Sabine box is the
|
|
245
|
-
correctness gate for P2. The render (P3) uses `MockAudioContext`. Bench the bake ray cost before any
|
|
246
|
-
TLAS. Run from the repo root: `npx jest --config jest.conf.json engine/sound/simulation`.
|
|
247
|
-
|
|
248
|
-
## 6. Risks
|
|
249
|
-
|
|
250
|
-
- **Probe-contract widening** (scalar → per-band) ripples through `AcousticProbe` serialization,
|
|
251
|
-
`bakeProbeField`, `reverbImpulseResponse`, `ProbeReverbRenderer` — hence P2 is the L item. Land P1
|
|
252
|
-
first (both S, self-contained), keep the scalar path behind the new curve.
|
|
253
|
-
- **Bake cost** (rays × bounces × probes) is real but offline; `TaskGroup` chunking keeps it
|
|
254
|
-
non-blocking. Don't reach for the TLAS until the bench says so.
|
|
255
|
-
- **Validation honesty**: trust the bake to replace `DECAY_PER_METRE` only after the Sabine-box RT60
|
|
256
|
-
matches analytics.
|
|
257
|
-
|
|
258
|
-
## 7. Sequence
|
|
259
|
-
|
|
260
|
-
P1a + P1b (S each, zero behavior change) → P2 (bake + Sabine gate) → P3 (render). P4 stays
|
|
261
|
-
measured/optional.
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Topologically-aware probe-visibility graph
|
|
2
|
-
|
|
3
|
-
## The cliff
|
|
4
|
-
|
|
5
|
-
`bakeVisibility` connects every mutually-visible probe pair via an all-pairs `for i, for j<i` loop.
|
|
6
|
-
With no occluders that is the **complete graph** — `n(n-1)/2` edges, O(n²) time *and* memory. A 128³ probe
|
|
7
|
-
field (2,097,152 probes) would try to materialise **2.199e12 edges** → OOM. (Bench:
|
|
8
|
-
`probe/bakeVisibility.bench.spec.js`.)
|
|
9
|
-
|
|
10
|
-
Pruning a distance cutoff into that loop does **not** fix it — it still *enumerates* all pairs (O(n²) time),
|
|
11
|
-
and the scheme is topologically blind. The fix is to never enumerate the complete graph: generate candidate
|
|
12
|
-
edges from the **spatial topology** of the probe cloud, so we only ever touch O(n) of them.
|
|
13
|
-
|
|
14
|
-
This is, in the literature, a **sparse geometric spanner** built like a **sparse roadmap spanner (SPARS2)**:
|
|
15
|
-
a base graph + connectivity bridges + path-quality shortcuts. References that map 1:1 onto the three stages:
|
|
16
|
-
SPARS/SPARS2 (Dobson & Bekris 2014 — names stage B a *"bridge"*, stage C a *"shortcut"*); the greedy
|
|
17
|
-
geometric spanner (Bose et al. — stage C's length test `dist_G(u,v) > t·‖uv‖`); PRM* component-connection
|
|
18
|
-
(stage B). Steam Audio, by contrast, keeps the all-pairs loop and just places **few** probes (5 m floor grid)
|
|
19
|
-
— a placement lever we deliberately treat separately.
|
|
20
|
-
|
|
21
|
-
## Decisions (locked)
|
|
22
|
-
|
|
23
|
-
- **Base = Delaunay, no jitter.** `compute_delaunay_tetrahedral_mesh` on the probe positions. (Grid fields
|
|
24
|
-
have a clean dedicated tessellator, `tetrahedral_mesh_build_from_grid`, but wiring it by grid-structure is
|
|
25
|
-
part of the *placement* workstream — not conflated here.)
|
|
26
|
-
- **Full A + B + C** in this change.
|
|
27
|
-
- **Dense probe fields stay.** This is purely a graph-construction fix; placement is a separate workstream.
|
|
28
|
-
- Caveat we are buying with B+C: **3D Delaunay is not a proven constant-stretch spanner** (2D is, ≤1.998;
|
|
29
|
-
3D has no such bound — Erickson, Xia). So the base graph *can* detour badly and *can* be fragmented by
|
|
30
|
-
walls; B repairs connectivity and C repairs path quality. They are mandatory, not optional.
|
|
31
|
-
|
|
32
|
-
## Stage A — Delaunay base graph (`probe_delaunay_edges.js`)
|
|
33
|
-
|
|
34
|
-
1. Copy probe positions into a packed `[x,y,z]*n`; `compute_delaunay_tetrahedral_mesh(mesh, points, n)`.
|
|
35
|
-
2. Extract the **unique undirected edges** of the live tets — 6 per tet (`getVertexIndex` pairs), deduped
|
|
36
|
-
(materialise the freed-tet skip set once; do **not** call `exists()` per tet — it is O(free)). The tet
|
|
37
|
-
mesh triangulates the convex hull, so this is a single connected graph of **≈6–7·n** edges.
|
|
38
|
-
3. Drop edges that fail `probe_edge_visible(field, index, a, b)`; keep survivors weighted by distance.
|
|
39
|
-
|
|
40
|
-
Result: a sparse, occlusion-respecting base graph. **O(n)** edges, **O(n)** shadow rays. (2.1M probes →
|
|
41
|
-
~13M edges / rays vs 2.2e12 — ~150,000× fewer.) Dropping occluded edges is what fragments the graph into
|
|
42
|
-
**islands** (rooms), which stage B repairs.
|
|
43
|
-
|
|
44
|
-
## Stage B — bridge the islands (`probe_visibility_bridge_components.js`)
|
|
45
|
-
|
|
46
|
-
A door the Delaunay edge happened to miss leaves two acoustically-connected rooms as separate components.
|
|
47
|
-
|
|
48
|
-
1. `uf_init` + `uf_union` over the surviving base edges → connected components (canonical root = min member).
|
|
49
|
-
2. For each probe, **radius-query the probe BVH** (`bvh_query_user_data_intersects_sphere`, radius = k× the
|
|
50
|
-
median base-edge length) for nearby probes in a **different** component; among the **visible** ones keep
|
|
51
|
-
the **shortest** edge per unordered component-pair (the PRM/SPARS bridge heuristic).
|
|
52
|
-
3. Add those bridges, re-`uf_union`, repeat until the component count stops dropping. Genuinely sealed
|
|
53
|
-
regions stay separate (correct — a closed vault should not leak).
|
|
54
|
-
|
|
55
|
-
**O(n · |radius neighbours|)**, no all-pairs. Bridges are the only edges that can exceed the local Delaunay
|
|
56
|
-
length, so they are also the place corner-leak pathing will most want.
|
|
57
|
-
|
|
58
|
-
## Stage C — augment for path quality (`probe_visibility_augment.js`)
|
|
59
|
-
|
|
60
|
-
The Delaunay base routes only through local hops, so a graph path can detour or kink where a clear straight
|
|
61
|
-
line exists. Add a **budgeted fraction** of extra edges (cap ≤ ~30% of base) on two criteria:
|
|
62
|
-
|
|
63
|
-
- **C1 length (greedy spanner).** Candidate chords `(u,v)` from the 2-ring (a shared base neighbour `w`) and
|
|
64
|
-
short BVH-radius pairs. Add iff `(u,v)` is visible **and** `dist_G(u,v) > t·‖uv‖` — the current graph route
|
|
65
|
-
is ≥ t× the straight line. `dist_G` is evaluated with a **distance-bounded Dijkstra capped at `t·‖uv‖`**
|
|
66
|
-
(reuse the heap Dijkstra; stop early once the cap is exceeded), so it is cheap, not a full SSSP per pair.
|
|
67
|
-
- **C2 directionality (diffraction-angle gate).** For a 2-ring kink `u–w–v`, with `d0 = ̂(u−w)`, `d1 = ̂(v−w)`,
|
|
68
|
-
add the chord iff visible **and** `dot(d0, −d1) < X` — the angle at `w` is acute, a sharp corner the sound
|
|
69
|
-
must wrap around. Acoustically a bend is a diffraction point whose HF loss grows with angle (UTD/Maekawa),
|
|
70
|
-
so straightening it is worth an edge even when it barely shortens the route. This is an acoustic heuristic,
|
|
71
|
-
**not** a spanner property — hence the budget cap, so it composes with C1 rather than overrunning it.
|
|
72
|
-
|
|
73
|
-
**O(n · degree²)** candidates from the 2-ring; each gated test is local/bounded. Process shortest-first,
|
|
74
|
-
stop at the budget.
|
|
75
|
-
|
|
76
|
-
## Assembly — `bakeVisibility` rewrite
|
|
77
|
-
|
|
78
|
-
`A (delaunay edges → visible) → B (bridge) → C (augment) → CSRGraph (both half-edges) → field.setVisibilityGraph`.
|
|
79
|
-
The CSR build, the `EDGE_WEIGHT_BLOCKED` runtime recheck, and `findAcousticPath` are unchanged downstream —
|
|
80
|
-
this only changes which edges exist, not their representation. Weights remain inter-probe distance so the
|
|
81
|
-
recheck restores them identically.
|
|
82
|
-
|
|
83
|
-
## New primitives that may be needed
|
|
84
|
-
|
|
85
|
-
- Tet → unique-edge extraction with an O(tets) freed-skip (helper in `probe_delaunay_edges.js`).
|
|
86
|
-
- A median base-edge-length helper to set the stage-B radius and the stage-C candidate radius.
|
|
87
|
-
- (If 2-ring proves insufficient at scale) WSPD candidate pairs — deferred unless measured to be needed.
|
|
88
|
-
|
|
89
|
-
## Test plan
|
|
90
|
-
|
|
91
|
-
- `probe_delaunay_edges.spec.js`: a small grid tetrahedralises to the expected adjacency; coincident/degenerate
|
|
92
|
-
inputs; edge uniqueness.
|
|
93
|
-
- `bakeVisibility.spec.js` (extend): empty scene is now **sparse** (≈O(n), assert ≪ n²) yet still **connected**
|
|
94
|
-
(one component) and every kept edge is visible; a wall fragments then B re-bridges through a gap; the
|
|
95
|
-
existing two-rooms-corridor integration test still passes (reachability + direction + per-band).
|
|
96
|
-
- Re-point `bakeVisibility.bench.spec.js`: the complete-graph assertion becomes a **sparsity + connectivity**
|
|
97
|
-
assertion; the 128³ case should now *complete* (sweep added to confirm ~linear edges/time).
|
|
98
|
-
- Stage C: a deliberate kink (L-shaped corridor with a clear diagonal) gains the shortcut; budget cap honoured.
|
|
99
|
-
|
|
100
|
-
## Open knobs (defaults to pick during implementation, document in code)
|
|
101
|
-
|
|
102
|
-
- stage-B radius multiplier `k` (× median edge length); stage-C stretch `t`; stage-C angle `X`; stage-C budget
|
|
103
|
-
fraction. All bake-time constants with JSDoc rationale (per the project's no-magic / uniform-flow style).
|
|
104
|
-
|
|
105
|
-
## As-built notes (landed)
|
|
106
|
-
|
|
107
|
-
- **Defaults chosen:** stage-B radius `2.5×` median edge length; stage-C stretch `1.3`, kink `dot < −0.5`
|
|
108
|
-
(~corners <60°), budget `0.2×` base edges.
|
|
109
|
-
- **Coplanar degeneracy is handled, not avoided:** a valid 3D Delaunay 1-skeleton is connected, so
|
|
110
|
-
`probe_delaunay_edges` checks connectivity and falls back to the complete graph when the extraction is
|
|
111
|
-
disconnected (a near-coplanar/degenerate field — e.g. the y=0 test scenes). Dense 3D fields never hit it.
|
|
112
|
-
- **Stage B is boundary-driven:** it searches only from the endpoints of dropped (occluded) edges (`sources`),
|
|
113
|
-
not all `n` probes — an interior probe with all-visible neighbours can't be a missed-door near side. An
|
|
114
|
-
empty scene drops nothing, so stage B is a no-op (measured: 10 s → 20 ms at 13.8k probes).
|
|
115
|
-
- **Spatial sort:** `probe_delaunay_edges` Morton-sorts the points before the incremental tetrahedralisation
|
|
116
|
-
(the core's own TODO) and maps tet vertices back through the permutation. ~25% off the build.
|
|
117
|
-
- **Result:** edges are O(n) (measured 6.7–8.0 per probe across 8³–32³, always 1 component); the old all-pairs
|
|
118
|
-
O(n²)/OOM is gone. The 128³ case no longer OOMs and completes.
|
|
119
|
-
- **Remaining bottleneck = the core incremental Delaunay BUILD** (~98% of bake time, super-linear). Follow-ups
|
|
120
|
-
(out of scope here): wire `tetrahedral_mesh_build_from_grid` for grid fields (O(n) — the placement
|
|
121
|
-
workstream), and/or speed up core's Delaunay (BRIO/spatial-sort insertion is its standing TODO).
|