@woosh/meep-engine 3.69.0 → 3.70.0
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 +30 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/bvh8/build/BVH8Converter.d.ts +16 -0
- package/src/core/bvh8/build/BVH8Converter.d.ts.map +1 -1
- package/src/core/bvh8/build/BVH8Converter.js +64 -37
- package/src/core/bvh8/build/bvh8_assign_slots_greedy.d.ts +25 -0
- package/src/core/bvh8/build/bvh8_assign_slots_greedy.d.ts.map +1 -0
- package/src/core/bvh8/build/bvh8_assign_slots_greedy.js +68 -0
- package/src/core/bvh8/build/bvh8_from_proxy.d.ts.map +1 -1
- package/src/core/bvh8/build/bvh8_from_proxy.js +2 -33
- package/src/core/bvh8/build/bvh8_node_fit_slots.d.ts +22 -0
- package/src/core/bvh8/build/bvh8_node_fit_slots.d.ts.map +1 -0
- package/src/core/bvh8/build/bvh8_node_fit_slots.js +115 -0
- package/src/core/bvh8/bvh8_depth.d.ts +8 -0
- package/src/core/bvh8/bvh8_depth.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_depth.js +39 -0
- package/src/core/math/complex/complex_fft_radix2.d.ts +19 -0
- package/src/core/math/complex/complex_fft_radix2.d.ts.map +1 -0
- package/src/core/math/complex/complex_fft_radix2.js +71 -0
- package/src/engine/graphics3/GPUFluidSystem.d.ts +17 -4
- package/src/engine/graphics3/GPUFluidSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUFluidSystem.js +113 -16
- package/src/engine/physics/cloth/playground/wind_main.js +7 -6
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +2 -2
- package/src/engine/physics/cloth/wind/AbstractClothWind.js +2 -2
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +3 -3
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothFluidWind.js +7 -9
- package/src/engine/physics/cloth/wind/ClothGPUFluidWind.d.ts +10 -10
- package/src/engine/physics/cloth/wind/ClothGPUFluidWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothGPUFluidWind.js +14 -22
- package/src/engine/physics/fluid/FluidAtmosphere.d.ts +16 -2
- package/src/engine/physics/fluid/FluidAtmosphere.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidAtmosphere.js +17 -3
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponentSerializationAdapter.d.ts +1 -2
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponentSerializationAdapter.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponentSerializationAdapter.js +1 -2
- package/src/engine/physics/fluid/ecs/FluidEffectorsSystem.d.ts +8 -5
- package/src/engine/physics/fluid/ecs/FluidEffectorsSystem.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidEffectorsSystem.js +60 -17
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +1 -1
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +33 -47
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +38 -176
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationAdapter.d.ts +8 -11
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationAdapter.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationAdapter.js +13 -24
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationUpgrader_0_1.d.ts +16 -0
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/physics/fluid/effector/GlobalFluidEffectorSerializationUpgrader_0_1.js +35 -0
- package/src/engine/physics/fluid/fluid_apply_atmosphere.d.ts +1 -1
- package/src/engine/physics/fluid/fluid_apply_atmosphere.js +1 -1
- package/src/engine/physics/fluid/turbulence/FLUID_TURBULENCE_TILE.d.ts +28 -0
- package/src/engine/physics/fluid/turbulence/FLUID_TURBULENCE_TILE.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/FLUID_TURBULENCE_TILE.js +29 -0
- package/src/engine/physics/fluid/turbulence/fluid_atmosphere_velocity_at.d.ts +16 -0
- package/src/engine/physics/fluid/turbulence/fluid_atmosphere_velocity_at.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/fluid_atmosphere_velocity_at.js +49 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_inverse_tile_size.d.ts +11 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_inverse_tile_size.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_inverse_tile_size.js +18 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_data.d.ts +25 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_data.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_data.js +65 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_generate.d.ts +56 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_generate.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_generate.js +313 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_sample.d.ts +16 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_sample.d.ts.map +1 -0
- package/src/engine/physics/fluid/turbulence/fluid_turbulence_tile_sample.js +69 -0
- package/src/generation/foliage/mesh/branch_ring_triangulate.d.ts +1 -1
- package/src/generation/foliage/mesh/branch_ring_triangulate.js +1 -1
- package/src/shade/playground/bvh_repro/README.md +8 -6
- package/src/shade/playground/bvh_repro/index.html +125 -124
- package/src/shade/playground/bvh_repro/main.js +259 -254
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
- package/src/shade/playground/foliage_wind/foliage_world.js +7 -4
- package/src/shade/playground/grass_surfaces/main.js +3 -2
- package/src/shade/playground/particle_ecs/bonfire_wind.d.ts +23 -13
- package/src/shade/playground/particle_ecs/bonfire_wind.d.ts.map +1 -1
- package/src/shade/playground/particle_ecs/bonfire_wind.js +30 -33
- package/src/shade/playground/skinned_blas_refit/README.md +26 -14
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts +14 -9
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.js +126 -127
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.js +95 -95
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts +9 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.js +146 -135
- package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts +6 -6
- package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.js +148 -134
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.d.ts +11 -8
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.js +342 -202
- package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts +12 -13
- package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.js +136 -116
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts +4 -4
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +255 -249
- package/src/shade/playground/water_surface/main.js +6 -3
- package/src/shade/renderer/animation/GPUAnimationManager.js +2 -2
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +7 -8
- package/src/shade/renderer/fluid/FLUID_FAR_FIELD_STRUCT.d.ts +111 -0
- package/src/shade/renderer/fluid/FLUID_FAR_FIELD_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/fluid/FLUID_FAR_FIELD_STRUCT.js +162 -0
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +37 -8
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascade.js +149 -47
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +10 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +69 -10
- package/src/shade/renderer/fluid/chunk_fluid_far_field.d.ts +19 -0
- package/src/shade/renderer/fluid/chunk_fluid_far_field.d.ts.map +1 -0
- package/src/shade/renderer/fluid/chunk_fluid_far_field.js +43 -0
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_PARENT_STRUCT.d.ts +10 -9
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_PARENT_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_PARENT_STRUCT.js +14 -12
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_RESTRICT_STRUCT.d.ts +3 -2
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_RESTRICT_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/FLUID_CASCADE_RESTRICT_STRUCT.js +7 -5
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_epilogue.d.ts +17 -9
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_epilogue.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_epilogue.js +58 -18
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts +23 -11
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +371 -335
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_fill.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_fill.js +2 -1
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +109 -108
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_restrict.d.ts +5 -3
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_restrict.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_restrict.js +24 -12
- package/src/shade/renderer/fluid/mac/FLUID_MAC_STEP_STRUCT.d.ts +6 -2
- package/src/shade/renderer/fluid/mac/FLUID_MAC_STEP_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/FLUID_MAC_STEP_STRUCT.js +10 -5
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +20 -21
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/FluidMacPasses.js +453 -427
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +2 -1
- package/src/shade/renderer/fluid/publish/FluidWindPublish.d.ts +13 -5
- package/src/shade/renderer/fluid/publish/FluidWindPublish.d.ts.map +1 -1
- package/src/shade/renderer/fluid/publish/FluidWindPublish.js +20 -10
- package/src/shade/renderer/fluid/publish/chunk_fluid_wind_publish_cell.d.ts +2 -2
- package/src/shade/renderer/fluid/publish/chunk_fluid_wind_publish_cell.js +2 -2
- package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts +5 -3
- package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
- package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +147 -142
- package/src/shade/renderer/fluid/query/GPUFluidQueries.js +2 -2
- package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/GPUGeometryManager.js +5 -7
- package/src/shade/renderer/geometry/MeshletGeometry.d.ts +4 -1
- package/src/shade/renderer/geometry/MeshletGeometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/MeshletGeometry.js +4 -1
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.d.ts +20 -0
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.d.ts.map +1 -1
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.js +35 -3
- package/src/shade/renderer/geometry/blas_from_meshlets.d.ts +9 -3
- package/src/shade/renderer/geometry/blas_from_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/blas_from_meshlets.js +16 -30
- package/src/shade/renderer/geometry/bvh/BLAS8_REFIT_TARGET_STRUCT.d.ts +14 -0
- package/src/shade/renderer/geometry/bvh/BLAS8_REFIT_TARGET_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/bvh/BLAS8_REFIT_TARGET_STRUCT.js +33 -0
- package/src/shade/renderer/geometry/bvh/GPUBLASRefitBatch.d.ts +18 -21
- package/src/shade/renderer/geometry/bvh/GPUBLASRefitBatch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUBLASRefitBatch.js +78 -158
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +18 -39
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +39 -398
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +6 -7
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +5 -7
- package/src/shade/renderer/geometry/bvh/bvh8_build_for_meshlets.d.ts +36 -0
- package/src/shade/renderer/geometry/bvh/bvh8_build_for_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/geometry/bvh/bvh8_build_for_meshlets.js +179 -0
- package/src/shade/renderer/geometry/bvh/meshlet_batch_to_clustered_bvh.d.ts +30 -0
- package/src/shade/renderer/geometry/bvh/meshlet_batch_to_clustered_bvh.d.ts.map +1 -0
- package/src/shade/renderer/geometry/bvh/meshlet_batch_to_clustered_bvh.js +207 -0
- package/src/shade/renderer/geometry/bvh/shader_blas8_refit_batch.d.ts +52 -0
- package/src/shade/renderer/geometry/bvh/shader_blas8_refit_batch.d.ts.map +1 -0
- package/src/shade/renderer/geometry/bvh/shader_blas8_refit_batch.js +464 -0
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts +12 -0
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +37 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.js +4 -4
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.js +2 -2
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js +2 -2
- package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.js +4 -4
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.js +2 -2
- package/src/shade/renderer/geometry/sr_create_group_RTX.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sr_create_group_RTX.js +4 -4
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +1 -0
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +1 -0
- package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.js +372 -376
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts +9 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.js +10 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.d.ts +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.js +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.d.ts +12 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.js +109 -60
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_sdf.js +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_surfaces.js +2 -2
- package/src/shade/renderer/gpu_primitive/bvh/BVH_BUFFER_LAYOUT.d.ts +2 -2
- package/src/shade/renderer/gpu_primitive/bvh/BVH_BUFFER_LAYOUT.js +70 -70
- package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.d.ts +6 -7
- package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.js +6 -7
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts +3 -3
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +3 -3
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.js +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts +2 -2
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +3 -3
- package/src/shade/renderer/gpu_primitive/bvh8/BVH8_TREE_BUFFER_LAYOUT.d.ts +69 -0
- package/src/shade/renderer/gpu_primitive/bvh8/BVH8_TREE_BUFFER_LAYOUT.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/BVH8_TREE_BUFFER_LAYOUT.js +89 -0
- package/src/shade/renderer/gpu_primitive/bvh8/bvh8_encode_from_bvh2.d.ts +41 -0
- package/src/shade/renderer/gpu_primitive/bvh8/bvh8_encode_from_bvh2.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/bvh8_encode_from_bvh2.js +348 -0
- package/src/shade/renderer/gpu_primitive/bvh8/check_bvh8_tree.d.ts +34 -0
- package/src/shade/renderer/gpu_primitive/bvh8/check_bvh8_tree.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/check_bvh8_tree.js +291 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_assign.d.ts +31 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_assign.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_assign.js +175 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_depth.d.ts +27 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_depth.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_depth.js +48 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_gather.d.ts +26 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_gather.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_gather.js +118 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_node.d.ts +22 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_node.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_node.js +143 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_sums.d.ts +36 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_sums.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/chunk_bvh8_encode_sums.js +97 -0
- package/src/shade/renderer/gpu_primitive/bvh8/graph_bvh8_encode_from_bvh2.d.ts +49 -0
- package/src/shade/renderer/gpu_primitive/bvh8/graph_bvh8_encode_from_bvh2.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/graph_bvh8_encode_from_bvh2.js +265 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_assign.d.ts +37 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_assign.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_assign.js +109 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count.d.ts +15 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count.js +85 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count_single_workgroup.d.ts +26 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count_single_workgroup.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_count_single_workgroup.js +200 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_parents.d.ts +19 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_parents.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_parents.js +81 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_write.d.ts +14 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_write.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/shader_bvh8_encode_write.js +101 -0
- package/src/shade/renderer/gpu_primitive/bvh8/verify_gpu_bvh8_encode.d.ts +19 -0
- package/src/shade/renderer/gpu_primitive/bvh8/verify_gpu_bvh8_encode.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh8/verify_gpu_bvh8_encode.js +361 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -1
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +5 -6
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +1 -0
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +1 -0
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +1 -0
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +8 -4
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +60 -33
- package/src/shade/renderer/scene/verify_gpu_tlas_build.d.ts +6 -6
- package/src/shade/renderer/scene/verify_gpu_tlas_build.d.ts.map +1 -1
- package/src/shade/renderer/scene/verify_gpu_tlas_build.js +23 -53
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_INODE_STRUCT.d.ts +3 -1
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_INODE_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_INODE_STRUCT.js +5 -3
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_MAX_DEPTH.d.ts +28 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_MAX_DEPTH.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/BVH8_MAX_DEPTH.js +29 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_grid.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_grid.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_grid.js +97 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_intersect.d.ts +8 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_intersect.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_intersect.js +23 -14
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_slot_distances.d.ts +36 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_slot_distances.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_node_slot_distances.js +222 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_direction_rcp.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_direction_rcp.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_direction_rcp.js +30 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_tree_read.d.ts +30 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_tree_read.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_tree_read.js +91 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_waiting_slots.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_waiting_slots.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_waiting_slots.js +40 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_nearest.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_nearest.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_nearest.js +121 -70
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_occluded.d.ts +13 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_occluded.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_blas_occluded.js +117 -61
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest.js +111 -72
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +1 -2
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +83 -54
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_occluded.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_occluded.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_occluded.js +92 -60
- package/src/shade/renderer/shader/chunk/sdf/chunk_point_query_blas_nearest.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_point_query_blas_nearest.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/sdf/chunk_point_query_blas_nearest.js +153 -106
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_point_query_nearest.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_point_query_nearest.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_point_query_nearest.js +115 -74
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.d.ts +5 -2
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.js +89 -63
- package/src/shade/renderer/shader/chunk/sdf/chunk_sdf_query_distance.d.ts +15 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_sdf_query_distance.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/sdf/chunk_sdf_query_distance.js +108 -63
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast.d.ts +14 -0
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast.js +94 -60
- package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.js +4 -4
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +2 -2
- package/src/shade/renderer/water/query/shader_water_surface_query.d.ts.map +1 -1
- package/src/shade/renderer/water/query/shader_water_surface_query.js +227 -227
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +7 -4
- package/src/shade/renderer/water/surface/particles/shader_water_particles.js +2 -2
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +36 -4
- package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +150 -4
- package/src/shade/renderer/wind/WIND_FIELD_STRUCT.d.ts +9 -3
- package/src/shade/renderer/wind/WIND_FIELD_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/wind/WIND_FIELD_STRUCT.js +13 -3
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +6 -6
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +6 -6
- package/src/shade/renderer/wind/chunk_fluid_turbulence.d.ts +39 -0
- package/src/shade/renderer/wind/chunk_fluid_turbulence.d.ts.map +1 -0
- package/src/shade/renderer/wind/chunk_fluid_turbulence.js +63 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +10 -7
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +34 -11
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +2 -2
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +2 -2
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts +6 -4
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
- package/src/shade/renderer/wind/wind_field_add_resources.js +9 -6
- package/src/shade/renderer/geometry/bvh/BLAS_REFIT_TARGET_STRUCT.d.ts +0 -18
- package/src/shade/renderer/geometry/bvh/BLAS_REFIT_TARGET_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/geometry/bvh/BLAS_REFIT_TARGET_STRUCT.js +0 -50
- package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.d.ts +0 -23
- package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.d.ts.map +0 -1
- package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.js +0 -87
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch.d.ts +0 -42
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch.d.ts.map +0 -1
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch.js +0 -141
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch_seed.d.ts +0 -21
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch_seed.d.ts.map +0 -1
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_batch_seed.js +0 -75
- package/src/shade/renderer/geometry/meshlet_batch_to_bvh.d.ts +0 -17
- package/src/shade/renderer/geometry/meshlet_batch_to_bvh.d.ts.map +0 -1
- package/src/shade/renderer/geometry/meshlet_batch_to_bvh.js +0 -247
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_query_blas_occlusion.d.ts +0 -7
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_query_blas_occlusion.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/bvh/bvh8/webgpu/chunk_bvh8_ray_query_blas_occlusion.js +0 -226
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mask_visibility_via_rays.d.ts +0 -8
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mask_visibility_via_rays.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mask_visibility_via_rays.js +0 -45
- package/src/shade/renderer/shader/chunk/light/sample/chunk_ray_sample_light.d.ts +0 -3
- package/src/shade/renderer/shader/chunk/light/sample/chunk_ray_sample_light.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_ray_sample_light.js +0 -105
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_distance.d.ts +0 -6
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_distance.d.ts.map +0 -1
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_distance.js +0 -86
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast_traversal_count.d.ts +0 -2
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast_traversal_count.d.ts.map +0 -1
- package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast_traversal_count.js +0 -136
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { bitCount } from "../../../../core/binary/operations/bitCount.js";
|
|
3
|
+
import { BVH8_SLOT_UNASSIGNED, bvh8_assign_slots_greedy } from "../../../../core/bvh8/build/bvh8_assign_slots_greedy.js";
|
|
4
|
+
import { bvh8_node_fit_slots } from "../../../../core/bvh8/build/bvh8_node_fit_slots.js";
|
|
5
|
+
import { BVH8 } from "../../../../core/bvh8/BVH8.js";
|
|
6
|
+
import {
|
|
7
|
+
BVH_HEADER_WORDS,
|
|
8
|
+
BVH_NODE_BOUNDS_WORD,
|
|
9
|
+
BVH_NODE_CHILD_1_WORD,
|
|
10
|
+
BVH_NODE_CHILD_2_WORD,
|
|
11
|
+
BVH_NODE_STRIDE_WORDS
|
|
12
|
+
} from "../bvh/BVH_BUFFER_LAYOUT.js";
|
|
13
|
+
import {
|
|
14
|
+
BVH8_TREE_BOUNDS_HIGH_WORD,
|
|
15
|
+
BVH8_TREE_BOUNDS_LOW_WORD,
|
|
16
|
+
BVH8_TREE_HEADER_WORDS,
|
|
17
|
+
BVH8_TREE_LEAF_COUNT_WORD,
|
|
18
|
+
BVH8_TREE_NODE_STRIDE_WORDS,
|
|
19
|
+
BVH8_TREE_ORDER_OFFSET_WORD,
|
|
20
|
+
bvh8_tree_buffer_size
|
|
21
|
+
} from "./BVH8_TREE_BUFFER_LAYOUT.js";
|
|
22
|
+
|
|
23
|
+
const BVH_NULL_NODE = 0xFFFFFFFF;
|
|
24
|
+
|
|
25
|
+
const fround = Math.fround;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Binary levels a node of the wide tree stands for.
|
|
29
|
+
* @type {number}
|
|
30
|
+
*/
|
|
31
|
+
export const BVH8_ENCODE_LEVELS = 3;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Encode a binary BVH as a BVH8, three binary levels to a node. The reference for the passes that do
|
|
35
|
+
* it on the GPU: they are held to this, word for word.
|
|
36
|
+
*
|
|
37
|
+
* **Which nodes.** An internal node of the binary tree whose depth is a multiple of three becomes a
|
|
38
|
+
* node of the wide tree; the root is at depth 0. Its children are what lies three levels below it,
|
|
39
|
+
* and the leaves met sooner: at most eight, taken child 1 before child 2 all the way down. One of
|
|
40
|
+
* them that is internal is itself at a depth that is a multiple of three, so it is a node too; one
|
|
41
|
+
* that is a leaf fills a leaf slot. A binary tree that is a single leaf is one node with that leaf
|
|
42
|
+
* in a slot.
|
|
43
|
+
*
|
|
44
|
+
* **Which slots.** A node's children are given its slots by {@link bvh8_assign_slots_greedy}: a
|
|
45
|
+
* child costs a slot the distance its box's centre lies from the node's centre, taken with the
|
|
46
|
+
* slot's signs — the bit of an axis set where the child should lie high on it. The cost is worked
|
|
47
|
+
* in single precision as `(±x + ±y) + ±z`, where an axis's term is the child's `low + high` less the
|
|
48
|
+
* node's. A child whose box is not a number costs nothing a comparison can rank: it takes the lowest
|
|
49
|
+
* slot left once the others have theirs, so that a tree's shape never depends on what its boxes hold.
|
|
50
|
+
*
|
|
51
|
+
* **Where.** Counting a node's child nodes and its leaves, in the order of the binary tree's own
|
|
52
|
+
* node indices: a node's child nodes are the block that starts at one more than the child nodes of
|
|
53
|
+
* every node before it, in slot order; its leaves' payloads are the run that starts at the leaves
|
|
54
|
+
* of every node before it, in slot order. The root is node 0. So a node finds its own place from
|
|
55
|
+
* its parent's block and the slot it has there, with no word from the parent.
|
|
56
|
+
*
|
|
57
|
+
* **Boxes.** A node's box is the binary node's, and its slots are fitted to it by
|
|
58
|
+
* {@link bvh8_node_fit_slots}.
|
|
59
|
+
*
|
|
60
|
+
* @param {Uint32Array} out the BVH8, in the layout of {@link BVH8_TREE_BUFFER_LAYOUT}; at least
|
|
61
|
+
* `bvh8_tree_buffer_size(leaf_count) / 4` words. Words past the tree written are left as they are.
|
|
62
|
+
* @param {Uint32Array} tree the binary tree as u32 words, `[root][node 0][node 1] ...`, in the layout
|
|
63
|
+
* of {@link BVH_BUFFER_LAYOUT}: `2 * leaf_count - 1` nodes, fitted
|
|
64
|
+
* @param {number} leaf_count
|
|
65
|
+
* @returns {number} nodes in the BVH8
|
|
66
|
+
*/
|
|
67
|
+
export function bvh8_encode_from_bvh2(out, tree, leaf_count) {
|
|
68
|
+
assert.isNonNegativeInteger(leaf_count, 'leaf_count');
|
|
69
|
+
assert.greaterThanOrEqual(out.length * Uint32Array.BYTES_PER_ELEMENT, bvh8_tree_buffer_size(leaf_count), 'out is too small for a tree of this many leaves');
|
|
70
|
+
|
|
71
|
+
const out_floats = new Float32Array(out.buffer, out.byteOffset, out.length);
|
|
72
|
+
|
|
73
|
+
if (leaf_count === 0) {
|
|
74
|
+
out.fill(0, 0, BVH8_TREE_HEADER_WORDS + BVH8_TREE_NODE_STRIDE_WORDS);
|
|
75
|
+
|
|
76
|
+
out[BVH8_TREE_ORDER_OFFSET_WORD] = BVH8_TREE_HEADER_WORDS + BVH8_TREE_NODE_STRIDE_WORDS;
|
|
77
|
+
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const binary_count = 2 * leaf_count - 1;
|
|
82
|
+
|
|
83
|
+
assert.greaterThanOrEqual(tree.length, BVH_HEADER_WORDS + binary_count * BVH_NODE_STRIDE_WORDS, 'tree is too short for this many leaves');
|
|
84
|
+
|
|
85
|
+
const tree_floats = new Float32Array(tree.buffer, tree.byteOffset, tree.length);
|
|
86
|
+
|
|
87
|
+
const root = tree[0];
|
|
88
|
+
|
|
89
|
+
const child_1 = node => tree[BVH_HEADER_WORDS + node * BVH_NODE_STRIDE_WORDS + BVH_NODE_CHILD_1_WORD];
|
|
90
|
+
const child_2 = node => tree[BVH_HEADER_WORDS + node * BVH_NODE_STRIDE_WORDS + BVH_NODE_CHILD_2_WORD];
|
|
91
|
+
const is_leaf = node => child_1(node) === BVH_NULL_NODE;
|
|
92
|
+
const bounds_word = node => BVH_HEADER_WORDS + node * BVH_NODE_STRIDE_WORDS + BVH_NODE_BOUNDS_WORD;
|
|
93
|
+
|
|
94
|
+
// ===========
|
|
95
|
+
// Parents, and from them each node's depth
|
|
96
|
+
// ===========
|
|
97
|
+
const parents = new Uint32Array(binary_count).fill(BVH_NULL_NODE);
|
|
98
|
+
|
|
99
|
+
for (let node = 0; node < binary_count; node++) {
|
|
100
|
+
if (!is_leaf(node)) {
|
|
101
|
+
parents[child_1(node)] = node;
|
|
102
|
+
parents[child_2(node)] = node;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const depth_of = node => {
|
|
107
|
+
let depth = 0;
|
|
108
|
+
|
|
109
|
+
for (let at = parents[node]; at !== BVH_NULL_NODE; at = parents[at]) {
|
|
110
|
+
depth++;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return depth;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// an internal node at a depth that is a multiple of three, or a root that is the tree's only leaf
|
|
117
|
+
const is_wide = node => node === root
|
|
118
|
+
|| (!is_leaf(node) && depth_of(node) % BVH8_ENCODE_LEVELS === 0);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The children of a wide node, child 1 before child 2 all the way down.
|
|
122
|
+
*
|
|
123
|
+
* @param {number} node
|
|
124
|
+
* @param {number[]} children output
|
|
125
|
+
* @returns {number} how many
|
|
126
|
+
*/
|
|
127
|
+
function gather(node, children) {
|
|
128
|
+
let count = 0;
|
|
129
|
+
|
|
130
|
+
if (is_leaf(node)) {
|
|
131
|
+
// the tree is this one leaf
|
|
132
|
+
children[count++] = node;
|
|
133
|
+
|
|
134
|
+
return count;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const visit = (at, level) => {
|
|
138
|
+
if (is_leaf(at) || level === BVH8_ENCODE_LEVELS) {
|
|
139
|
+
children[count++] = at;
|
|
140
|
+
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
visit(child_1(at), level + 1);
|
|
145
|
+
visit(child_2(at), level + 1);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
visit(child_1(node), 1);
|
|
149
|
+
visit(child_2(node), 1);
|
|
150
|
+
|
|
151
|
+
return count;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const cost = new Float32Array(64);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The slot each child of a wide node is given.
|
|
158
|
+
*
|
|
159
|
+
* @param {number} node
|
|
160
|
+
* @param {number[]} children
|
|
161
|
+
* @param {number} child_count
|
|
162
|
+
* @param {Uint32Array} slots output, a slot a child
|
|
163
|
+
*/
|
|
164
|
+
function assign(node, children, child_count, slots) {
|
|
165
|
+
const n = bounds_word(node);
|
|
166
|
+
|
|
167
|
+
for (let c = 0; c < child_count; c++) {
|
|
168
|
+
const b = bounds_word(children[c]);
|
|
169
|
+
|
|
170
|
+
const x = fround(fround(tree_floats[b] + tree_floats[b + 3]) - fround(tree_floats[n] + tree_floats[n + 3]));
|
|
171
|
+
const y = fround(fround(tree_floats[b + 1] + tree_floats[b + 4]) - fround(tree_floats[n + 1] + tree_floats[n + 4]));
|
|
172
|
+
const z = fround(fround(tree_floats[b + 2] + tree_floats[b + 5]) - fround(tree_floats[n + 2] + tree_floats[n + 5]));
|
|
173
|
+
|
|
174
|
+
for (let s = 0; s < 8; s++) {
|
|
175
|
+
cost[c * 8 + s] = fround(fround(((s & 4) !== 0 ? -x : x) + ((s & 2) !== 0 ? -y : y)) + ((s & 1) !== 0 ? -z : z));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let filled = bvh8_assign_slots_greedy(slots, cost, child_count);
|
|
180
|
+
|
|
181
|
+
// whoever no cost could rank, in order, into the lowest slots left
|
|
182
|
+
for (let c = 0; c < child_count; c++) {
|
|
183
|
+
if (slots[c] !== BVH8_SLOT_UNASSIGNED) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let slot = 0;
|
|
188
|
+
|
|
189
|
+
while ((filled & (1 << slot)) !== 0) {
|
|
190
|
+
slot++;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
slots[c] = slot;
|
|
194
|
+
filled |= 1 << slot;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ===========
|
|
199
|
+
// Count each wide node's child nodes and leaves, and lay the blocks and runs end to end in the
|
|
200
|
+
// order of the binary tree's node indices
|
|
201
|
+
// ===========
|
|
202
|
+
const child_base = new Uint32Array(binary_count);
|
|
203
|
+
const leaf_base = new Uint32Array(binary_count);
|
|
204
|
+
|
|
205
|
+
const children = new Array(8);
|
|
206
|
+
const slots = new Uint32Array(8);
|
|
207
|
+
|
|
208
|
+
let node_count = 1;
|
|
209
|
+
let leaves_placed = 0;
|
|
210
|
+
|
|
211
|
+
for (let node = 0; node < binary_count; node++) {
|
|
212
|
+
child_base[node] = node_count;
|
|
213
|
+
leaf_base[node] = leaves_placed;
|
|
214
|
+
|
|
215
|
+
if (!is_wide(node)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const child_count = gather(node, children);
|
|
220
|
+
|
|
221
|
+
for (let c = 0; c < child_count; c++) {
|
|
222
|
+
if (is_leaf(children[c])) {
|
|
223
|
+
leaves_placed++;
|
|
224
|
+
} else {
|
|
225
|
+
node_count++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
assert.equal(leaves_placed, leaf_count, 'every leaf is the child of one wide node');
|
|
231
|
+
|
|
232
|
+
const order_offset = BVH8_TREE_HEADER_WORDS + node_count * BVH8_TREE_NODE_STRIDE_WORDS;
|
|
233
|
+
|
|
234
|
+
// ===========
|
|
235
|
+
// Write each wide node at the place its parent's block gives it
|
|
236
|
+
// ===========
|
|
237
|
+
const bvh8 = new BVH8();
|
|
238
|
+
|
|
239
|
+
bvh8.allocate_nodes(node_count);
|
|
240
|
+
|
|
241
|
+
const parent_children = new Array(8);
|
|
242
|
+
const parent_slots = new Uint32Array(8);
|
|
243
|
+
|
|
244
|
+
const slot_boxes = new Float32Array(48);
|
|
245
|
+
|
|
246
|
+
for (let node = 0; node < binary_count; node++) {
|
|
247
|
+
if (!is_wide(node)) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let index = 0;
|
|
252
|
+
|
|
253
|
+
if (node !== root) {
|
|
254
|
+
// three levels up is the wide node this one is a child of; its place there is the block's
|
|
255
|
+
// start and the child nodes in the slots below its own
|
|
256
|
+
const parent = parents[parents[parents[node]]];
|
|
257
|
+
|
|
258
|
+
const sibling_count = gather(parent, parent_children);
|
|
259
|
+
|
|
260
|
+
assign(parent, parent_children, sibling_count, parent_slots);
|
|
261
|
+
|
|
262
|
+
let slot = 0;
|
|
263
|
+
let internal = 0;
|
|
264
|
+
|
|
265
|
+
for (let c = 0; c < sibling_count; c++) {
|
|
266
|
+
if (parent_children[c] === node) {
|
|
267
|
+
slot = parent_slots[c];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (!is_leaf(parent_children[c])) {
|
|
271
|
+
internal |= 1 << parent_slots[c];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
index = child_base[parent] + bitCount(internal & ((1 << slot) - 1));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const child_count = gather(node, children);
|
|
279
|
+
|
|
280
|
+
assign(node, children, child_count, slots);
|
|
281
|
+
|
|
282
|
+
let occupied = 0;
|
|
283
|
+
let internal = 0;
|
|
284
|
+
|
|
285
|
+
// which child sits in a slot
|
|
286
|
+
const child_in_slot = new Array(8).fill(BVH_NULL_NODE);
|
|
287
|
+
|
|
288
|
+
for (let c = 0; c < child_count; c++) {
|
|
289
|
+
const slot = slots[c];
|
|
290
|
+
|
|
291
|
+
occupied |= 1 << slot;
|
|
292
|
+
child_in_slot[slot] = children[c];
|
|
293
|
+
|
|
294
|
+
if (!is_leaf(children[c])) {
|
|
295
|
+
internal |= 1 << slot;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const b = bounds_word(children[c]);
|
|
299
|
+
|
|
300
|
+
for (let i = 0; i < 6; i++) {
|
|
301
|
+
slot_boxes[slot * 6 + i] = tree_floats[b + i];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const n = bounds_word(node);
|
|
306
|
+
|
|
307
|
+
bvh8_node_fit_slots(bvh8, index, tree_floats.subarray(n, n + 6), slot_boxes, occupied);
|
|
308
|
+
|
|
309
|
+
bvh8.node_set_imask(index, internal);
|
|
310
|
+
bvh8.node_set_base_index_child(index, child_base[node]);
|
|
311
|
+
bvh8.node_set_base_index_triangle(index, leaf_base[node]);
|
|
312
|
+
|
|
313
|
+
let leaves_before = 0;
|
|
314
|
+
|
|
315
|
+
for (let slot = 0; slot < 8; slot++) {
|
|
316
|
+
if ((occupied & (1 << slot)) === 0) {
|
|
317
|
+
bvh8.node_set_meta(index, slot, 0);
|
|
318
|
+
} else if ((internal & (1 << slot)) !== 0) {
|
|
319
|
+
bvh8.node_set_meta(index, slot, 0b00100000 | (24 + slot));
|
|
320
|
+
} else {
|
|
321
|
+
// a run of one leaf
|
|
322
|
+
bvh8.node_set_meta(index, slot, 0b00100000 | leaves_before);
|
|
323
|
+
|
|
324
|
+
// a binary leaf's second child word is its payload
|
|
325
|
+
out[order_offset + leaf_base[node] + leaves_before] = child_2(child_in_slot[slot]);
|
|
326
|
+
|
|
327
|
+
leaves_before++;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ===========
|
|
333
|
+
// The header, and the nodes behind it
|
|
334
|
+
// ===========
|
|
335
|
+
const r = bounds_word(root);
|
|
336
|
+
|
|
337
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
338
|
+
out_floats[BVH8_TREE_BOUNDS_LOW_WORD + axis] = tree_floats[r + axis];
|
|
339
|
+
out_floats[BVH8_TREE_BOUNDS_HIGH_WORD + axis] = tree_floats[r + 3 + axis];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
out[BVH8_TREE_LEAF_COUNT_WORD] = leaf_count;
|
|
343
|
+
out[BVH8_TREE_ORDER_OFFSET_WORD] = order_offset;
|
|
344
|
+
|
|
345
|
+
out.set(new Uint32Array(bvh8.data_buffer, 0, node_count * BVH8_TREE_NODE_STRIDE_WORDS), BVH8_TREE_HEADER_WORDS);
|
|
346
|
+
|
|
347
|
+
return node_count;
|
|
348
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check a BVH8 in the layout of {@link BVH8_TREE_BUFFER_LAYOUT} for what every walk of it relies on,
|
|
3
|
+
* whoever built it:
|
|
4
|
+
*
|
|
5
|
+
* - the header counts the leaves and says where their payloads start, straight behind the nodes;
|
|
6
|
+
* - from node 0 every node is reached, and reached once;
|
|
7
|
+
* - a slot is empty, a child node or one leaf, and its meta and the node's child mask agree which;
|
|
8
|
+
* - a node's child nodes are the block its base names, in slot order;
|
|
9
|
+
* - every payload expected is a leaf's, once, and no leaf carries another;
|
|
10
|
+
* - a slot's box holds every leaf under it, to within the node's grid: no leaf sticks out, and the
|
|
11
|
+
* box is no looser than two steps of the grid a side;
|
|
12
|
+
* - the header's box is the box of every leaf.
|
|
13
|
+
*
|
|
14
|
+
* A tree of no leaves is a header that counts none and one node with every slot empty.
|
|
15
|
+
*
|
|
16
|
+
* @param {ArrayLike<number>} tree the buffer's words
|
|
17
|
+
* @param {number} leaf_count how many leaves the tree should hold
|
|
18
|
+
* @param {ArrayLike<number>} expected_payloads the payload of every leaf, in any order
|
|
19
|
+
* @param {function(number): ArrayLike<number>} [box_of] the box of the leaf carrying a payload,
|
|
20
|
+
* `[min.xyz, max.xyz]` in float32 values; without it no box is checked
|
|
21
|
+
* @returns {{problems: string[], warnings: string[], node_count: number, max_depth: number, depth_histogram: number[], low: number[], high: number[]}}
|
|
22
|
+
* what is wrong, the first three of a kind; then the tree's nodes, the levels of nodes a walk goes
|
|
23
|
+
* down, its leaves by the level of the node that holds them, and the header's box
|
|
24
|
+
*/
|
|
25
|
+
export function check_bvh8_tree(tree: ArrayLike<number>, leaf_count: number, expected_payloads: ArrayLike<number>, box_of?: (arg0: number) => ArrayLike<number>): {
|
|
26
|
+
problems: string[];
|
|
27
|
+
warnings: string[];
|
|
28
|
+
node_count: number;
|
|
29
|
+
max_depth: number;
|
|
30
|
+
depth_histogram: number[];
|
|
31
|
+
low: number[];
|
|
32
|
+
high: number[];
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=check_bvh8_tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check_bvh8_tree.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/gpu_primitive/bvh8/check_bvh8_tree.js"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,sCATW,UAAU,MAAM,CAAC,cACjB,MAAM,qBACN,UAAU,MAAM,CAAC,kBACR,MAAM,KAAG,UAAU,MAAM,CAAC,GAEjC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAC,CAmQrJ"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { bitCount } from "../../../../core/binary/operations/bitCount.js";
|
|
2
|
+
import { reinterpret_uint32_as_float32 } from "../../../../core/binary/reinterpret_uint32_as_float32.js";
|
|
3
|
+
import {
|
|
4
|
+
BVH8_TREE_BOUNDS_HIGH_WORD,
|
|
5
|
+
BVH8_TREE_BOUNDS_LOW_WORD,
|
|
6
|
+
BVH8_TREE_HEADER_WORDS,
|
|
7
|
+
BVH8_TREE_LEAF_COUNT_WORD,
|
|
8
|
+
BVH8_TREE_NODE_STRIDE_WORDS,
|
|
9
|
+
BVH8_TREE_ORDER_OFFSET_WORD
|
|
10
|
+
} from "./BVH8_TREE_BUFFER_LAYOUT.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check a BVH8 in the layout of {@link BVH8_TREE_BUFFER_LAYOUT} for what every walk of it relies on,
|
|
14
|
+
* whoever built it:
|
|
15
|
+
*
|
|
16
|
+
* - the header counts the leaves and says where their payloads start, straight behind the nodes;
|
|
17
|
+
* - from node 0 every node is reached, and reached once;
|
|
18
|
+
* - a slot is empty, a child node or one leaf, and its meta and the node's child mask agree which;
|
|
19
|
+
* - a node's child nodes are the block its base names, in slot order;
|
|
20
|
+
* - every payload expected is a leaf's, once, and no leaf carries another;
|
|
21
|
+
* - a slot's box holds every leaf under it, to within the node's grid: no leaf sticks out, and the
|
|
22
|
+
* box is no looser than two steps of the grid a side;
|
|
23
|
+
* - the header's box is the box of every leaf.
|
|
24
|
+
*
|
|
25
|
+
* A tree of no leaves is a header that counts none and one node with every slot empty.
|
|
26
|
+
*
|
|
27
|
+
* @param {ArrayLike<number>} tree the buffer's words
|
|
28
|
+
* @param {number} leaf_count how many leaves the tree should hold
|
|
29
|
+
* @param {ArrayLike<number>} expected_payloads the payload of every leaf, in any order
|
|
30
|
+
* @param {function(number): ArrayLike<number>} [box_of] the box of the leaf carrying a payload,
|
|
31
|
+
* `[min.xyz, max.xyz]` in float32 values; without it no box is checked
|
|
32
|
+
* @returns {{problems: string[], warnings: string[], node_count: number, max_depth: number, depth_histogram: number[], low: number[], high: number[]}}
|
|
33
|
+
* what is wrong, the first three of a kind; then the tree's nodes, the levels of nodes a walk goes
|
|
34
|
+
* down, its leaves by the level of the node that holds them, and the header's box
|
|
35
|
+
*/
|
|
36
|
+
export function check_bvh8_tree(tree, leaf_count, expected_payloads, box_of) {
|
|
37
|
+
const words = tree instanceof Uint32Array ? tree : Uint32Array.from(tree);
|
|
38
|
+
const floats = new Float32Array(words.buffer, words.byteOffset, words.length);
|
|
39
|
+
|
|
40
|
+
/** @type {string[]} */
|
|
41
|
+
const problems = [];
|
|
42
|
+
|
|
43
|
+
const result = {
|
|
44
|
+
problems,
|
|
45
|
+
warnings: [],
|
|
46
|
+
node_count: 0,
|
|
47
|
+
max_depth: 0,
|
|
48
|
+
depth_histogram: [],
|
|
49
|
+
low: Array.from(floats.subarray(BVH8_TREE_BOUNDS_LOW_WORD, BVH8_TREE_BOUNDS_LOW_WORD + 3)),
|
|
50
|
+
high: Array.from(floats.subarray(BVH8_TREE_BOUNDS_HIGH_WORD, BVH8_TREE_BOUNDS_HIGH_WORD + 3)),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// how many problems of each kind have been met
|
|
54
|
+
const met = new Map();
|
|
55
|
+
|
|
56
|
+
// of a kind of problem, the first few say it; a tree wrong at the root is wrong everywhere below
|
|
57
|
+
function problem(kind, text) {
|
|
58
|
+
const count = (met.get(kind) ?? 0) + 1;
|
|
59
|
+
|
|
60
|
+
met.set(kind, count);
|
|
61
|
+
|
|
62
|
+
if (count <= 3) {
|
|
63
|
+
problems.push(text);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (words[BVH8_TREE_LEAF_COUNT_WORD] !== leaf_count) {
|
|
68
|
+
problem('header', `the header counts ${words[BVH8_TREE_LEAF_COUNT_WORD]} leaves, expected ${leaf_count}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const order_offset = words[BVH8_TREE_ORDER_OFFSET_WORD];
|
|
72
|
+
|
|
73
|
+
const node_words = order_offset - BVH8_TREE_HEADER_WORDS;
|
|
74
|
+
|
|
75
|
+
if (order_offset < BVH8_TREE_HEADER_WORDS + BVH8_TREE_NODE_STRIDE_WORDS || node_words % BVH8_TREE_NODE_STRIDE_WORDS !== 0) {
|
|
76
|
+
problem('header', `the payloads start at word ${order_offset}, which is not behind a whole number of nodes`);
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (order_offset + leaf_count > words.length) {
|
|
82
|
+
problem('header', `the payloads start at word ${order_offset} and ${leaf_count} of them run past the buffer's ${words.length} words`);
|
|
83
|
+
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const node_count = node_words / BVH8_TREE_NODE_STRIDE_WORDS;
|
|
88
|
+
|
|
89
|
+
result.node_count = node_count;
|
|
90
|
+
|
|
91
|
+
if (leaf_count === 0) {
|
|
92
|
+
if (node_count !== 1) {
|
|
93
|
+
problem('empty', `a tree of no leaves has ${node_count} nodes, expected the one empty node`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (let word = 0; word < BVH8_TREE_NODE_STRIDE_WORDS; word++) {
|
|
97
|
+
if (words[BVH8_TREE_HEADER_WORDS + word] !== 0) {
|
|
98
|
+
problem('empty', `the empty node's word ${word} is 0x${words[BVH8_TREE_HEADER_WORDS + word].toString(16)}, expected zero`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const visited = new Uint8Array(node_count);
|
|
106
|
+
|
|
107
|
+
// how many leaves carry each payload
|
|
108
|
+
const carried = new Map();
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {number} node
|
|
112
|
+
* @param {number} depth levels of nodes down to and including this one
|
|
113
|
+
* @returns {number[]|null} the box of every leaf under the node, if boxes are known
|
|
114
|
+
*/
|
|
115
|
+
function walk(node, depth) {
|
|
116
|
+
if (visited[node] === 1) {
|
|
117
|
+
problem('reached twice', `node ${node} is reached twice`);
|
|
118
|
+
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
visited[node] = 1;
|
|
123
|
+
|
|
124
|
+
result.max_depth = Math.max(result.max_depth, depth);
|
|
125
|
+
|
|
126
|
+
const at = BVH8_TREE_HEADER_WORDS + node * BVH8_TREE_NODE_STRIDE_WORDS;
|
|
127
|
+
|
|
128
|
+
const origin = [floats[at], floats[at + 1], floats[at + 2]];
|
|
129
|
+
|
|
130
|
+
const packed = words[at + 3];
|
|
131
|
+
|
|
132
|
+
// the step of the node's grid an axis; an exponent of zero is a step of nothing
|
|
133
|
+
const steps = [packed & 0xFF, (packed >>> 8) & 0xFF, (packed >>> 16) & 0xFF]
|
|
134
|
+
.map(exponent => exponent === 0 ? 0 : reinterpret_uint32_as_float32(exponent << 23));
|
|
135
|
+
|
|
136
|
+
const child_mask = packed >>> 24;
|
|
137
|
+
|
|
138
|
+
const child_base = words[at + 4];
|
|
139
|
+
const leaf_base = words[at + 5];
|
|
140
|
+
|
|
141
|
+
/** @type {number[]|null} */
|
|
142
|
+
let under_node = null;
|
|
143
|
+
|
|
144
|
+
let child_rank = 0;
|
|
145
|
+
let held = 0;
|
|
146
|
+
|
|
147
|
+
for (let slot = 0; slot < 8; slot++) {
|
|
148
|
+
const slot_meta = (words[at + 6 + (slot >> 2)] >>> ((slot & 3) * 8)) & 0xFF;
|
|
149
|
+
|
|
150
|
+
const is_child = (child_mask & (1 << slot)) !== 0;
|
|
151
|
+
|
|
152
|
+
if (slot_meta === 0) {
|
|
153
|
+
if (is_child) {
|
|
154
|
+
problem('meta', `node ${node} slot ${slot} is empty and in the child mask`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
held++;
|
|
161
|
+
|
|
162
|
+
/** @type {number[]|null} */
|
|
163
|
+
let under = null;
|
|
164
|
+
|
|
165
|
+
if (is_child) {
|
|
166
|
+
if (slot_meta !== (0b00100000 | (24 + slot))) {
|
|
167
|
+
problem('meta', `node ${node} slot ${slot} is in the child mask with meta 0x${slot_meta.toString(16)}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const child = child_base + child_rank;
|
|
171
|
+
|
|
172
|
+
child_rank++;
|
|
173
|
+
|
|
174
|
+
if (child >= node_count) {
|
|
175
|
+
problem('child', `node ${node} slot ${slot} names child node ${child} of ${node_count}`);
|
|
176
|
+
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
under = walk(child, depth + 1);
|
|
181
|
+
} else {
|
|
182
|
+
if (bitCount(slot_meta >>> 5) !== 1) {
|
|
183
|
+
problem('meta', `node ${node} slot ${slot} has meta 0x${slot_meta.toString(16)}, which is not one leaf`);
|
|
184
|
+
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const leaf = leaf_base + (slot_meta & 31);
|
|
189
|
+
|
|
190
|
+
if (leaf >= leaf_count) {
|
|
191
|
+
problem('leaf', `node ${node} slot ${slot} names leaf ${leaf} of ${leaf_count}`);
|
|
192
|
+
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const payload = words[order_offset + leaf];
|
|
197
|
+
|
|
198
|
+
carried.set(payload, (carried.get(payload) ?? 0) + 1);
|
|
199
|
+
|
|
200
|
+
result.depth_histogram[depth] = (result.depth_histogram[depth] ?? 0) + 1;
|
|
201
|
+
|
|
202
|
+
if (box_of !== undefined) {
|
|
203
|
+
under = Array.from(box_of(payload));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (under === null) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
212
|
+
const byte_shift = (slot & 3) * 8;
|
|
213
|
+
|
|
214
|
+
const q_low = (words[at + 8 + axis * 4 + (slot >> 2)] >>> byte_shift) & 0xFF;
|
|
215
|
+
const q_high = (words[at + 10 + axis * 4 + (slot >> 2)] >>> byte_shift) & 0xFF;
|
|
216
|
+
|
|
217
|
+
const low = origin[axis] + q_low * steps[axis];
|
|
218
|
+
const high = origin[axis] + q_high * steps[axis];
|
|
219
|
+
|
|
220
|
+
if (!(low <= under[axis] && high >= under[axis + 3])) {
|
|
221
|
+
problem('holds', `node ${node} slot ${slot} axis ${axis}: the box [${low}, ${high}] does not hold what is under it, [${under[axis]}, ${under[axis + 3]}]`);
|
|
222
|
+
} else if (under[axis] - low > 2 * steps[axis] || high - under[axis + 3] > 2 * steps[axis]) {
|
|
223
|
+
problem('loose', `node ${node} slot ${slot} axis ${axis}: the box [${low}, ${high}] is more than two steps of ${steps[axis]} looser than what is under it, [${under[axis]}, ${under[axis + 3]}]`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (under_node === null) {
|
|
228
|
+
under_node = under.slice();
|
|
229
|
+
} else {
|
|
230
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
231
|
+
under_node[axis] = Math.min(under_node[axis], under[axis]);
|
|
232
|
+
under_node[axis + 3] = Math.max(under_node[axis + 3], under[axis + 3]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (held === 0) {
|
|
238
|
+
problem('nothing', `node ${node} holds nothing`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return under_node;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const under_root = walk(0, 1);
|
|
245
|
+
|
|
246
|
+
let unreached = 0;
|
|
247
|
+
|
|
248
|
+
for (let node = 0; node < node_count; node++) {
|
|
249
|
+
if (visited[node] === 0) {
|
|
250
|
+
unreached++;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (unreached > 0) {
|
|
255
|
+
problem('unreached', `${unreached} of ${node_count} nodes are never reached from the root`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let leaves_expected = 0;
|
|
259
|
+
|
|
260
|
+
for (let i = 0; i < expected_payloads.length; i++) {
|
|
261
|
+
const payload = expected_payloads[i];
|
|
262
|
+
|
|
263
|
+
leaves_expected++;
|
|
264
|
+
|
|
265
|
+
const times = carried.get(payload) ?? 0;
|
|
266
|
+
|
|
267
|
+
if (times !== 1) {
|
|
268
|
+
problem('payload', `payload ${payload} is carried by ${times} leaves, expected one`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
carried.delete(payload);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const [payload, times] of carried) {
|
|
275
|
+
problem('stray payload', `payload ${payload}, which no leaf should carry, is carried by ${times}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (leaves_expected !== leaf_count) {
|
|
279
|
+
problem('header', `${leaves_expected} payloads were expected of a tree of ${leaf_count} leaves`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (under_root !== null) {
|
|
283
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
284
|
+
if (result.low[axis] !== under_root[axis] || result.high[axis] !== under_root[axis + 3]) {
|
|
285
|
+
problem('bounds', `the header's box on axis ${axis} is [${result.low[axis]}, ${result.high[axis]}], and the leaves span [${under_root[axis]}, ${under_root[axis + 3]}]`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return result;
|
|
291
|
+
}
|