@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
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { rgb_to_luminance } from "../../../../core/color/rgb_to_luminance.js";
|
|
2
|
+
import { Ray3 } from "../../../../core/geom/3d/ray/Ray3.js";
|
|
3
|
+
import { ray3_compose_array } from "../../../../core/geom/3d/ray/ray3_compose_array.js";
|
|
4
|
+
import { v3_dot } from "../../../../core/geom/vec3/v3_dot.js";
|
|
5
|
+
import { v3_matrix3_rotate } from "../../../../core/geom/vec3/v3_matrix3_rotate.js";
|
|
6
|
+
import { v3_orthonormal_matrix_from_normal } from "../../../../core/geom/vec3/v3_orthonormal_matrix_from_normal.js";
|
|
7
|
+
import { getBiasedNormalSample } from "../path_tracer/sampling/getBiasedNormalSample.js";
|
|
8
|
+
|
|
9
|
+
const _ray = new Ray3();
|
|
10
|
+
const _normal = new Float32Array(3);
|
|
11
|
+
const _dir = new Float32Array(3);
|
|
12
|
+
const _radiance = new Float32Array(3);
|
|
13
|
+
const _hit = new Float32Array(16);
|
|
14
|
+
const _basis = new Float32Array(9);
|
|
15
|
+
const _tangent = new Float32Array(3);
|
|
16
|
+
const _bitangent = new Float32Array(3);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Estimate the lightmap value at a single surface point in **mixed mode**: the
|
|
20
|
+
* cosine-weighted average incoming radiance — indirect bounces + sky only (direct
|
|
21
|
+
* light is supplied at render time by the realtime lights, not baked).
|
|
22
|
+
*
|
|
23
|
+
* Reuses {@link PathTracer#path_trace} along cosine-weighted hemisphere directions
|
|
24
|
+
* ({@link getBiasedNormalSample}, power 1) — bounced light, emissive surfaces, and
|
|
25
|
+
* the environment. Each texel draws its own independent random directions (no fixed
|
|
26
|
+
* sample set is shared between texels, which would otherwise show as structured
|
|
27
|
+
* bias on flat surfaces).
|
|
28
|
+
*
|
|
29
|
+
* **Supersampling:** each sample's ray ORIGIN is jittered within the texel's world
|
|
30
|
+
* footprint (in the surface tangent plane, magnitude `cfg.supersample × texel`), so
|
|
31
|
+
* a texel straddling a shadow boundary or silhouette averages lit/occluded
|
|
32
|
+
* sub-positions into a soft gradient instead of a hard one-texel line.
|
|
33
|
+
*
|
|
34
|
+
* Also produces two auxiliary signals used by the baker:
|
|
35
|
+
* - the **variance of the mean** (luminance), written to `out[3]`, which drives
|
|
36
|
+
* the variance-guided denoiser;
|
|
37
|
+
* - a **confidence** in [0,1] (the return value): `1 - (fraction of short probes
|
|
38
|
+
* that hit a BACK face)`. Flags only buried/wrong-side points; an enclosed-room
|
|
39
|
+
* floor (front faces all around) stays confident. `cfg.confidence_probes === 0`
|
|
40
|
+
* disables it (confidence 1).
|
|
41
|
+
*
|
|
42
|
+
* The stored radiance is `E / π` (cosine-weighted mean); three.js's lightmap path
|
|
43
|
+
* multiplies it back by `π · albedo / π = albedo`, preserving surface colour.
|
|
44
|
+
*
|
|
45
|
+
* @param {Float32Array|number[]} out 4 channels written: linear r, g, b, luminance variance-of-mean
|
|
46
|
+
* @param {number} px world-space point x (already nudged off the surface)
|
|
47
|
+
* @param {number} py world-space point y
|
|
48
|
+
* @param {number} pz world-space point z
|
|
49
|
+
* @param {number} nx world-space surface normal x (unit)
|
|
50
|
+
* @param {number} ny world-space surface normal y
|
|
51
|
+
* @param {number} nz world-space surface normal z
|
|
52
|
+
* @param {number} texel_world_size world-space size of one lightmap texel at this point
|
|
53
|
+
* @param {PathTracedScene} scene
|
|
54
|
+
* @param {PathTracer} path_tracer
|
|
55
|
+
* @param {{samples:number, max_samples:number, variance_target:number, min_bounce:number, max_bounce:number, confidence_probes:number, inside_probe_texels:number, supersample:number}} cfg
|
|
56
|
+
* `samples` is the minimum count; sampling continues up to `max_samples` while the
|
|
57
|
+
* relative variance-of-mean exceeds `variance_target` (0 = fixed `samples`).
|
|
58
|
+
* @param {function():number} random
|
|
59
|
+
* @returns {number} confidence in [0,1]
|
|
60
|
+
*/
|
|
61
|
+
export function lightmap_gather(
|
|
62
|
+
out,
|
|
63
|
+
px, py, pz,
|
|
64
|
+
nx, ny, nz,
|
|
65
|
+
texel_world_size,
|
|
66
|
+
scene,
|
|
67
|
+
path_tracer,
|
|
68
|
+
cfg,
|
|
69
|
+
random
|
|
70
|
+
) {
|
|
71
|
+
_normal[0] = nx;
|
|
72
|
+
_normal[1] = ny;
|
|
73
|
+
_normal[2] = nz;
|
|
74
|
+
|
|
75
|
+
const min_samples = cfg.samples;
|
|
76
|
+
const max_samples = Math.max(min_samples, cfg.max_samples ?? min_samples);
|
|
77
|
+
const variance_target = cfg.variance_target ?? 0; // relative var-of-mean target; 0 = fixed count
|
|
78
|
+
const min_bounce = cfg.min_bounce;
|
|
79
|
+
const max_bounce = cfg.max_bounce;
|
|
80
|
+
|
|
81
|
+
// surface tangent frame for sub-texel origin jitter (supersampling)
|
|
82
|
+
const jitter = (cfg.supersample ?? 0) * texel_world_size;
|
|
83
|
+
if (jitter > 0) {
|
|
84
|
+
v3_orthonormal_matrix_from_normal(_basis, 0, nx, ny, nz);
|
|
85
|
+
v3_matrix3_rotate(_tangent, 0, 1, 0, 0, _basis);
|
|
86
|
+
v3_matrix3_rotate(_bitangent, 0, 0, 1, 0, _basis);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let r = 0;
|
|
90
|
+
let g = 0;
|
|
91
|
+
let b = 0;
|
|
92
|
+
let lum_sum = 0;
|
|
93
|
+
let lum_sum_sq = 0;
|
|
94
|
+
|
|
95
|
+
// Variance-adaptive sampling: take at least `min_samples`, then keep going
|
|
96
|
+
// while the relative noise of the mean is still above target, up to
|
|
97
|
+
// `max_samples`. Noisy regions (contacts, occlusion edges, high-frequency
|
|
98
|
+
// bounce) naturally draw more samples; smooth sky-lit areas stop early.
|
|
99
|
+
let n = 0;
|
|
100
|
+
let variance_of_mean = 0;
|
|
101
|
+
while (n < max_samples) {
|
|
102
|
+
let ox = px;
|
|
103
|
+
let oy = py;
|
|
104
|
+
let oz = pz;
|
|
105
|
+
|
|
106
|
+
if (jitter > 0) {
|
|
107
|
+
const ju = (random() - 0.5) * jitter;
|
|
108
|
+
const jv = (random() - 0.5) * jitter;
|
|
109
|
+
ox += _tangent[0] * ju + _bitangent[0] * jv;
|
|
110
|
+
oy += _tangent[1] * ju + _bitangent[1] * jv;
|
|
111
|
+
oz += _tangent[2] * ju + _bitangent[2] * jv;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// cosine-weighted hemisphere direction around the surface normal
|
|
115
|
+
getBiasedNormalSample(_dir, 0, _normal, 0, 1, random);
|
|
116
|
+
|
|
117
|
+
ray3_compose_array(_ray, ox, oy, oz, _dir[0], _dir[1], _dir[2]);
|
|
118
|
+
_ray.tMax = Infinity;
|
|
119
|
+
|
|
120
|
+
path_tracer.path_trace(_radiance, _ray, min_bounce, max_bounce, random, scene);
|
|
121
|
+
|
|
122
|
+
r += _radiance[0];
|
|
123
|
+
g += _radiance[1];
|
|
124
|
+
b += _radiance[2];
|
|
125
|
+
|
|
126
|
+
const lum = rgb_to_luminance(_radiance[0], _radiance[1], _radiance[2]);
|
|
127
|
+
lum_sum += lum;
|
|
128
|
+
lum_sum_sq += lum * lum;
|
|
129
|
+
n++;
|
|
130
|
+
|
|
131
|
+
if (n >= min_samples) {
|
|
132
|
+
const mean = lum_sum / n;
|
|
133
|
+
// unbiased variance-of-the-mean: (sample variance)/n = popVar/(n-1).
|
|
134
|
+
// (n > 1 always holds here: min_samples >= 4 in every config.)
|
|
135
|
+
const pop_var = Math.max(0, lum_sum_sq / n - mean * mean);
|
|
136
|
+
variance_of_mean = n > 1 ? pop_var / (n - 1) : 0;
|
|
137
|
+
if (variance_target > 0 && variance_of_mean <= variance_target * (mean * mean + 1e-8)) {
|
|
138
|
+
break; // relative noise low enough
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const inv = 1 / n;
|
|
144
|
+
out[0] = r * inv;
|
|
145
|
+
out[1] = g * inv;
|
|
146
|
+
out[2] = b * inv;
|
|
147
|
+
out[3] = variance_of_mean;
|
|
148
|
+
|
|
149
|
+
// geometric confidence: is the sample point buried (on the wrong side of
|
|
150
|
+
// nearby geometry)? Count short probes whose first hit is a BACK face.
|
|
151
|
+
const probes = cfg.confidence_probes;
|
|
152
|
+
if (probes <= 0) {
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const inside_distance = cfg.inside_probe_texels * texel_world_size;
|
|
157
|
+
let backface = 0;
|
|
158
|
+
for (let p = 0; p < probes; p++) {
|
|
159
|
+
getBiasedNormalSample(_dir, 0, _normal, 0, 1, random);
|
|
160
|
+
ray3_compose_array(_ray, px, py, pz, _dir[0], _dir[1], _dir[2]);
|
|
161
|
+
_ray.tMax = inside_distance;
|
|
162
|
+
if (scene.trace(_hit, _ray) >= 0 && v3_dot(_hit[3], _hit[4], _hit[5], _dir[0], _dir[1], _dir[2]) > 0) {
|
|
163
|
+
backface++;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return 1 - backface / probes;
|
|
168
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rasterize a 2D triangle in integer pixel space, invoking `callback` once per
|
|
3
|
+
* covered texel with the barycentric weights of the three vertices (A, B, C) at
|
|
4
|
+
* the sampled point. The weights are an exact partition of unity (`wA+wB+wC===1`,
|
|
5
|
+
* all `>=0`), so a caller can interpolate any per-vertex attribute directly.
|
|
6
|
+
*
|
|
7
|
+
* Default (center) mode: a texel is covered iff its CENTER lies inside the
|
|
8
|
+
* triangle, sampled at that center.
|
|
9
|
+
*
|
|
10
|
+
* Conservative mode (`conservative === true`): a texel is also covered if its
|
|
11
|
+
* cell overlaps the triangle even though its center is outside (thin features,
|
|
12
|
+
* chart borders). For those, the sample is **clamped to the closest point on the
|
|
13
|
+
* triangle** so the interpolated position/normal stays on the surface — avoiding
|
|
14
|
+
* the dropped-edge-texel black gutters of center-only coverage.
|
|
15
|
+
*
|
|
16
|
+
* Degenerate (zero-area) triangles produce no callbacks.
|
|
17
|
+
*
|
|
18
|
+
* @param {number} ax vertex A x, in pixels
|
|
19
|
+
* @param {number} ay vertex A y, in pixels
|
|
20
|
+
* @param {number} bx vertex B x, in pixels
|
|
21
|
+
* @param {number} by vertex B y, in pixels
|
|
22
|
+
* @param {number} cx vertex C x, in pixels
|
|
23
|
+
* @param {number} cy vertex C y, in pixels
|
|
24
|
+
* @param {number} width raster width (texel centers tested in [0, width))
|
|
25
|
+
* @param {number} height raster height (texel centers tested in [0, height))
|
|
26
|
+
* @param {function(px:number, py:number, wA:number, wB:number, wC:number):void} callback
|
|
27
|
+
* @param {boolean} [conservative] include edge-overlapping texels with a clamped sample (default false)
|
|
28
|
+
*/
|
|
29
|
+
export function lightmap_rasterize_triangle(ax: number, ay: number, bx: number, by: number, cx: number, cy: number, width: number, height: number, callback: any, conservative?: boolean): void;
|
|
30
|
+
//# sourceMappingURL=lightmap_rasterize_triangle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightmap_rasterize_triangle.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.js"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,gDAXW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,SACN,MAAM,UACN,MAAM,gCAEN,OAAO,QAgEjB"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/** Half the diagonal of a unit texel — the conservative overlap reach from a center. */
|
|
2
|
+
const HALF_TEXEL_DIAGONAL = Math.SQRT2 * 0.5;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Closest point to (px,py) on segment (ax,ay)->(bx,by), written to out[0..1].
|
|
6
|
+
*
|
|
7
|
+
* @param {Float32Array|number[]} out
|
|
8
|
+
* @param {number} px
|
|
9
|
+
* @param {number} py
|
|
10
|
+
* @param {number} ax
|
|
11
|
+
* @param {number} ay
|
|
12
|
+
* @param {number} bx
|
|
13
|
+
* @param {number} by
|
|
14
|
+
*/
|
|
15
|
+
function closest_on_segment(out, px, py, ax, ay, bx, by) {
|
|
16
|
+
const ex = bx - ax;
|
|
17
|
+
const ey = by - ay;
|
|
18
|
+
const len2 = ex * ex + ey * ey;
|
|
19
|
+
let t = len2 > 0 ? ((px - ax) * ex + (py - ay) * ey) / len2 : 0;
|
|
20
|
+
if (t < 0) t = 0; else if (t > 1) t = 1;
|
|
21
|
+
out[0] = ax + t * ex;
|
|
22
|
+
out[1] = ay + t * ey;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const _q = new Float32Array(2);
|
|
26
|
+
const _e = new Float32Array(2);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Closest point to (px,py) on the (filled) triangle, written to out[0..1].
|
|
30
|
+
* Assumes the point is outside the triangle (callers test inside first).
|
|
31
|
+
*
|
|
32
|
+
* @param {Float32Array|number[]} out
|
|
33
|
+
*/
|
|
34
|
+
function closest_on_triangle(out, px, py, ax, ay, bx, by, cx, cy) {
|
|
35
|
+
let best_d2 = Infinity;
|
|
36
|
+
|
|
37
|
+
closest_on_segment(_e, px, py, ax, ay, bx, by);
|
|
38
|
+
let dx = px - _e[0], dy = py - _e[1];
|
|
39
|
+
let d2 = dx * dx + dy * dy;
|
|
40
|
+
if (d2 < best_d2) { best_d2 = d2; out[0] = _e[0]; out[1] = _e[1]; }
|
|
41
|
+
|
|
42
|
+
closest_on_segment(_e, px, py, bx, by, cx, cy);
|
|
43
|
+
dx = px - _e[0]; dy = py - _e[1];
|
|
44
|
+
d2 = dx * dx + dy * dy;
|
|
45
|
+
if (d2 < best_d2) { best_d2 = d2; out[0] = _e[0]; out[1] = _e[1]; }
|
|
46
|
+
|
|
47
|
+
closest_on_segment(_e, px, py, cx, cy, ax, ay);
|
|
48
|
+
dx = px - _e[0]; dy = py - _e[1];
|
|
49
|
+
d2 = dx * dx + dy * dy;
|
|
50
|
+
if (d2 < best_d2) { best_d2 = d2; out[0] = _e[0]; out[1] = _e[1]; }
|
|
51
|
+
|
|
52
|
+
return Math.sqrt(best_d2);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Rasterize a 2D triangle in integer pixel space, invoking `callback` once per
|
|
57
|
+
* covered texel with the barycentric weights of the three vertices (A, B, C) at
|
|
58
|
+
* the sampled point. The weights are an exact partition of unity (`wA+wB+wC===1`,
|
|
59
|
+
* all `>=0`), so a caller can interpolate any per-vertex attribute directly.
|
|
60
|
+
*
|
|
61
|
+
* Default (center) mode: a texel is covered iff its CENTER lies inside the
|
|
62
|
+
* triangle, sampled at that center.
|
|
63
|
+
*
|
|
64
|
+
* Conservative mode (`conservative === true`): a texel is also covered if its
|
|
65
|
+
* cell overlaps the triangle even though its center is outside (thin features,
|
|
66
|
+
* chart borders). For those, the sample is **clamped to the closest point on the
|
|
67
|
+
* triangle** so the interpolated position/normal stays on the surface — avoiding
|
|
68
|
+
* the dropped-edge-texel black gutters of center-only coverage.
|
|
69
|
+
*
|
|
70
|
+
* Degenerate (zero-area) triangles produce no callbacks.
|
|
71
|
+
*
|
|
72
|
+
* @param {number} ax vertex A x, in pixels
|
|
73
|
+
* @param {number} ay vertex A y, in pixels
|
|
74
|
+
* @param {number} bx vertex B x, in pixels
|
|
75
|
+
* @param {number} by vertex B y, in pixels
|
|
76
|
+
* @param {number} cx vertex C x, in pixels
|
|
77
|
+
* @param {number} cy vertex C y, in pixels
|
|
78
|
+
* @param {number} width raster width (texel centers tested in [0, width))
|
|
79
|
+
* @param {number} height raster height (texel centers tested in [0, height))
|
|
80
|
+
* @param {function(px:number, py:number, wA:number, wB:number, wC:number):void} callback
|
|
81
|
+
* @param {boolean} [conservative] include edge-overlapping texels with a clamped sample (default false)
|
|
82
|
+
*/
|
|
83
|
+
export function lightmap_rasterize_triangle(ax, ay, bx, by, cx, cy, width, height, callback, conservative = false) {
|
|
84
|
+
// conservative mode reaches one extra texel of overlap, so widen the scan box
|
|
85
|
+
const margin = conservative ? 1 : 0;
|
|
86
|
+
|
|
87
|
+
const min_x = Math.max(0, Math.floor(Math.min(ax, bx, cx)) - margin);
|
|
88
|
+
const max_x = Math.min(width - 1, Math.floor(Math.max(ax, bx, cx)) + margin);
|
|
89
|
+
const min_y = Math.max(0, Math.floor(Math.min(ay, by, cy)) - margin);
|
|
90
|
+
const max_y = Math.min(height - 1, Math.floor(Math.max(ay, by, cy)) + margin);
|
|
91
|
+
|
|
92
|
+
const d = (by - cy) * (ax - cx) + (cx - bx) * (ay - cy);
|
|
93
|
+
|
|
94
|
+
if (d === 0) {
|
|
95
|
+
// degenerate triangle, no area to cover
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const inv_d = 1 / d;
|
|
100
|
+
|
|
101
|
+
for (let py = min_y; py <= max_y; py++) {
|
|
102
|
+
const sy = py + 0.5;
|
|
103
|
+
|
|
104
|
+
for (let px = min_x; px <= max_x; px++) {
|
|
105
|
+
const sx = px + 0.5;
|
|
106
|
+
|
|
107
|
+
const wA = ((by - cy) * (sx - cx) + (cx - bx) * (sy - cy)) * inv_d;
|
|
108
|
+
const wB = ((cy - ay) * (sx - cx) + (ax - cx) * (sy - cy)) * inv_d;
|
|
109
|
+
const wC = 1 - wA - wB;
|
|
110
|
+
|
|
111
|
+
if (wA >= 0 && wB >= 0 && wC >= 0) {
|
|
112
|
+
callback(px, py, wA, wB, wC);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!conservative) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// center is outside: keep the texel only if its cell overlaps the
|
|
121
|
+
// triangle, sampling the clamped (on-triangle) closest point
|
|
122
|
+
const dist = closest_on_triangle(_q, sx, sy, ax, ay, bx, by, cx, cy);
|
|
123
|
+
if (dist > HALF_TEXEL_DIAGONAL) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const qx = _q[0];
|
|
128
|
+
const qy = _q[1];
|
|
129
|
+
let cwA = ((by - cy) * (qx - cx) + (cx - bx) * (qy - cy)) * inv_d;
|
|
130
|
+
let cwB = ((cy - ay) * (qx - cx) + (ax - cx) * (qy - cy)) * inv_d;
|
|
131
|
+
// clamp tiny negative fp drift so the weights stay a valid convex combo
|
|
132
|
+
if (cwA < 0) cwA = 0;
|
|
133
|
+
if (cwB < 0) cwB = 0;
|
|
134
|
+
let cwC = 1 - cwA - cwB;
|
|
135
|
+
if (cwC < 0) {
|
|
136
|
+
cwC = 0;
|
|
137
|
+
const s = cwA + cwB;
|
|
138
|
+
cwA /= s;
|
|
139
|
+
cwB /= s;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
callback(px, py, cwA, cwB, cwC);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduce lighting discontinuities across UV seams by blending the two atlas-space
|
|
3
|
+
* sides of each shared 3D edge toward each other (a CPU take on the Bakery
|
|
4
|
+
* line-blend seam fix — far simpler than least-squares stitching).
|
|
5
|
+
*
|
|
6
|
+
* A seam is a 3D edge that two charts both keep on their boundary: two
|
|
7
|
+
* {@link Chart#boundary_edges} with the same pair of SOURCE vertices but different
|
|
8
|
+
* UVs. For each such pair we walk both edges in lockstep (parameter t in [0,1],
|
|
9
|
+
* aligned by source-vertex order) at ~half-texel steps and average the covered
|
|
10
|
+
* texels on both sides, repeated a few times so the match propagates.
|
|
11
|
+
*
|
|
12
|
+
* **Only smooth seams are blended.** A shared chart-boundary edge can also be a
|
|
13
|
+
* hard feature crease (a cube's top face meets its side face at 90°), where the
|
|
14
|
+
* two sides have genuinely different lighting and MUST NOT be merged — blending
|
|
15
|
+
* there leaks the dark side into the bright one. So a pair of texels is averaged
|
|
16
|
+
* only when their world normals agree (`dot >= normal_threshold`); creases, whose
|
|
17
|
+
* normals are perpendicular, are left alone. This is the normal-continuity test
|
|
18
|
+
* the Bakery seam fix uses.
|
|
19
|
+
*
|
|
20
|
+
* Seams only ever occur within a single mesh's unwrap (different meshes don't share
|
|
21
|
+
* edges), so `chart_groups` is one chart list per mesh.
|
|
22
|
+
*
|
|
23
|
+
* @param {Float32Array} data atlas pixels, row-major, stride `channels`
|
|
24
|
+
* @param {Float32Array} normals per-texel world normal (3 per texel), length width*height*3
|
|
25
|
+
* @param {Uint8Array} coverage per-texel coverage (1 = valid), length width*height
|
|
26
|
+
* @param {number} width
|
|
27
|
+
* @param {number} height
|
|
28
|
+
* @param {number} channels values per texel
|
|
29
|
+
* @param {Chart[][]} chart_groups one packed-chart list per mesh
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
* @param {number} [options.iterations] blend passes (default 4)
|
|
32
|
+
* @param {number} [options.normal_threshold] min normal dot to treat an edge as a smooth seam (default 0.9)
|
|
33
|
+
*/
|
|
34
|
+
export function lightmap_seam_fix(data: Float32Array, normals: Float32Array, coverage: Uint8Array, width: number, height: number, channels: number, chart_groups: Chart[][], options?: {
|
|
35
|
+
iterations?: number;
|
|
36
|
+
normal_threshold?: number;
|
|
37
|
+
}): void;
|
|
38
|
+
//# sourceMappingURL=lightmap_seam_fix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightmap_seam_fix.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/lightmap/lightmap_seam_fix.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wCAXW,YAAY,WACZ,YAAY,YACZ,UAAU,SACV,MAAM,UACN,MAAM,YACN,MAAM,gBACN,OAAO,EAAE;IAEQ,UAAU,GAA3B,MAAM;IACW,gBAAgB,GAAjC,MAAM;SAgBhB"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduce lighting discontinuities across UV seams by blending the two atlas-space
|
|
3
|
+
* sides of each shared 3D edge toward each other (a CPU take on the Bakery
|
|
4
|
+
* line-blend seam fix — far simpler than least-squares stitching).
|
|
5
|
+
*
|
|
6
|
+
* A seam is a 3D edge that two charts both keep on their boundary: two
|
|
7
|
+
* {@link Chart#boundary_edges} with the same pair of SOURCE vertices but different
|
|
8
|
+
* UVs. For each such pair we walk both edges in lockstep (parameter t in [0,1],
|
|
9
|
+
* aligned by source-vertex order) at ~half-texel steps and average the covered
|
|
10
|
+
* texels on both sides, repeated a few times so the match propagates.
|
|
11
|
+
*
|
|
12
|
+
* **Only smooth seams are blended.** A shared chart-boundary edge can also be a
|
|
13
|
+
* hard feature crease (a cube's top face meets its side face at 90°), where the
|
|
14
|
+
* two sides have genuinely different lighting and MUST NOT be merged — blending
|
|
15
|
+
* there leaks the dark side into the bright one. So a pair of texels is averaged
|
|
16
|
+
* only when their world normals agree (`dot >= normal_threshold`); creases, whose
|
|
17
|
+
* normals are perpendicular, are left alone. This is the normal-continuity test
|
|
18
|
+
* the Bakery seam fix uses.
|
|
19
|
+
*
|
|
20
|
+
* Seams only ever occur within a single mesh's unwrap (different meshes don't share
|
|
21
|
+
* edges), so `chart_groups` is one chart list per mesh.
|
|
22
|
+
*
|
|
23
|
+
* @param {Float32Array} data atlas pixels, row-major, stride `channels`
|
|
24
|
+
* @param {Float32Array} normals per-texel world normal (3 per texel), length width*height*3
|
|
25
|
+
* @param {Uint8Array} coverage per-texel coverage (1 = valid), length width*height
|
|
26
|
+
* @param {number} width
|
|
27
|
+
* @param {number} height
|
|
28
|
+
* @param {number} channels values per texel
|
|
29
|
+
* @param {Chart[][]} chart_groups one packed-chart list per mesh
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
* @param {number} [options.iterations] blend passes (default 4)
|
|
32
|
+
* @param {number} [options.normal_threshold] min normal dot to treat an edge as a smooth seam (default 0.9)
|
|
33
|
+
*/
|
|
34
|
+
export function lightmap_seam_fix(data, normals, coverage, width, height, channels, chart_groups, options = {}) {
|
|
35
|
+
const iterations = options.iterations ?? 4;
|
|
36
|
+
const normal_threshold = options.normal_threshold ?? 0.9;
|
|
37
|
+
|
|
38
|
+
const seams = collect_seams(chart_groups);
|
|
39
|
+
if (seams.length === 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (let iter = 0; iter < iterations; iter++) {
|
|
44
|
+
for (let s = 0; s < seams.length; s++) {
|
|
45
|
+
blend_seam(data, normals, coverage, width, height, channels, seams[s], normal_threshold);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {Chart[][]} chart_groups
|
|
52
|
+
* @returns {Array<{au0:number,av0:number,au1:number,av1:number,bu0:number,bv0:number,bu1:number,bv1:number}>}
|
|
53
|
+
*/
|
|
54
|
+
function collect_seams(chart_groups) {
|
|
55
|
+
const seams = [];
|
|
56
|
+
|
|
57
|
+
for (let g = 0; g < chart_groups.length; g++) {
|
|
58
|
+
const charts = chart_groups[g];
|
|
59
|
+
const by_edge = new Map();
|
|
60
|
+
|
|
61
|
+
for (let ci = 0; ci < charts.length; ci++) {
|
|
62
|
+
const chart = charts[ci];
|
|
63
|
+
const be = chart.boundary_edges;
|
|
64
|
+
const vol = chart.vertex_of_local;
|
|
65
|
+
const uv = chart.uv;
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < be.length; i += 2) {
|
|
68
|
+
const lv0 = be[i];
|
|
69
|
+
const lv1 = be[i + 1];
|
|
70
|
+
let o0 = vol[lv0];
|
|
71
|
+
let o1 = vol[lv1];
|
|
72
|
+
let u0 = uv[lv0 * 2], v0 = uv[lv0 * 2 + 1];
|
|
73
|
+
let u1 = uv[lv1 * 2], v1 = uv[lv1 * 2 + 1];
|
|
74
|
+
|
|
75
|
+
// orient endpoints by source-vertex id so both sides align in t
|
|
76
|
+
if (o0 > o1) {
|
|
77
|
+
const to = o0; o0 = o1; o1 = to;
|
|
78
|
+
const tu = u0; u0 = u1; u1 = tu;
|
|
79
|
+
const tv = v0; v0 = v1; v1 = tv;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const key = o0 + "_" + o1;
|
|
83
|
+
const existing = by_edge.get(key);
|
|
84
|
+
const edge = { u0, v0, u1, v1 };
|
|
85
|
+
if (existing === undefined) {
|
|
86
|
+
by_edge.set(key, edge);
|
|
87
|
+
} else {
|
|
88
|
+
// a second occurrence of this edge -> a seam between two charts
|
|
89
|
+
seams.push({
|
|
90
|
+
au0: existing.u0, av0: existing.v0, au1: existing.u1, av1: existing.v1,
|
|
91
|
+
bu0: edge.u0, bv0: edge.v0, bu1: edge.u1, bv1: edge.v1,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return seams;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Average the covered texels along both sides of one seam edge — but only where
|
|
103
|
+
* the two sides are the same continuous surface (normals agree); hard creases are
|
|
104
|
+
* skipped.
|
|
105
|
+
*/
|
|
106
|
+
function blend_seam(data, normals, coverage, width, height, channels, seam, normal_threshold) {
|
|
107
|
+
const a_len = Math.hypot((seam.au1 - seam.au0) * width, (seam.av1 - seam.av0) * height);
|
|
108
|
+
const b_len = Math.hypot((seam.bu1 - seam.bu0) * width, (seam.bv1 - seam.bv0) * height);
|
|
109
|
+
const steps = Math.max(2, Math.ceil(Math.max(a_len, b_len) * 2)); // ~half-texel steps
|
|
110
|
+
|
|
111
|
+
for (let i = 0; i <= steps; i++) {
|
|
112
|
+
const t = i / steps;
|
|
113
|
+
|
|
114
|
+
const ax = clamp_index((seam.au0 + (seam.au1 - seam.au0) * t) * width, width);
|
|
115
|
+
const ay = clamp_index((seam.av0 + (seam.av1 - seam.av0) * t) * height, height);
|
|
116
|
+
const bx = clamp_index((seam.bu0 + (seam.bu1 - seam.bu0) * t) * width, width);
|
|
117
|
+
const by = clamp_index((seam.bv0 + (seam.bv1 - seam.bv0) * t) * height, height);
|
|
118
|
+
|
|
119
|
+
const pa = ay * width + ax;
|
|
120
|
+
const pb = by * width + bx;
|
|
121
|
+
if (coverage[pa] === 0 || coverage[pb] === 0) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// only blend a continuous surface, never a hard feature crease
|
|
126
|
+
const na = pa * 3;
|
|
127
|
+
const nb = pb * 3;
|
|
128
|
+
const dot = normals[na] * normals[nb] + normals[na + 1] * normals[nb + 1] + normals[na + 2] * normals[nb + 2];
|
|
129
|
+
if (dot < normal_threshold) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const base_a = pa * channels;
|
|
134
|
+
const base_b = pb * channels;
|
|
135
|
+
for (let c = 0; c < channels; c++) {
|
|
136
|
+
const avg = (data[base_a + c] + data[base_b + c]) * 0.5;
|
|
137
|
+
data[base_a + c] = avg;
|
|
138
|
+
data[base_b + c] = avg;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {number} coord pixel coordinate (may be fractional / out of range)
|
|
145
|
+
* @param {number} size
|
|
146
|
+
* @returns {number} integer texel index in [0, size)
|
|
147
|
+
*/
|
|
148
|
+
function clamp_index(coord, size) {
|
|
149
|
+
let v = Math.floor(coord);
|
|
150
|
+
if (v < 0) v = 0; else if (v >= size) v = size - 1;
|
|
151
|
+
return v;
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototypeLightmapBaker.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.js"],"names":[],"mappings":""}
|