@woosh/meep-engine 2.164.0 → 2.165.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/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BitImage2.d.ts +91 -0
- package/src/core/binary/BitImage2.d.ts.map +1 -0
- package/src/core/binary/BitImage2.js +242 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts +22 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts.map +1 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.js +69 -0
- package/src/core/geom/2d/packing/skyline.d.ts +116 -0
- package/src/core/geom/2d/packing/skyline.d.ts.map +1 -0
- package/src/core/geom/2d/packing/skyline.js +258 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts +18 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts.map +1 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +86 -0
- package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +486 -0
- package/src/core/geom/3d/atlas/BFF_PLAN.md +174 -0
- package/src/core/geom/3d/atlas/Chart.d.ts +58 -0
- package/src/core/geom/3d/atlas/Chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/Chart.js +77 -0
- package/src/core/geom/3d/atlas/REVIEW_02.md +392 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +73 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.js +315 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.js +16 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.js +188 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.js +107 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts +39 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_generate.js +43 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts +84 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.js +266 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.js +36 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts +22 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.js +62 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.js +33 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.js +50 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts +27 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.js +39 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts +22 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.js +57 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts +36 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.js +46 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts +62 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +551 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.js +73 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts +37 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +270 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts +23 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +224 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts +14 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js +38 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js +86 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts +20 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.js +183 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts +27 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.js +66 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts +31 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.js +40 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts +23 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.js +136 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts +24 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.js +77 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts +27 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +113 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +44 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +275 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +22 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +199 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts +32 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts.map +1 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.js +64 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts +20 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +66 -0
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +13 -11
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.js +4 -3
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.js +10 -6
- package/src/core/geom/3d/topology/struct/TopoMesh.js +2 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts +0 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/TopoTriangle.js +2 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +8 -27
- package/src/core/geom/vec3/v3_cotangent.d.ts +20 -0
- package/src/core/geom/vec3/v3_cotangent.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_cotangent.js +29 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts +19 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.js +30 -0
- package/src/core/geom/vec3/v3_multiply.d.ts +16 -0
- package/src/core/geom/vec3/v3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_multiply.js +19 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts +24 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve.js +106 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts +21 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.js +59 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +19 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +117 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts +50 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.js +88 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts +9 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec.js +22 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts +12 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.js +29 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.d.ts +39 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.js +22 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.js +32 -9
- package/src/core/math/physics/mie/compute_mie_phase.d.ts +2 -3
- package/src/core/math/physics/mie/compute_mie_phase.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_phase.js +1 -3
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts +0 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts.map +1 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.js +0 -7
- package/src/engine/ecs/attachment/TransformAttachmentBinding.js +3 -3
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +2 -2
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +4 -3
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +2 -2
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +9 -8
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +2 -1
- package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +0 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +8 -7
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.js +11 -6
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +2 -3
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.js +3 -4
- package/src/engine/graphics/geometry/MikkT/DegenEpilogue.js +4 -4
- package/src/engine/graphics/geometry/MikkT/EvalTspace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/EvalTspace.js +11 -8
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +7 -8
- package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +8 -8
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.js +30 -25
- package/src/engine/graphics/geometry/MikkT/MikkTSpace.js +7 -7
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts +0 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.js +6 -4
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/STSpace.js +3 -3
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +0 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts +0 -2
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts.map +1 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.js +4 -3
- package/src/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +2 -2
- package/src/engine/graphics/impostors/octahedral/grid/UvEncoder.d.ts +17 -7
- package/src/engine/graphics/impostors/voxel/VoxelImpostorBaker.js +2 -2
- package/src/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +3 -3
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +4 -3
- package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts +0 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/Decal.js +3 -3
- package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +4 -3
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +6 -4
- package/src/engine/graphics/sh3/lightmap/ARTIFACTS_PLAN.md +146 -0
- package/src/engine/graphics/sh3/lightmap/CODE_REVIEW.md +121 -0
- package/src/engine/graphics/sh3/lightmap/LIGHTMAPPER_REVIEW.md +183 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts +90 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.js +678 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts +32 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.js +155 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts +49 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.js +136 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts +19 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.js +89 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts +54 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.js +168 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts +30 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.js +145 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts +38 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.js +152 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts +2 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.js +186 -0
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/PathTracer.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.js +6 -4
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +3 -3
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +5 -4
- package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.js +2 -2
- package/src/engine/input/devices/KeyboardDevice.d.ts +61 -14
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +41 -15
- package/src/engine/input/devices/isHTMLElementFocusable.d.ts.map +1 -1
- package/src/engine/input/devices/isHTMLElementFocusable.js +2 -9
- package/src/engine/sound/simulation/prototypeAcousticSolver.js +261 -143
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
MeshStandardMaterial,
|
|
7
7
|
SphereGeometry
|
|
8
8
|
} from "three";
|
|
9
|
-
import { AABB3 } from "../../../core/geom/3d/aabb/AABB3.js";
|
|
10
9
|
import { Ray3 } from "../../../core/geom/3d/ray/Ray3.js";
|
|
11
10
|
import { BoxShape3D } from "../../../core/geom/3d/shape/BoxShape3D.js";
|
|
12
11
|
import { CapsuleShape3D } from "../../../core/geom/3d/shape/CapsuleShape3D.js";
|
|
@@ -33,9 +32,7 @@ import { ShadedGeometrySystem } from "../../graphics/ecs/mesh-v2/ShadedGeometryS
|
|
|
33
32
|
import {
|
|
34
33
|
AmbientOcclusionPostProcessEffect
|
|
35
34
|
} from "../../graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js";
|
|
36
|
-
import {
|
|
37
|
-
import { LightProbeVolume } from "../../graphics/sh3/lpv/LightProbeVolume.js";
|
|
38
|
-
import { LightProbeVolumeBaker } from "../../graphics/sh3/lpv/LightProbeVolumeBaker.js";
|
|
35
|
+
import { bake_lightmap_for_scene } from "../../graphics/sh3/lightmap/bake_lightmap_for_scene.js";
|
|
39
36
|
import { setup_environment_sky_from_ecd } from "../../graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.js";
|
|
40
37
|
import {
|
|
41
38
|
sampler2d_sample_equirectangular_direction
|
|
@@ -200,6 +197,8 @@ const SHACK_DOOR_HALF = 0.5, SHACK_DOOR_H = 2.0; // a 1 m doorway on the west wa
|
|
|
200
197
|
// occluder index re-syncs on transform change) — closed it seals the opening, open it clears it.
|
|
201
198
|
const DOOR_T = 0.2; // door slab thickness (sits within the opening)
|
|
202
199
|
const DOOR_SLIDE_SPEED = 3.0; // m/s vertical travel
|
|
200
|
+
const DOOR_OPEN_CLEARANCE = 0.2; // extra drop when open, so the lowered slab's top sinks clear of the floor
|
|
201
|
+
// (y=0) instead of sitting coplanar with it and z-fighting the seam
|
|
203
202
|
|
|
204
203
|
// -- Orbiting external source (WorldMode layer), circling the scene from outside ------------------------
|
|
205
204
|
const ORBIT_CLIP = "data/sounds/music/matsmusic/d1/Fiverr Alexgoldring WorldMode LAYER 1.ogg";
|
|
@@ -209,17 +208,18 @@ const ORBIT_HEIGHT = 5; // a touch above the walls, so line-of-sig
|
|
|
209
208
|
const ORBIT_SPEED = 0.18; // rad/s (~35 s per lap)
|
|
210
209
|
const ORBIT_DIST_MIN = 12, ORBIT_DIST_MAX = 90; // carries far — clearly audible from the centre with LoS
|
|
211
210
|
|
|
212
|
-
// --
|
|
213
|
-
//
|
|
214
|
-
//
|
|
211
|
+
// -- Baked indirect lighting (a single shared lightmap). Baked once at startup by path-tracing the scene's
|
|
212
|
+
// UV-atlas texels (mixed mode: indirect bounces + sky only — direct light stays realtime), so the atlas
|
|
213
|
+
// resolution + samples/texel are the bake-cost knobs. After the bake the IBL is switched off
|
|
214
|
+
// (scene.environment = null) so the baked lightmap is the only indirect light — the sky stays as the backdrop.
|
|
215
215
|
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
const
|
|
216
|
+
// Unlike the old probe volume there are NO bounds to tune: the charter derives the atlas from the geometry
|
|
217
|
+
// itself, so every ShadedGeometry surface is covered. The bake rewrites each mesh with a uv2 channel and points
|
|
218
|
+
// its material at the shared lightmap; the acoustic occluder/collider shapes are untouched (lightmap is visuals
|
|
219
|
+
// only), so the acoustic simulation is unaffected.
|
|
220
|
+
const LIGHTMAP_RESOLUTION = 1024; // shared atlas size (texels per side)
|
|
221
|
+
const LIGHTMAP_SAMPLES = 1024; // hemisphere gather samples per fully-baked texel
|
|
222
|
+
const LIGHTMAP_MAX_BOUNCE = 4; // path-tracer maximum bounce depth
|
|
223
223
|
|
|
224
224
|
// -- Point lights co-located with each emissive source marker (a warm/cool glow in its room) -----------
|
|
225
225
|
const SOURCE_LIGHT_INTENSITY = 6, SOURCE_LIGHT_DISTANCE = 12;
|
|
@@ -227,15 +227,18 @@ const SOURCE_LIGHT_INTENSITY = 6, SOURCE_LIGHT_DISTANCE = 12;
|
|
|
227
227
|
// Wired in the configuration callback (needs the EngineConfiguration); baked against in main().
|
|
228
228
|
let acousticSim = null;
|
|
229
229
|
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
230
|
+
// The graphics MaterialManager, captured at the top of main(). Every lit scene material is obtained THROUGH it
|
|
231
|
+
// (see litMaterial) so the engine's registered compile-steps patch it — in particular the forward+ clustered-
|
|
232
|
+
// lighting transformer (registered by the LightSystem's forward+ plugin), which is what makes the per-source
|
|
233
|
+
// POINT lights actually illuminate a surface. A bare `new MeshStandardMaterial(...)` skips the compile chain and
|
|
234
|
+
// so receives NO clustered (point/spot) lighting — only the directional sun.
|
|
233
235
|
let materialManager = null;
|
|
234
236
|
|
|
235
237
|
/**
|
|
236
|
-
* A managed lit material: routed through the {@link MaterialManager} so every registered compile-step
|
|
237
|
-
*
|
|
238
|
-
* `new MeshStandardMaterial
|
|
238
|
+
* A managed lit material: routed through the {@link MaterialManager} so every registered compile-step patches it
|
|
239
|
+
* — notably the forward+ clustered-lighting transformer, so the per-source POINT lights light it. Use this for
|
|
240
|
+
* every lit surface instead of a bare `new MeshStandardMaterial`. The baked lightmap is applied on top by
|
|
241
|
+
* {@link bake_lightmap_for_scene}, which sets `material.lightMap` on the obtained material directly.
|
|
239
242
|
*
|
|
240
243
|
* @param {object} params MeshStandardMaterial parameters (color, roughness, emissive, …)
|
|
241
244
|
* @returns {MeshStandardMaterial} the managed (compiled) material to hand to {@link ShadedGeometry.from}
|
|
@@ -273,31 +276,13 @@ function setupSound(config, engine) {
|
|
|
273
276
|
config.addSystem(new SoundListenerSystem(engine.sound.context));
|
|
274
277
|
}
|
|
275
278
|
|
|
276
|
-
/**
|
|
277
|
-
* Create the light probe volume + its material compile-step. MUST run before any scene geometry compiles — the
|
|
278
|
-
* transformer injects the irradiance-sampling shader chunk into lit materials AT compile time — so it is called
|
|
279
|
-
* at the very top of {@link main}. The bake itself runs later, once the geometry exists ({@link bakeLightProbes}).
|
|
280
|
-
*
|
|
281
|
-
* @param {Engine} engine
|
|
282
|
-
* @returns {{volume:LightProbeVolume, transformer:MaterialTransformer}}
|
|
283
|
-
*/
|
|
284
|
-
function setupLightProbes(engine) {
|
|
285
|
-
materialManager = engine.graphics.getMaterialManager();
|
|
286
|
-
const volume = new LightProbeVolume();
|
|
287
|
-
// Fragment (per-pixel) sampling: this scene is big flat boxes, so vertex sampling (only the 4 face corners)
|
|
288
|
-
// would barely read; fragment is costlier but shows the baked GI gradient across a wall/floor.
|
|
289
|
-
const transformer = new MaterialTransformer({ volume, stage: ProbeResolutionStage.Fragment });
|
|
290
|
-
materialManager.addCompileStep(transformer);
|
|
291
|
-
return { volume, transformer };
|
|
292
|
-
}
|
|
293
|
-
|
|
294
279
|
const _skyScratch = new Float32Array(4);
|
|
295
280
|
|
|
296
281
|
/**
|
|
297
|
-
* A path-tracer background sampler over the Hosek sky equirectangular texture, by ray direction (+Y up). The
|
|
298
|
-
* baker's path tracer otherwise has a BLACK background ({@link PathTracedScene} default), so without
|
|
299
|
-
* bake captures only the sun bouncing off surfaces — no sky-dome fill. It samples the SAME sharp sky
|
|
300
|
-
* renderer applies, so the baked GI matches the visible sky.
|
|
282
|
+
* A path-tracer background sampler over the Hosek sky equirectangular texture, by ray direction (+Y up). The
|
|
283
|
+
* lightmap baker's path tracer otherwise has a BLACK background ({@link PathTracedScene} default), so without
|
|
284
|
+
* this the bake captures only the sun bouncing off surfaces — no sky-dome fill. It samples the SAME sharp sky
|
|
285
|
+
* texture the renderer applies, so the baked GI matches the visible sky.
|
|
301
286
|
*
|
|
302
287
|
* @param {THREE.DataTexture} skyTexture equirectangular Float32 RGBA sky (the return of setup_environment_sky_from_ecd)
|
|
303
288
|
* @returns {function(out:number[], out_offset:number, direction:number[], direction_offset:number): void}
|
|
@@ -322,44 +307,118 @@ function makeSkyBackgroundSampler(skyTexture) {
|
|
|
322
307
|
}
|
|
323
308
|
|
|
324
309
|
/**
|
|
325
|
-
* Bake
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
310
|
+
* Bake a single shared lightmap against the now-populated scene ({@link bake_lightmap_for_scene} charts every
|
|
311
|
+
* {@link ShadedGeometry} into one UV atlas and path-traces its texels — {@link LIGHTMAP_RESOLUTION} +
|
|
312
|
+
* {@link LIGHTMAP_SAMPLES} drive the cost), overriding the baker's default procedural sky with the Hosek SKY as
|
|
313
|
+
* its background radiance so the baked sky-dome fill matches the visible sky. The bake rewrites each mesh with a
|
|
314
|
+
* uv2 channel and points its material at the shared lightmap, so it lights itself once the texels resolve. Then
|
|
315
|
+
* switch the IBL OFF (`scene.environment = null`) so the baked lightmap is the only indirect light; the sky
|
|
316
|
+
* stays as the visible backdrop (`scene.background`).
|
|
330
317
|
*
|
|
331
318
|
* @param {Engine} engine
|
|
332
319
|
* @param {EntityComponentDataset} ecd
|
|
333
|
-
* @param {{volume:LightProbeVolume, transformer:MaterialTransformer}} lpv
|
|
334
320
|
* @param {THREE.DataTexture} skyTexture the equirectangular sky to sample as the bake's background radiance
|
|
335
321
|
*/
|
|
336
|
-
async function
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
322
|
+
async function bakeLightmap(engine, ecd, skyTexture) {
|
|
323
|
+
const group = bake_lightmap_for_scene({
|
|
324
|
+
ecd,
|
|
325
|
+
lightmap_resolution: LIGHTMAP_RESOLUTION,
|
|
326
|
+
samples_per_texel: LIGHTMAP_SAMPLES,
|
|
327
|
+
max_bounce: LIGHTMAP_MAX_BOUNCE,
|
|
328
|
+
// Sample the Hosek sky as the bake's background (its default is the procedural RTIW sky) — escaped rays
|
|
329
|
+
// then return the SAME sky the renderer shows, so the baked fill matches the visible sky.
|
|
330
|
+
background: makeSkyBackgroundSampler(skyTexture),
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Run the bake on the executor (incremental — the partial atlas uploads each cycle) and wait for it to finish.
|
|
334
|
+
// While it runs, poll the group's progress each frame to drive an unobtrusive corner progress bar + ETA.
|
|
335
|
+
const progress = makeBakeProgressBar();
|
|
336
|
+
const start = performance.now();
|
|
337
|
+
let running = true;
|
|
338
|
+
|
|
339
|
+
engine.executor.runGroup(group);
|
|
340
|
+
|
|
341
|
+
(function poll() {
|
|
342
|
+
if (!running) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
progress.set(group.computeProgress(), performance.now() - start);
|
|
346
|
+
requestAnimationFrame(poll);
|
|
347
|
+
})();
|
|
348
|
+
|
|
349
|
+
await group.promise();
|
|
350
|
+
|
|
351
|
+
running = false;
|
|
352
|
+
progress.remove();
|
|
353
|
+
|
|
354
|
+
engine.graphics.scene.environment = null; // IBL off — only the baked lightmap contributes indirect light now
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* A small, unobtrusive lightmap-bake progress bar pinned to the bottom-left corner, showing percent done + a
|
|
359
|
+
* live ETA. The ETA is a linear extrapolation from elapsed time (`elapsed × (1 − p) / p`), reading "estimating…"
|
|
360
|
+
* until there is enough progress to extrapolate. Returns a handle to drive + dismiss it.
|
|
361
|
+
*
|
|
362
|
+
* @returns {{set: function(fraction:number, elapsedMs:number): void, remove: function(): void}}
|
|
363
|
+
*/
|
|
364
|
+
function makeBakeProgressBar() {
|
|
365
|
+
const container = document.createElement("div");
|
|
366
|
+
Object.assign(container.style, {
|
|
367
|
+
position: "absolute", left: "10px", bottom: "10px", zIndex: "1000",
|
|
368
|
+
width: "210px", padding: "8px 10px",
|
|
369
|
+
font: "12px sans-serif", color: "#cfe6ff",
|
|
370
|
+
background: "rgba(18,26,34,0.85)", border: "1px solid #3a6ea5", borderRadius: "4px",
|
|
371
|
+
pointerEvents: "none", userSelect: "none",
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const label = document.createElement("div");
|
|
375
|
+
label.style.marginBottom = "6px";
|
|
376
|
+
label.style.letterSpacing = "0.3px";
|
|
377
|
+
label.textContent = "Baking lightmap…";
|
|
378
|
+
|
|
379
|
+
const track = document.createElement("div");
|
|
380
|
+
Object.assign(track.style, {
|
|
381
|
+
height: "6px", width: "100%", background: "rgba(255,255,255,0.12)", borderRadius: "3px", overflow: "hidden",
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const fill = document.createElement("div");
|
|
385
|
+
Object.assign(fill.style, { height: "100%", width: "0%", background: "#5fa8ff", transition: "width 0.1s linear" });
|
|
386
|
+
|
|
387
|
+
track.appendChild(fill);
|
|
388
|
+
container.appendChild(label);
|
|
389
|
+
container.appendChild(track);
|
|
390
|
+
document.body.appendChild(container);
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
set(fraction, elapsedMs) {
|
|
394
|
+
const p = Math.max(0, Math.min(1, fraction));
|
|
395
|
+
fill.style.width = `${(p * 100).toFixed(1)}%`;
|
|
396
|
+
const eta = p > 0.02 ? formatDuration((elapsedMs / p) * (1 - p)) : "estimating…";
|
|
397
|
+
label.textContent = `Baking lightmap… ${(p * 100).toFixed(0)}% · ETA ${eta}`;
|
|
398
|
+
},
|
|
399
|
+
remove() {
|
|
400
|
+
container.remove();
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** Format a millisecond duration as a compact "Xm Ys" / "Ys" string for the bake ETA. */
|
|
406
|
+
function formatDuration(ms) {
|
|
407
|
+
const totalSeconds = Math.max(0, Math.round(ms / 1000));
|
|
408
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
409
|
+
const seconds = totalSeconds % 60;
|
|
410
|
+
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
353
411
|
}
|
|
354
412
|
|
|
355
413
|
async function main(engine) {
|
|
356
414
|
const em = engine.entityManager;
|
|
357
415
|
const ecd = em.dataset;
|
|
358
416
|
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
|
|
417
|
+
// Capture the MaterialManager up front: every lit material is obtained through it (see litMaterial) so the
|
|
418
|
+
// engine's compile-steps patch it — notably the forward+ clustered-lighting transformer that lights surfaces
|
|
419
|
+
// with the per-source POINT lights. (That transformer is registered by the LightSystem's forward+ plugin,
|
|
420
|
+
// acquired in buildLights below; the obtain() calls happen later, as the world geometry is built.)
|
|
421
|
+
materialManager = engine.graphics.getMaterialManager();
|
|
363
422
|
|
|
364
423
|
// -- Systems ---------------------------------------------------------
|
|
365
424
|
EngineHarness.addFpsCounter(engine);
|
|
@@ -416,17 +475,21 @@ async function main(engine) {
|
|
|
416
475
|
buildScatteredOccluders(ecd);
|
|
417
476
|
buildSmallShack(ecd);
|
|
418
477
|
buildSlidingDoors(ecd); // house door + cathedral entrance, built OPEN (so the bake sees the openings clear)
|
|
419
|
-
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
478
|
+
|
|
479
|
+
// The three fixed sources' MARKERS (emissive sphere + point light) are built now, before the bake, so the
|
|
480
|
+
// lightmap captures their glow + the rooms they light. Only their AudioEmitter is deferred to the first
|
|
481
|
+
// click (startSources): the engine ticks inside EngineHarness.initialize, so an autoplay emitter built here
|
|
482
|
+
// would link + play on the still-suspended context (the autoplay-policy warning); attaching it on the
|
|
483
|
+
// gesture means its first playEvent lands on a running context. The moving orbiter source is spawned whole
|
|
484
|
+
// on that click (its light moves, so it is not baked).
|
|
485
|
+
const staticSources = buildStaticSourceMarkers(ecd);
|
|
423
486
|
|
|
424
487
|
// -- Player ----------------------------------------------------------
|
|
425
488
|
const player = buildPlayerEntity(ecd);
|
|
426
489
|
fpsSystem.groundResolver = makePhysicsGroundResolver(physicsSystem, player.entity);
|
|
427
490
|
motion.playerEntity = player.entity; // door-proximity overlap tests against the player capsule
|
|
428
491
|
buildInputBindings(ecd, player, motion);
|
|
429
|
-
setupInteraction(engine, ecd);
|
|
492
|
+
setupInteraction(engine, ecd, staticSources);
|
|
430
493
|
|
|
431
494
|
// -- Bake the probe field against the now-populated occluder index ----
|
|
432
495
|
// The acoustic entities above linked into acousticSim.occluderIndex on build; bake the visibility
|
|
@@ -459,13 +522,14 @@ async function main(engine) {
|
|
|
459
522
|
|
|
460
523
|
logHelp();
|
|
461
524
|
|
|
462
|
-
// --
|
|
463
|
-
// is the only indirect light. Done LAST (after the audio path is fully wired) — it
|
|
464
|
-
// a few seconds; the scene renders IBL-lit
|
|
465
|
-
|
|
466
|
-
console.
|
|
467
|
-
|
|
468
|
-
|
|
525
|
+
// -- Lightmap: bake the indirect GI into a shared atlas against the populated scene, then switch the IBL off
|
|
526
|
+
// so the baked lightmap is the only indirect light. Done LAST (after the audio path is fully wired) — it
|
|
527
|
+
// path-traces the atlas texels over a few seconds; the scene renders IBL-lit and uploads the partial atlas
|
|
528
|
+
// each cycle, then switches to the fully-baked GI when it finishes. -------------------------------------
|
|
529
|
+
console.log("%c[lightmap] baking…", "color:#ffcc66;font-weight:bold");
|
|
530
|
+
console.time("[lightmap] bake");
|
|
531
|
+
await bakeLightmap(engine, ecd, skyTexture);
|
|
532
|
+
console.timeEnd("[lightmap] bake");
|
|
469
533
|
}
|
|
470
534
|
|
|
471
535
|
/**
|
|
@@ -838,7 +902,9 @@ function spawnSlidingDoor(ecd, { center, size, zoneCenter, zoneHalf, label }) {
|
|
|
838
902
|
const collider = new Collider();
|
|
839
903
|
collider.shape = BoxShape3D.from_size(size.x, size.y, size.z);
|
|
840
904
|
|
|
841
|
-
|
|
905
|
+
// slid fully below the floor → the opening is clear; the extra DOOR_OPEN_CLEARANCE sinks the slab's top
|
|
906
|
+
// past the floor seam (its open top lands at y = -DOOR_OPEN_CLEARANCE) so it doesn't z-fight the floor.
|
|
907
|
+
const openY = center.y - size.y - DOOR_OPEN_CLEARANCE;
|
|
842
908
|
|
|
843
909
|
// START open (slid down): the doors begin open AND, since the acoustic bake runs after the world is built,
|
|
844
910
|
// it sees the openings clear rather than sealed. E closes them.
|
|
@@ -1017,12 +1083,13 @@ class PrototypeMotionSystem extends System {
|
|
|
1017
1083
|
// The MainMenu loop, shared by the house, cathedral and shack sources (same clip, different rooms/acoustics).
|
|
1018
1084
|
const MAIN_MENU_CLIP = "data/sounds/music/matsmusic/d1/Fiverr Alexgoldring MainMenu.ogg";
|
|
1019
1085
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1086
|
+
// The three FIXED sources — house, cathedral and the little SHACK — all play the SAME MainMenu loop (so the
|
|
1087
|
+
// difference you hear is purely the room acoustics). Their markers (an emissive sphere + a co-located point
|
|
1088
|
+
// light) are built at world time so the lightmap BAKES them — both the marker's glow and the room each one
|
|
1089
|
+
// lights. Only the AudioEmitter is deferred to the first click (see startSources). (The paths have spaces — the
|
|
1090
|
+
// browser percent-encodes them on fetch, and the dev server serves it straight from `app/`.)
|
|
1091
|
+
const STATIC_SOURCE_SPECS = [
|
|
1092
|
+
{
|
|
1026
1093
|
id: "house-mainmenu",
|
|
1027
1094
|
clipPath: MAIN_MENU_CLIP,
|
|
1028
1095
|
position: SRC,
|
|
@@ -1031,8 +1098,8 @@ function buildSources(ecd) {
|
|
|
1031
1098
|
markerColor: 0xffcc66,
|
|
1032
1099
|
markerEmissive: 0xff8800,
|
|
1033
1100
|
lightDistance: SOURCE_LIGHT_DISTANCE / 2, // a tighter orange glow in the small dead room
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1101
|
+
},
|
|
1102
|
+
{
|
|
1036
1103
|
id: "cathedral-mainmenu",
|
|
1037
1104
|
clipPath: MAIN_MENU_CLIP,
|
|
1038
1105
|
position: CATH_SRC,
|
|
@@ -1040,8 +1107,8 @@ function buildSources(ecd) {
|
|
|
1040
1107
|
distanceMax: CATH_SRC_DIST_MAX,
|
|
1041
1108
|
markerColor: 0x99ccff,
|
|
1042
1109
|
markerEmissive: 0x3388ff,
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1045
1112
|
id: "shack-mainmenu",
|
|
1046
1113
|
clipPath: MAIN_MENU_CLIP,
|
|
1047
1114
|
position: new Vector3(SHACK_X, 1.2, SHACK_Z),
|
|
@@ -1049,22 +1116,59 @@ function buildSources(ecd) {
|
|
|
1049
1116
|
distanceMax: SRC_DIST_MAX,
|
|
1050
1117
|
markerColor: 0xcc99ff,
|
|
1051
1118
|
markerEmissive: 0x8844cc,
|
|
1052
|
-
}
|
|
1119
|
+
},
|
|
1120
|
+
];
|
|
1053
1121
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1122
|
+
/**
|
|
1123
|
+
* Build the three FIXED sources' visual markers (an emissive sphere + a co-located point light each). Called at
|
|
1124
|
+
* world-build time, BEFORE the lightmap bake, so the bake captures each source's glow and the room it lights.
|
|
1125
|
+
* The audio is attached later, on the first click ({@link startSources}).
|
|
1126
|
+
*
|
|
1127
|
+
* @param {EntityComponentDataset} ecd
|
|
1128
|
+
* @returns {{entity:number, spec:object}[]} one record per static source, consumed by {@link startSources}
|
|
1129
|
+
*/
|
|
1130
|
+
function buildStaticSourceMarkers(ecd) {
|
|
1131
|
+
return STATIC_SOURCE_SPECS.map((spec) => ({ entity: buildSourceMarker(ecd, spec), spec }));
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* Start the audio on the first click, once the context has resumed: attach a (3D, looping, autoplay)
|
|
1136
|
+
* {@link AudioEmitter} to each pre-built static marker — so it links and autoplays on a RUNNING context (routing
|
|
1137
|
+
* is fixed at link, so the emitter must first appear on a resumed context) — and spawn the moving orbiter whole.
|
|
1138
|
+
*
|
|
1139
|
+
* @param {EntityComponentDataset} ecd
|
|
1140
|
+
* @param {{entity:number, spec:object}[]} staticSources the markers built by {@link buildStaticSourceMarkers}
|
|
1141
|
+
*/
|
|
1142
|
+
function startSources(ecd, staticSources) {
|
|
1143
|
+
for (const { entity, spec } of staticSources) {
|
|
1144
|
+
addSourceEmitter(ecd, entity, spec);
|
|
1145
|
+
}
|
|
1146
|
+
spawnOrbiter(ecd);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* A fourth source that ORBITS the whole scene from outside (a WorldMode layer): acoustic + a long max distance,
|
|
1151
|
+
* so from the centre you hear it swing in and out as buildings break the line of sight. Spawned whole on the
|
|
1152
|
+
* first click (marker + emitter + {@link PrototypeMover}, which drives its position each frame around
|
|
1153
|
+
* (ORBIT_CX, ORBIT_CZ)); because its light MOVES it is deliberately not baked into the lightmap.
|
|
1154
|
+
*
|
|
1155
|
+
* @param {EntityComponentDataset} ecd
|
|
1156
|
+
*/
|
|
1157
|
+
function spawnOrbiter(ecd) {
|
|
1158
|
+
const entity = buildSourceMarker(ecd, {
|
|
1060
1159
|
position: new Vector3(ORBIT_CX + ORBIT_RADIUS, ORBIT_HEIGHT, ORBIT_CZ),
|
|
1061
|
-
distanceMin: ORBIT_DIST_MIN,
|
|
1062
|
-
distanceMax: ORBIT_DIST_MAX,
|
|
1063
1160
|
markerColor: 0x99ff99,
|
|
1064
1161
|
markerEmissive: 0x33cc55,
|
|
1065
1162
|
lightIntensity: 9,
|
|
1066
1163
|
lightDistance: 15, // ~30% smaller than the other markers' default reach
|
|
1067
1164
|
});
|
|
1165
|
+
addSourceEmitter(ecd, entity, {
|
|
1166
|
+
id: "orbit-worldmode",
|
|
1167
|
+
clipPath: ORBIT_CLIP,
|
|
1168
|
+
distanceMin: ORBIT_DIST_MIN,
|
|
1169
|
+
distanceMax: ORBIT_DIST_MAX,
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1068
1172
|
const mover = new PrototypeMover();
|
|
1069
1173
|
mover.kind = "orbit";
|
|
1070
1174
|
mover.cx = ORBIT_CX;
|
|
@@ -1072,42 +1176,22 @@ function buildSources(ecd) {
|
|
|
1072
1176
|
mover.radius = ORBIT_RADIUS;
|
|
1073
1177
|
mover.height = ORBIT_HEIGHT;
|
|
1074
1178
|
mover.speed = ORBIT_SPEED;
|
|
1075
|
-
ecd.addComponentToEntity(
|
|
1179
|
+
ecd.addComponentToEntity(entity, mover); // PrototypeMotionSystem links it via (PrototypeMover, Transform)
|
|
1076
1180
|
}
|
|
1077
1181
|
|
|
1078
1182
|
/**
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1183
|
+
* Build a source's visual: a small emissive marker sphere + a co-located point light (its colour taken from the
|
|
1184
|
+
* marker's emissive tint, so each source casts a coloured glow into its room). No {@link AudioEmitter} — that is
|
|
1185
|
+
* attached separately ({@link addSourceEmitter}), so a static marker can be baked into the lightmap while its
|
|
1186
|
+
* audio waits for the first click. Not an acoustic occluder (no {@link AcousticBody}).
|
|
1082
1187
|
*
|
|
1083
1188
|
* @param {EntityComponentDataset} ecd
|
|
1084
|
-
* @param {{
|
|
1085
|
-
*
|
|
1086
|
-
* @returns {
|
|
1189
|
+
* @param {{position:Vector3, markerColor:number, markerEmissive:number, lightIntensity?:number,
|
|
1190
|
+
* lightDistance?:number}} p
|
|
1191
|
+
* @returns {number} the spawned entity id (so an emitter / mover can be attached later)
|
|
1087
1192
|
*/
|
|
1088
|
-
function
|
|
1089
|
-
|
|
1090
|
-
const event = EventDescription.from(
|
|
1091
|
-
id,
|
|
1092
|
-
SampleAudioClip.from(clipPath, { loop: true }),
|
|
1093
|
-
{
|
|
1094
|
-
is3D: true,
|
|
1095
|
-
distanceMin,
|
|
1096
|
-
distanceMax,
|
|
1097
|
-
// Physically-based (sound-pressure-fitted) rolloff, sampled across [min, max] in metres: full
|
|
1098
|
-
// volume within distanceMin, a natural log-ish falloff to silence at distanceMax. Reuses the
|
|
1099
|
-
// engine's own falloff + curve builder rather than a hand-rolled line.
|
|
1100
|
-
attenuation: buildAttenuationCurve(distanceMin, distanceMax, interpolate_irradiance_smith),
|
|
1101
|
-
},
|
|
1102
|
-
);
|
|
1103
|
-
|
|
1104
|
-
const emitter = new AudioEmitter();
|
|
1105
|
-
emitter.event = event;
|
|
1106
|
-
emitter.acoustic = true; // occlusion / transmission / pathing
|
|
1107
|
-
emitter.sourceRadius = 0.3; // a little volume so occlusion fades in/out rather than popping
|
|
1108
|
-
emitter.autoplay = true;
|
|
1109
|
-
emitter.volume.set(1);
|
|
1110
|
-
|
|
1193
|
+
function buildSourceMarker(ecd, { position, markerColor, markerEmissive,
|
|
1194
|
+
lightIntensity = SOURCE_LIGHT_INTENSITY, lightDistance = SOURCE_LIGHT_DISTANCE }) {
|
|
1111
1195
|
const markerGeom = new SphereGeometry(0.3, 16, 16);
|
|
1112
1196
|
const markerMat = litMaterial({
|
|
1113
1197
|
color: markerColor,
|
|
@@ -1119,8 +1203,6 @@ function spawnAudioSource(ecd, { id, clipPath, position, distanceMin, distanceMa
|
|
|
1119
1203
|
sg.setFlag(ShadedGeometryFlags.Visible);
|
|
1120
1204
|
sg.setFlag(ShadedGeometryFlags.CastShadow);
|
|
1121
1205
|
|
|
1122
|
-
// A point light co-located with the marker — the markers were already emissive, this lets each one cast a
|
|
1123
|
-
// coloured glow into its room (the light colour is taken from the marker's emissive tint).
|
|
1124
1206
|
const light = new Light();
|
|
1125
1207
|
light.type.set(Light.Type.POINT);
|
|
1126
1208
|
light.color.setRGBUint8((markerEmissive >> 16) & 0xff, (markerEmissive >> 8) & 0xff, markerEmissive & 0xff);
|
|
@@ -1131,7 +1213,6 @@ function spawnAudioSource(ecd, { id, clipPath, position, distanceMin, distanceMa
|
|
|
1131
1213
|
transform.position.copy(position);
|
|
1132
1214
|
|
|
1133
1215
|
const eb = new Entity()
|
|
1134
|
-
.add(emitter)
|
|
1135
1216
|
.add(sg)
|
|
1136
1217
|
.add(light)
|
|
1137
1218
|
.add(Tag.fromJSON(["AudioSource"]))
|
|
@@ -1139,7 +1220,43 @@ function spawnAudioSource(ecd, { id, clipPath, position, distanceMin, distanceMa
|
|
|
1139
1220
|
.add(transform);
|
|
1140
1221
|
eb.build(ecd);
|
|
1141
1222
|
|
|
1142
|
-
return
|
|
1223
|
+
return eb.id;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Attach a 3D looping, acoustic, autoplay {@link AudioEmitter} to a pre-built source marker entity. Done on the
|
|
1228
|
+
* first click, once the context has resumed, so the emitter links (and autoplays) on a RUNNING context — the
|
|
1229
|
+
* autoplay-policy-safe path. It shares the marker's Transform, so it sounds from the marker and tracks it if a
|
|
1230
|
+
* mover drives it.
|
|
1231
|
+
*
|
|
1232
|
+
* @param {EntityComponentDataset} ecd
|
|
1233
|
+
* @param {number} entity the marker built by {@link buildSourceMarker}
|
|
1234
|
+
* @param {{id:string, clipPath:string, distanceMin:number, distanceMax:number}} p
|
|
1235
|
+
*/
|
|
1236
|
+
function addSourceEmitter(ecd, entity, { id, clipPath, distanceMin, distanceMax }) {
|
|
1237
|
+
const event = EventDescription.from(
|
|
1238
|
+
id,
|
|
1239
|
+
SampleAudioClip.from(clipPath, { loop: true }),
|
|
1240
|
+
{
|
|
1241
|
+
is3D: true,
|
|
1242
|
+
distanceMin,
|
|
1243
|
+
distanceMax,
|
|
1244
|
+
// Physically-based (sound-pressure-fitted) rolloff, sampled across [min, max] in metres: full
|
|
1245
|
+
// volume within distanceMin, a natural log-ish falloff to silence at distanceMax. Reuses the
|
|
1246
|
+
// engine's own falloff + curve builder rather than a hand-rolled line.
|
|
1247
|
+
attenuation: buildAttenuationCurve(distanceMin, distanceMax, interpolate_irradiance_smith),
|
|
1248
|
+
},
|
|
1249
|
+
);
|
|
1250
|
+
|
|
1251
|
+
const emitter = new AudioEmitter();
|
|
1252
|
+
emitter.event = event;
|
|
1253
|
+
emitter.acoustic = true; // occlusion / transmission / pathing
|
|
1254
|
+
emitter.sourceRadius = 0.3; // a little volume so occlusion fades in/out rather than popping
|
|
1255
|
+
emitter.autoplay = true;
|
|
1256
|
+
emitter.volume.set(1);
|
|
1257
|
+
|
|
1258
|
+
// (AudioEmitter, Transform) completes on this add → AudioEmitterSystem links it (and autoplays) immediately.
|
|
1259
|
+
ecd.addComponentToEntity(entity, emitter);
|
|
1143
1260
|
}
|
|
1144
1261
|
|
|
1145
1262
|
/**
|
|
@@ -1311,15 +1428,16 @@ function buildInputBindings(ecd, player, motion) {
|
|
|
1311
1428
|
* Wire the canvas click to (a) start audio and (b) capture the mouse.
|
|
1312
1429
|
*
|
|
1313
1430
|
* The autoplay policy requires a user gesture before audio: the engine creates the context suspended and
|
|
1314
|
-
* starts ticking immediately, so we must not let
|
|
1315
|
-
*
|
|
1316
|
-
* `playEvent` lands on a running context (no autoplay
|
|
1317
|
-
* ESC (browser default) releases it.
|
|
1431
|
+
* starts ticking immediately, so we must not let a source play before the first click. On that click we resume
|
|
1432
|
+
* the context and — only once `resume()` has actually resolved — start the sources (attach emitters to the
|
|
1433
|
+
* pre-built markers + spawn the orbiter), so their first `playEvent` lands on a running context (no autoplay
|
|
1434
|
+
* warning). Pointer lock is (re)requested every click; ESC (browser default) releases it.
|
|
1318
1435
|
*
|
|
1319
1436
|
* @param {Engine} engine
|
|
1320
1437
|
* @param {EntityComponentDataset} ecd
|
|
1438
|
+
* @param {{entity:number, spec:object}[]} staticSources the static source markers to attach emitters to
|
|
1321
1439
|
*/
|
|
1322
|
-
function setupInteraction(engine, ecd) {
|
|
1440
|
+
function setupInteraction(engine, ecd, staticSources) {
|
|
1323
1441
|
const el = engine.graphics.domElement;
|
|
1324
1442
|
const captureEl = engine.viewStack.el;
|
|
1325
1443
|
|
|
@@ -1328,9 +1446,9 @@ function setupInteraction(engine, ecd) {
|
|
|
1328
1446
|
captureEl.addEventListener("click", () => {
|
|
1329
1447
|
if (!audioStarted) {
|
|
1330
1448
|
audioStarted = true;
|
|
1331
|
-
// resume() returns the context.resume() promise —
|
|
1332
|
-
// first playEvent lands on a running context.
|
|
1333
|
-
engine.sound.resumeContext().then(() =>
|
|
1449
|
+
// resume() returns the context.resume() promise — start the sources (attach emitters to the pre-built
|
|
1450
|
+
// markers + spawn the orbiter) only after it resolves, so the first playEvent lands on a running context.
|
|
1451
|
+
engine.sound.resumeContext().then(() => startSources(ecd, staticSources));
|
|
1334
1452
|
}
|
|
1335
1453
|
|
|
1336
1454
|
if (document.pointerLockElement === el || !el.requestPointerLock) return;
|