@woosh/meep-engine 2.156.0 → 2.157.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/README.md +1 -3
- package/editor/view/ecs/components/common/AutoCanvasView.js +100 -53
- package/editor/view/ecs/components/common/TextController.js +59 -0
- package/editor/view/node-graph/NodeGraphCamera.js +90 -0
- package/editor/view/node-graph/NodeGraphEditorView.js +121 -22
- package/editor/view/node-graph/NodeGraphSelection.js +89 -0
- package/editor/view/node-graph/NodeGraphView.js +669 -453
- package/editor/view/node-graph/NodeView.js +211 -135
- package/editor/view/node-graph/actions/ConnectionCreateAction.js +53 -0
- package/editor/view/node-graph/actions/ConnectionDeleteAction.js +36 -0
- package/editor/view/node-graph/actions/NodeDeleteAction.js +88 -0
- package/editor/view/node-graph/actions/NodeParameterSetAction.js +52 -0
- package/editor/view/node-graph/actions/NodesMoveAction.js +41 -0
- package/editor/view/node-graph/actions/SelectionSetAction.js +60 -0
- package/editor/view/node-graph/connection_wire_geometry.js +107 -0
- package/package.json +1 -1
- package/samples/generation/SampleGenerator0.js +8 -1
- package/src/core/binary/reinterpret_float32_as_uint32.d.ts +7 -0
- package/src/core/binary/reinterpret_float32_as_uint32.d.ts.map +1 -0
- package/src/core/binary/reinterpret_float32_as_uint32.js +13 -0
- package/src/core/binary/reinterpret_uint32_as_float32.d.ts +7 -0
- package/src/core/binary/reinterpret_uint32_as_float32.d.ts.map +1 -0
- package/src/core/binary/reinterpret_uint32_as_float32.js +14 -0
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.js +1 -3
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts +12 -0
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts.map +1 -0
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.js +92 -0
- package/src/core/bvh8/BVH8.d.ts +127 -0
- package/src/core/bvh8/BVH8.d.ts.map +1 -0
- package/src/core/bvh8/BVH8.js +436 -0
- package/src/core/bvh8/NOTES.md +63 -0
- package/src/core/bvh8/build/BVH8Converter.d.ts +59 -0
- package/src/core/bvh8/build/BVH8Converter.d.ts.map +1 -0
- package/src/core/bvh8/build/BVH8Converter.js +588 -0
- package/src/core/bvh8/build/NodeProxy.d.ts +66 -0
- package/src/core/bvh8/build/NodeProxy.d.ts.map +1 -0
- package/src/core/bvh8/build/NodeProxy.js +308 -0
- package/src/core/bvh8/build/TriangleCluster.d.ts +29 -0
- package/src/core/bvh8/build/TriangleCluster.d.ts.map +1 -0
- package/src/core/bvh8/build/TriangleCluster.js +123 -0
- package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts +8 -0
- package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts.map +1 -0
- package/src/core/bvh8/build/aabb3_compute_merge_cost.js +29 -0
- package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts +10 -0
- package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts.map +1 -0
- package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +18 -0
- package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts +10 -0
- package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts.map +1 -0
- package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -0
- package/src/core/bvh8/build/bvh8_from_proxy.d.ts +9 -0
- package/src/core/bvh8/build/bvh8_from_proxy.d.ts.map +1 -0
- package/src/core/bvh8/build/bvh8_from_proxy.js +256 -0
- package/src/core/bvh8/build/byte.d.ts +7 -0
- package/src/core/bvh8/build/byte.d.ts.map +1 -0
- package/src/core/bvh8/build/byte.js +10 -0
- package/src/core/bvh8/build/encode_bounds_e.d.ts +9 -0
- package/src/core/bvh8/build/encode_bounds_e.d.ts.map +1 -0
- package/src/core/bvh8/build/encode_bounds_e.js +12 -0
- package/src/core/bvh8/bvh8_convert_to_dot.d.ts +11 -0
- package/src/core/bvh8/bvh8_convert_to_dot.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_convert_to_dot.js +133 -0
- package/src/core/bvh8/bvh8_count_primitives.d.ts +22 -0
- package/src/core/bvh8/bvh8_count_primitives.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_count_primitives.js +98 -0
- package/src/core/bvh8/bvh8_geometry_validate.d.ts +16 -0
- package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_geometry_validate.js +149 -0
- package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts +16 -0
- package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_geometry_validate_indirect.js +177 -0
- package/src/core/bvh8/bvh8_get_node_bounds.d.ts +9 -0
- package/src/core/bvh8/bvh8_get_node_bounds.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_get_node_bounds.js +35 -0
- package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts +10 -0
- package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_get_node_child_bounds.js +53 -0
- package/src/core/bvh8/bvh8_node_child_surface_area.d.ts +9 -0
- package/src/core/bvh8/bvh8_node_child_surface_area.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -0
- package/src/core/bvh8/bvh8_node_count_triangles.d.ts +8 -0
- package/src/core/bvh8/bvh8_node_count_triangles.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_node_count_triangles.js +28 -0
- package/src/core/bvh8/bvh8_quality.d.ts +8 -0
- package/src/core/bvh8/bvh8_quality.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_quality.js +73 -0
- package/src/core/bvh8/bvh8_validate_structure.d.ts +15 -0
- package/src/core/bvh8/bvh8_validate_structure.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_validate_structure.js +87 -0
- package/src/core/collection/Uint32MinHeap.d.ts +56 -0
- package/src/core/collection/Uint32MinHeap.d.ts.map +1 -0
- package/src/core/collection/Uint32MinHeap.js +109 -0
- package/src/core/collection/list/FilteredListProjection.js +1 -1
- package/src/{engine/physics/island → core/collection/union-find}/union_find.d.ts +8 -5
- package/src/core/collection/union-find/union_find.d.ts.map +1 -0
- package/src/{engine/physics/island → core/collection/union-find}/union_find.js +8 -5
- package/src/core/dom/isImageBitmap.d.ts +7 -0
- package/src/core/dom/isImageBitmap.d.ts.map +1 -0
- package/src/core/dom/isImageBitmap.js +12 -0
- package/src/core/function/frameThrottle.d.ts +8 -0
- package/src/core/function/frameThrottle.d.ts.map +1 -0
- package/src/core/function/frameThrottle.js +23 -0
- package/src/{engine/physics/narrowphase/clip_against_axis_uv.d.ts → core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts} +3 -3
- package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts.map +1 -0
- package/src/{engine/physics/narrowphase/clip_against_axis_uv.js → core/geom/2d/polygon/polygon2_clip_axis_halfplane.js} +51 -51
- package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts → core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts} +9 -7
- package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts.map +1 -0
- package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.js → core/geom/3d/aabb/aabb3_transform_oriented_inverse.js} +9 -7
- package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts +12 -0
- package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts.map +1 -0
- package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +46 -0
- package/src/core/geom/3d/box/box3_projected_half_extent.d.ts +28 -0
- package/src/core/geom/3d/box/box3_projected_half_extent.d.ts.map +1 -0
- package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -0
- package/src/core/geom/3d/frustum/read_cluster_frustum_corners.js +1 -1
- package/src/core/geom/3d/frustum/read_frustum_corner.d.ts +9 -0
- package/src/core/geom/3d/frustum/read_frustum_corner.d.ts.map +1 -0
- package/src/core/geom/3d/frustum/read_frustum_corner.js +14 -0
- package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -0
- package/src/{engine/physics → core/geom/3d}/gjk/gjk.js +430 -372
- package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.d.ts +8 -5
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -0
- package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.js +520 -544
- package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.d.ts +5 -4
- package/src/core/geom/3d/gjk/minkowski_support.d.ts.map +1 -0
- package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.js +71 -70
- package/src/{engine/physics → core/geom/3d}/gjk/mpr.d.ts +3 -3
- package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -0
- package/src/{engine/physics → core/geom/3d}/gjk/mpr.js +368 -362
- package/src/{engine/physics/integration/quat_integrate.d.ts → core/geom/3d/quaternion/quat3_integrate.d.ts} +2 -2
- package/src/core/geom/3d/quaternion/quat3_integrate.d.ts.map +1 -0
- package/src/{engine/physics/integration/quat_integrate.js → core/geom/3d/quaternion/quat3_integrate.js} +1 -1
- package/src/{engine/physics/narrowphase/PosedShape.d.ts → core/geom/3d/shape/PosedShape3D.d.ts} +9 -8
- package/src/{engine/physics/narrowphase/PosedShape.d.ts.map → core/geom/3d/shape/PosedShape3D.d.ts.map} +1 -1
- package/src/{engine/physics/narrowphase/PosedShape.js → core/geom/3d/shape/PosedShape3D.js} +10 -9
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +15 -11
- package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +1 -1
- package/src/core/geom/vec3/v3_quat3_apply_inverse.js +1 -1
- package/src/core/math/complex/complex_add.d.ts +1 -1
- package/src/core/math/complex/complex_add.d.ts.map +1 -1
- package/src/core/math/complex/complex_add.js +12 -3
- package/src/core/math/complex/complex_div.d.ts +1 -1
- package/src/core/math/complex/complex_div.d.ts.map +1 -1
- package/src/core/math/complex/complex_div.js +11 -4
- package/src/core/math/complex/complex_mul.d.ts +1 -1
- package/src/core/math/complex/complex_mul.d.ts.map +1 -1
- package/src/core/math/complex/complex_mul.js +10 -3
- package/src/core/math/complex/complex_sub.d.ts +1 -1
- package/src/core/math/complex/complex_sub.d.ts.map +1 -1
- package/src/core/math/complex/complex_sub.js +12 -3
- package/src/{engine/physics/fluid/solver/optimal_sor_omega.d.ts → core/math/linalg/sor_optimal_omega.d.ts} +4 -3
- package/src/core/math/linalg/sor_optimal_omega.d.ts.map +1 -0
- package/src/{engine/physics/fluid/solver/optimal_sor_omega.js → core/math/linalg/sor_optimal_omega.js} +4 -3
- package/src/core/math/lookup/ParameterLookupTable.d.ts +123 -0
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -0
- package/src/core/math/lookup/ParameterLookupTable.js +495 -0
- package/src/core/math/lookup/ParameterLookupTableFlags.d.ts +5 -0
- package/src/core/math/lookup/ParameterLookupTableFlags.d.ts.map +1 -0
- package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -0
- package/src/core/math/physics/kinematics/computeInterceptPoint.d.ts.map +1 -0
- package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.js +79 -79
- package/src/core/math/physics/mie/ri_air.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_air.js +1 -3
- package/src/core/math/physics/mie/ri_ammonium_sulfate.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_ammonium_sulfate.js +1 -3
- package/src/core/math/physics/mie/ri_brine.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_brine.js +1 -3
- package/src/core/math/physics/mie/ri_dust.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_dust.js +1 -3
- package/src/core/math/physics/mie/ri_pollen.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_pollen.js +1 -3
- package/src/core/math/physics/mie/ri_smoke.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_smoke.js +1 -3
- package/src/core/math/physics/mie/ri_soot.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_soot.js +1 -3
- package/src/core/math/physics/mie/ri_water.d.ts.map +1 -1
- package/src/core/math/physics/mie/ri_water.js +1 -3
- package/src/core/math/random/random_pick_weighted_index.d.ts +10 -0
- package/src/core/math/random/random_pick_weighted_index.d.ts.map +1 -0
- package/src/core/math/random/random_pick_weighted_index.js +26 -0
- package/src/core/model/node-graph/NodeGraph.d.ts +9 -0
- package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
- package/src/core/model/node-graph/NodeGraph.js +38 -0
- package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts +23 -0
- package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/NodeGraphVisualData.js +54 -0
- package/src/core/path/convertPathToURL.d.ts +9 -0
- package/src/core/path/convertPathToURL.d.ts.map +1 -0
- package/src/core/path/convertPathToURL.js +107 -0
- package/src/core/process/worker/WorkerBuilder.js +1 -1
- package/src/core/process/worker/extractTransferables.js +1 -1
- package/src/engine/animation/curve/draw/build_tangent_editor.d.ts.map +1 -1
- package/src/engine/animation/curve/draw/build_tangent_editor.js +8 -1
- package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.d.ts.map +1 -1
- package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.js +11 -5
- package/src/engine/asset/Asset.d.ts.map +1 -1
- package/src/engine/asset/Asset.js +16 -6
- package/src/engine/asset/AssetManager.d.ts +61 -52
- package/src/engine/asset/AssetManager.d.ts.map +1 -1
- package/src/engine/asset/AssetManager.js +1411 -1045
- package/src/engine/asset/AssetRequest.d.ts +1 -1
- package/src/engine/asset/AssetRequest.d.ts.map +1 -1
- package/src/engine/asset/AssetRequest.js +1 -1
- package/src/engine/asset/AssetRequestScope.d.ts.map +1 -1
- package/src/engine/asset/AssetRequestScope.js +7 -0
- package/src/engine/asset/PendingAsset.d.ts +32 -1
- package/src/engine/asset/PendingAsset.d.ts.map +1 -1
- package/src/engine/asset/PendingAsset.js +108 -61
- package/src/engine/asset/loaders/ArrayBufferLoader.js +2 -2
- package/src/engine/asset/loaders/AssetLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/AssetLoader.js +19 -2
- package/src/engine/asset/loaders/GLTFAssetLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/GLTFAssetLoader.js +123 -114
- package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts +1 -1
- package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/JavascriptAssetLoader.js +31 -47
- package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
- package/src/engine/asset/loaders/SVGAssetLoader.js +2 -2
- package/src/engine/asset/loaders/SoundAssetLoader.js +1 -1
- package/src/engine/asset/loaders/TextAssetLoader.js +2 -2
- package/src/{core → engine/asset/loaders}/font/FontAsset.d.ts +1 -1
- package/src/engine/asset/loaders/font/FontAsset.d.ts.map +1 -0
- package/src/{core → engine/asset/loaders}/font/FontAsset.js +21 -21
- package/src/{core → engine/asset/loaders}/font/FontAssetLoader.d.ts +1 -1
- package/src/engine/asset/loaders/font/FontAssetLoader.d.ts.map +1 -0
- package/src/{core → engine/asset/loaders}/font/FontAssetLoader.js +20 -20
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -20
- package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/texture/TextureAssetLoader.js +8 -2
- package/src/engine/asset/preloader/AssetPreloader.js +1 -1
- package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +1 -1
- package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +1 -1
- package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +19 -22
- package/src/engine/graphics/FrameThrottle.d.ts +1 -7
- package/src/engine/graphics/FrameThrottle.d.ts.map +1 -1
- package/src/engine/graphics/FrameThrottle.js +2 -24
- package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.d.ts +1 -1
- package/src/engine/graphics/debug/shape_to_visual_entity.d.ts.map +1 -0
- package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.js +159 -159
- package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.d.ts +1 -1
- package/src/engine/graphics/debug/visualize_tetrahedral_mesh.d.ts.map +1 -0
- package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.js +46 -46
- package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts +1 -1
- package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts.map +1 -1
- package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -32
- package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +2 -76
- package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -427
- package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts +1 -4
- package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -6
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
- package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +1 -8
- package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -14
- package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +1 -11
- package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -46
- package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +27 -0
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -0
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -0
- package/src/engine/graphics/texture/isImageBitmap.d.ts +1 -6
- package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -1
- package/src/engine/graphics/texture/isImageBitmap.js +2 -12
- package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.d.ts +2 -2
- package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.d.ts.map +1 -0
- package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.js +55 -55
- package/src/engine/network/NetworkSession.d.ts +12 -1
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +52 -1
- package/src/engine/network/README.md +45 -0
- package/src/engine/network/convertPathToURL.d.ts +1 -8
- package/src/engine/network/convertPathToURL.d.ts.map +1 -1
- package/src/engine/network/convertPathToURL.js +2 -107
- package/src/engine/network/core/quantize/quantize_float.d.ts.map +1 -1
- package/src/engine/network/core/quantize/quantize_float.js +7 -0
- package/src/engine/network/core/quantize/quantize_position.d.ts.map +1 -1
- package/src/engine/network/core/quantize/quantize_position.js +12 -1
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -1
- package/src/engine/network/replication/Replicator.d.ts +8 -0
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +48 -0
- package/src/engine/network/transport/Channel.d.ts.map +1 -1
- package/src/engine/network/transport/Channel.js +46 -12
- package/src/engine/network/transport/ReliableCommandPipeline.d.ts +16 -0
- package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
- package/src/engine/network/transport/ReliableCommandPipeline.js +29 -0
- package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/NodeUDPTransport.js +7 -1
- package/src/engine/network/transport/fragments/packet_size.d.ts +5 -5
- package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
- package/src/engine/network/transport/fragments/packet_size.js +5 -5
- package/src/engine/physics/BULLET_REVIEW.md +1 -1
- package/src/engine/physics/JOLT_REVIEW.md +2 -2
- package/src/engine/physics/PLAN.md +1094 -945
- package/src/engine/physics/RAPIER_REVIEW.md +2 -2
- package/src/engine/physics/body/BodyStorage.d.ts +2 -12
- package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
- package/src/engine/physics/body/BodyStorage.js +406 -452
- package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
- package/src/engine/physics/body/SolverBodyState.js +12 -3
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +28 -3
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +60 -24
- package/src/engine/physics/broadphase/generate_pairs.d.ts +9 -5
- package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
- package/src/engine/physics/broadphase/generate_pairs.js +52 -37
- package/src/engine/physics/ccd/linear_sweep.d.ts +15 -5
- package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
- package/src/engine/physics/ccd/linear_sweep.js +122 -40
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
- package/src/engine/physics/constraint/solve_constraints.js +830 -805
- package/src/engine/physics/contact/ManifoldStore.d.ts +91 -16
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
- package/src/engine/physics/contact/ManifoldStore.js +204 -60
- package/src/engine/physics/ecs/BodyKind.d.ts +7 -3
- package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
- package/src/engine/physics/ecs/BodyKind.js +29 -25
- package/src/engine/physics/ecs/Collider.d.ts +7 -0
- package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
- package/src/engine/physics/ecs/Collider.js +7 -0
- package/src/engine/physics/ecs/ColliderSerializationAdapter.js +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +110 -6
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +467 -45
- package/src/engine/physics/ecs/RigidBody.d.ts +20 -5
- package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
- package/src/engine/physics/ecs/RigidBody.js +307 -286
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -3
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
- package/src/engine/physics/ecs/RigidBodyFlags.js +31 -28
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +12 -4
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +19 -5
- package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts +10 -0
- package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -0
- package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts +28 -0
- package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts.map +1 -0
- package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -0
- package/src/engine/physics/events/ContactEventBuffer.d.ts +11 -0
- package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
- package/src/engine/physics/events/ContactEventBuffer.js +40 -0
- package/src/engine/physics/events/diff_manifolds.d.ts +30 -13
- package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -1
- package/src/engine/physics/events/diff_manifolds.js +87 -50
- package/src/engine/physics/fluid/FluidField.d.ts +45 -17
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +53 -23
- package/src/engine/physics/fluid/FluidSimulator.d.ts +141 -5
- package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidSimulator.js +336 -43
- package/src/engine/physics/fluid/REVIEW_02_PLAN.md +114 -0
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +4 -3
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidComponent.js +4 -3
- package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
- package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts +41 -0
- package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts.map +1 -0
- package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.js +124 -0
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +27 -8
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.js +67 -18
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts +42 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +136 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts +37 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +169 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts +36 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +100 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +6 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +6 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +7 -2
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +17 -12
- package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts +42 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +32 -22
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +43 -26
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts +31 -0
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +26 -19
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +46 -42
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +38 -10
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +158 -75
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +22 -17
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -96
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +30 -1
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +160 -116
- package/src/engine/physics/integration/integrate_position.js +97 -97
- package/src/engine/physics/island/IslandBuilder.d.ts +49 -8
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
- package/src/engine/physics/island/IslandBuilder.js +93 -14
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +683 -673
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_triangle_contact.js +899 -749
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts +27 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_contacts.js +624 -459
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_triangle_contact.js +58 -38
- package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/compute_penetration.js +369 -325
- package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +3 -1
- package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/convex_convex_manifold.js +568 -422
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +6 -3
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +66 -10
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +4 -1
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +97 -94
- package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1739
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +14 -7
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -69
- package/src/engine/physics/persistence/solver_caches.d.ts +20 -0
- package/src/engine/physics/persistence/solver_caches.d.ts.map +1 -0
- package/src/engine/physics/persistence/solver_caches.js +309 -0
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
- package/src/engine/physics/queries/overlap_shape.js +187 -184
- package/src/engine/physics/queries/raycast.d.ts +3 -2
- package/src/engine/physics/queries/raycast.d.ts.map +1 -1
- package/src/engine/physics/queries/raycast.js +37 -11
- package/src/engine/physics/queries/shape_cast.d.ts +18 -5
- package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
- package/src/engine/physics/queries/shape_cast.js +417 -393
- package/src/engine/physics/solver/solve_contacts.d.ts +22 -6
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +1482 -1338
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
- package/src/engine/physics/vehicle/RaycastVehicle.js +344 -339
- package/src/engine/ui/DraggableAspect.d.ts +12 -3
- package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
- package/src/engine/ui/DraggableAspect.js +115 -83
- package/src/generation/COORDINATES.md +54 -0
- package/src/generation/GridTaskGroup.js +2 -2
- package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -0
- package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts +9 -1
- package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts.map +1 -1
- package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -59
- package/src/generation/automata/CellularAutomata.d.ts +6 -3
- package/src/generation/automata/CellularAutomata.d.ts.map +1 -1
- package/src/generation/automata/CellularAutomata.js +22 -19
- package/src/generation/filtering/CellFilter.d.ts +17 -0
- package/src/generation/filtering/CellFilter.d.ts.map +1 -1
- package/src/generation/filtering/CellFilter.js +117 -77
- package/src/generation/filtering/CellFilterCellMatcher.d.ts.map +1 -1
- package/src/generation/filtering/CellFilterCellMatcher.js +2 -0
- package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts +5 -0
- package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts.map +1 -1
- package/src/generation/filtering/boolean/CellFilterLiteralBoolean.js +15 -0
- package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts +0 -1
- package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts.map +1 -1
- package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -50
- package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts +0 -1
- package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts.map +1 -1
- package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -59
- package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts +0 -1
- package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts.map +1 -1
- package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -33
- package/src/generation/filtering/numeric/CellFilterCache.d.ts +1 -0
- package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts +3 -2
- package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +9 -35
- package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts +0 -1
- package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterCurvature.js +19 -43
- package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts +0 -1
- package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +2 -6
- package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +9 -12
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -1
- package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts +0 -1
- package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterSobel.js +2 -6
- package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts +5 -4
- package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts.map +1 -1
- package/src/generation/filtering/numeric/math/CellFilterInverseLerp.js +5 -4
- package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts +17 -0
- package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts.map +1 -0
- package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -0
- package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.d.ts.map +1 -1
- package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +7 -1
- package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.d.ts.map +1 -1
- package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +7 -10
- package/src/generation/filtering/numeric/util/sampler_from_filter.d.ts.map +1 -1
- package/src/generation/filtering/numeric/util/sampler_from_filter.js +2 -1
- package/src/generation/grid/GridData.d.ts.map +1 -1
- package/src/generation/grid/GridData.js +14 -1
- package/src/generation/grid/actions/ContinuousGridCellAction.d.ts +10 -3
- package/src/generation/grid/actions/ContinuousGridCellAction.d.ts.map +1 -1
- package/src/generation/grid/actions/ContinuousGridCellAction.js +18 -3
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts +11 -1
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts.map +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.js +13 -3
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +2 -2
- package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +4 -6
- package/src/generation/grid/coords/grid_to_texel.d.ts +9 -0
- package/src/generation/grid/coords/grid_to_texel.d.ts.map +1 -0
- package/src/generation/grid/coords/grid_to_texel.js +10 -0
- package/src/generation/grid/coords/texel_to_grid.d.ts +9 -0
- package/src/generation/grid/coords/texel_to_grid.d.ts.map +1 -0
- package/src/generation/grid/coords/texel_to_grid.js +10 -0
- package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts +2 -2
- package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts.map +1 -1
- package/src/generation/grid/generation/GridTaskApplyActionToCells.js +10 -6
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +20 -21
- package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts +7 -0
- package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts.map +1 -1
- package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +18 -10
- package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +16 -7
- package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts +5 -3
- package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +26 -23
- package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +10 -1
- package/src/generation/grid/generation/grid/select/CellSupplierBestN.d.ts.map +1 -1
- package/src/generation/grid/generation/grid/select/CellSupplierBestN.js +4 -0
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts +15 -8
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +89 -92
- package/src/generation/markers/GridActionRuleSet.d.ts.map +1 -1
- package/src/generation/markers/GridActionRuleSet.js +10 -2
- package/src/generation/markers/GridCellActionPlaceMarker.d.ts +11 -0
- package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
- package/src/generation/markers/GridCellActionPlaceMarker.js +20 -3
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +3 -1
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +9 -2
- package/src/generation/markers/MarkerNode.d.ts +8 -3
- package/src/generation/markers/MarkerNode.d.ts.map +1 -1
- package/src/generation/markers/MarkerNode.js +12 -5
- package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts.map +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts.map +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -2
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts.map +1 -1
- package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +2 -2
- package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.d.ts.map +1 -1
- package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +6 -4
- package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.d.ts.map +1 -1
- package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +1 -3
- package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.d.ts.map +1 -1
- package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +12 -11
- package/src/generation/markers/matcher/MarkerNodeMatcherAnd.js +2 -2
- package/src/generation/markers/transform/MarkerNodeTransformer.d.ts +4 -1
- package/src/generation/markers/transform/MarkerNodeTransformer.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformer.js +4 -1
- package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +1 -3
- package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts +5 -0
- package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +15 -0
- package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +1 -3
- package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +2 -4
- package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
- package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +1 -3
- package/src/generation/placement/GridCellPlacementRule.d.ts.map +1 -1
- package/src/generation/placement/GridCellPlacementRule.js +1 -3
- package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
- package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -10
- package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.d.ts.map +1 -1
- package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +6 -4
- package/src/generation/placement/action/random/weighted/WeightedGridCellAction.d.ts.map +1 -1
- package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +1 -3
- package/src/generation/rules/CellMatcher.d.ts +3 -1
- package/src/generation/rules/CellMatcher.d.ts.map +1 -1
- package/src/generation/rules/CellMatcher.js +3 -1
- package/src/generation/rules/CellMatcherFromFilter.d.ts.map +1 -1
- package/src/generation/rules/CellMatcherFromFilter.js +1 -3
- package/src/generation/rules/CellMatcherLayerBitMaskTest.d.ts.map +1 -1
- package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -20
- package/src/generation/test_support/executeTaskTreeSync.d.ts +9 -0
- package/src/generation/test_support/executeTaskTreeSync.d.ts.map +1 -0
- package/src/generation/test_support/executeTaskTreeSync.js +78 -0
- package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +2 -1
- package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
- package/src/generation/theme/TerrainLayerRuleAggregator.js +9 -6
- package/src/generation/theme/Theme.d.ts +1 -1
- package/src/generation/theme/Theme.d.ts.map +1 -1
- package/src/generation/theme/Theme.js +2 -2
- package/src/generation/theme/ThemeEngine.d.ts +3 -3
- package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
- package/src/generation/theme/ThemeEngine.js +26 -16
- package/src/generation/theme/cell/CellProcessingRule.d.ts +3 -3
- package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
- package/src/generation/theme/cell/CellProcessingRule.js +6 -10
- package/src/generation/theme/cell/CellProcessingRuleSet.d.ts +1 -1
- package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
- package/src/generation/theme/cell/CellProcessingRuleSet.js +2 -2
- package/src/view/common/ListView.js +1 -1
- package/src/view/elements/BottomLeftResizeHandleView.d.ts.map +1 -1
- package/src/view/elements/BottomLeftResizeHandleView.js +13 -5
- package/src/core/font/FontAsset.d.ts.map +0 -1
- package/src/core/font/FontAssetLoader.d.ts.map +0 -1
- package/src/core/geom/3d/shape/util/shape_to_visual_entity.d.ts.map +0 -1
- package/src/core/geom/3d/tetrahedra/visualize_tetrahedral_mesh.d.ts.map +0 -1
- package/src/core/process/action/AsynchronousDelayAction.d.ts.map +0 -1
- package/src/engine/physics/computeInterceptPoint.d.ts.map +0 -1
- package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +0 -1
- package/src/engine/physics/gjk/gjk.d.ts.map +0 -1
- package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +0 -1
- package/src/engine/physics/gjk/minkowski_support.d.ts.map +0 -1
- package/src/engine/physics/gjk/mpr.d.ts.map +0 -1
- package/src/engine/physics/integration/quat_integrate.d.ts.map +0 -1
- package/src/engine/physics/island/union_find.d.ts.map +0 -1
- package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +0 -1
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +0 -1
- package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts +0 -21
- package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +0 -1
- package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +0 -68
- package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts +0 -10
- package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts.map +0 -1
- package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.js +0 -17
- /package/src/{engine/physics → core/geom/3d}/gjk/NOTES.md +0 -0
- /package/src/{engine/physics → core/geom/3d}/gjk/gjk.d.ts +0 -0
- /package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.d.ts +0 -0
|
@@ -1,1739 +1,1738 @@
|
|
|
1
|
-
import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
|
|
2
|
-
import { Triangle3D } from "../../../core/geom/3d/shape/Triangle3D.js";
|
|
3
|
-
import { body_id_index } from "../body/BodyStorage.js";
|
|
4
|
-
import { combine_friction, combine_restitution } from "../contact/combine_material.js";
|
|
5
|
-
import { CONTACT_STRIDE, MAX_CONTACTS_PER_MANIFOLD } from "../contact/ManifoldStore.js";
|
|
6
|
-
import { gjk_epa_penetration } from "
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
*
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
*
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* @
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
*
|
|
211
|
-
* @
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
*
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* @param {
|
|
379
|
-
* @param {
|
|
380
|
-
* @param {
|
|
381
|
-
* @param {
|
|
382
|
-
* @param {
|
|
383
|
-
* @
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
//
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
//
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
convex_manifold_result[base
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
*
|
|
416
|
-
* the
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
* @param {
|
|
420
|
-
* @param {
|
|
421
|
-
* @param {
|
|
422
|
-
* @param {
|
|
423
|
-
* @
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
nx, ny, nz
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
boxTr.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
//
|
|
507
|
-
//
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
boxTr.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
trA.
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
trB.
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
//
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
box_manifold_result[base
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const
|
|
633
|
-
const
|
|
634
|
-
const
|
|
635
|
-
const
|
|
636
|
-
const
|
|
637
|
-
const
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
return
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
//
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
//
|
|
673
|
-
//
|
|
674
|
-
//
|
|
675
|
-
//
|
|
676
|
-
//
|
|
677
|
-
//
|
|
678
|
-
//
|
|
679
|
-
//
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
//
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
//
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
//
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
//
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
// face
|
|
766
|
-
//
|
|
767
|
-
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
//
|
|
772
|
-
//
|
|
773
|
-
// sphere
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
const
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
//
|
|
810
|
-
//
|
|
811
|
-
const
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
//
|
|
866
|
-
//
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
const
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
//
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
// rejection
|
|
1165
|
-
//
|
|
1166
|
-
//
|
|
1167
|
-
//
|
|
1168
|
-
//
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
//
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
//
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const
|
|
1197
|
-
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
//
|
|
1213
|
-
//
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
//
|
|
1217
|
-
//
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
//
|
|
1299
|
-
//
|
|
1300
|
-
//
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1303
|
-
//
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
*
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
const
|
|
1417
|
-
const
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
//
|
|
1507
|
-
//
|
|
1508
|
-
//
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
const
|
|
1517
|
-
const
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1608
|
-
*
|
|
1609
|
-
*
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
const
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
//
|
|
1654
|
-
//
|
|
1655
|
-
//
|
|
1656
|
-
//
|
|
1657
|
-
//
|
|
1658
|
-
//
|
|
1659
|
-
//
|
|
1660
|
-
//
|
|
1661
|
-
//
|
|
1662
|
-
//
|
|
1663
|
-
//
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
const
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1674
|
-
const
|
|
1675
|
-
const
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
let
|
|
1679
|
-
let
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
const
|
|
1685
|
-
const
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
//
|
|
1695
|
-
//
|
|
1696
|
-
//
|
|
1697
|
-
//
|
|
1698
|
-
//
|
|
1699
|
-
//
|
|
1700
|
-
//
|
|
1701
|
-
//
|
|
1702
|
-
//
|
|
1703
|
-
//
|
|
1704
|
-
//
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
const
|
|
1710
|
-
const
|
|
1711
|
-
const
|
|
1712
|
-
const
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
//
|
|
1726
|
-
//
|
|
1727
|
-
|
|
1728
|
-
data[off]
|
|
1729
|
-
data[off +
|
|
1730
|
-
data[off +
|
|
1731
|
-
data[off +
|
|
1732
|
-
data[off +
|
|
1733
|
-
data[off +
|
|
1734
|
-
data[off +
|
|
1735
|
-
data[off +
|
|
1736
|
-
data[off +
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
}
|
|
1
|
+
import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
|
|
2
|
+
import { Triangle3D } from "../../../core/geom/3d/shape/Triangle3D.js";
|
|
3
|
+
import { body_id_index } from "../body/BodyStorage.js";
|
|
4
|
+
import { combine_friction, combine_restitution } from "../contact/combine_material.js";
|
|
5
|
+
import { CONTACT_STRIDE, MAX_CONTACTS_PER_MANIFOLD } from "../contact/ManifoldStore.js";
|
|
6
|
+
import { gjk_epa_penetration } from "../../../core/geom/3d/gjk/gjk_epa_penetration.js";
|
|
7
|
+
import { reduce_manifold_contacts } from "./reduce_manifold_contacts.js";
|
|
8
|
+
import { mpr } from "../../../core/geom/3d/gjk/mpr.js";
|
|
9
|
+
import { box_box_manifold, BOX_BOX_OUT_LENGTH } from "./box_box_manifold.js";
|
|
10
|
+
import { convex_hull_clip, CONVEX_CONVEX_OUT_LENGTH } from "./convex_convex_manifold.js";
|
|
11
|
+
import { get_mesh_convex_hull } from "./mesh_convex_hull.js";
|
|
12
|
+
import { mesh_mesh_tet_contacts } from "./mesh_mesh_tet_manifold.js";
|
|
13
|
+
import { box_triangle_contact, BOX_TRIANGLE_OUT_LENGTH } from "./box_triangle_contact.js";
|
|
14
|
+
import {
|
|
15
|
+
CAPSULE_BOX_CONTACT_STRIDE,
|
|
16
|
+
CAPSULE_BOX_MAX_CONTACTS,
|
|
17
|
+
capsule_box_multi_contacts,
|
|
18
|
+
capsule_capsule_contact,
|
|
19
|
+
CAPSULE_CAPSULE_CONTACT_STRIDE,
|
|
20
|
+
capsule_capsule_multi_contacts,
|
|
21
|
+
capsule_sphere_contact,
|
|
22
|
+
} from "./capsule_contacts.js";
|
|
23
|
+
import {
|
|
24
|
+
capsule_triangle_contact,
|
|
25
|
+
CAPSULE_TRIANGLE_CONTACT_STRIDE,
|
|
26
|
+
CAPSULE_TRIANGLE_MAX_CONTACTS,
|
|
27
|
+
} from "./capsule_triangle_contact.js";
|
|
28
|
+
import { aabb3_transform_oriented_inverse } from "../../../core/geom/3d/aabb/aabb3_transform_oriented_inverse.js";
|
|
29
|
+
import { decompose_to_triangles } from "./decomposition/decompose_to_triangles.js";
|
|
30
|
+
import { TRIANGLE_FLOAT_STRIDE } from "./decomposition/triangle_buffer_layout.js";
|
|
31
|
+
import { PosedShape3D } from "../../../core/geom/3d/shape/PosedShape3D.js";
|
|
32
|
+
import { sphere_box_contact } from "./sphere_box_contact.js";
|
|
33
|
+
import { sphere_sphere_contact } from "./sphere_sphere_contact.js";
|
|
34
|
+
import { sphere_triangle_contact } from "./sphere_triangle_contact.js";
|
|
35
|
+
|
|
36
|
+
const posed_a = new PosedShape3D();
|
|
37
|
+
const posed_b = new PosedShape3D();
|
|
38
|
+
|
|
39
|
+
// Penetration axis + depth from the robust GJK + EPA query
|
|
40
|
+
// (gjk_epa_penetration writes a unit normal here; it owns its own simplex
|
|
41
|
+
// internally, so the narrowphase no longer keeps a simplex buffer).
|
|
42
|
+
const epa_result = new Float64Array(3);
|
|
43
|
+
const sphere_result = new Float64Array(4);
|
|
44
|
+
const closed_form_result = new Float64Array(10);
|
|
45
|
+
|
|
46
|
+
/** Scratch for the capsule-capsule multi-contact manifold (2 contacts max). */
|
|
47
|
+
const capsule_capsule_result = new Float64Array(2 * CAPSULE_CAPSULE_CONTACT_STRIDE);
|
|
48
|
+
const sphere_triangle_result = new Float64Array(10);
|
|
49
|
+
const box_triangle_result = new Float64Array(BOX_TRIANGLE_OUT_LENGTH);
|
|
50
|
+
const capsule_triangle_result = new Float64Array(CAPSULE_TRIANGLE_MAX_CONTACTS * CAPSULE_TRIANGLE_CONTACT_STRIDE);
|
|
51
|
+
const box_manifold_result = new Float64Array(BOX_BOX_OUT_LENGTH);
|
|
52
|
+
const convex_manifold_result = new Float64Array(CONVEX_CONVEX_OUT_LENGTH);
|
|
53
|
+
const capsule_box_multi_result = new Float64Array(CAPSULE_BOX_MAX_CONTACTS * CAPSULE_BOX_CONTACT_STRIDE);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Candidate-contact stride: wax, way, waz, wbx, wby, wbz, nx, ny, nz, depth,
|
|
57
|
+
* feature_id, friction, restitution.
|
|
58
|
+
*
|
|
59
|
+
* The `feature_id` (offset 10) is a stable cross-frame identifier of the
|
|
60
|
+
* geometric feature pair that produced this contact — used by the
|
|
61
|
+
* match-and-merge pass in {@link narrowphase_step} to carry warm-start
|
|
62
|
+
* impulses from the previous frame's manifold to the slot index that
|
|
63
|
+
* corresponds to the same physical contact. A value of 0 means
|
|
64
|
+
* "no feature info, fall back to position matching".
|
|
65
|
+
*
|
|
66
|
+
* `friction` (offset 11) and `restitution` (offset 12) are the COMBINED
|
|
67
|
+
* coefficients for the specific (colliderA, colliderB) pair that produced this
|
|
68
|
+
* contact, combined here (the only place that knows the exact source collider
|
|
69
|
+
* on each side) and carried into the manifold so a compound body's per-collider
|
|
70
|
+
* materials are honoured per-contact.
|
|
71
|
+
*
|
|
72
|
+
* @type {number}
|
|
73
|
+
*/
|
|
74
|
+
const CANDIDATE_STRIDE = 13;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Combined friction / restitution for the collider pair currently being
|
|
78
|
+
* dispatched. Set once at the top of {@link dispatch_pair} (which is called
|
|
79
|
+
* per collider pair) and written into every contact that call appends, so
|
|
80
|
+
* each contact carries the material of its actual source colliders. Module
|
|
81
|
+
* scratch rather than threaded through every `append_contact` call site.
|
|
82
|
+
* @type {number}
|
|
83
|
+
*/
|
|
84
|
+
let g_pair_friction = 0;
|
|
85
|
+
let g_pair_restitution = 0;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Maximum number of contacts emitted into the per-pair manifold after the
|
|
89
|
+
* reduction step. Mirrors {@link MAX_CONTACTS_PER_MANIFOLD} in ManifoldStore.
|
|
90
|
+
* @type {number}
|
|
91
|
+
*/
|
|
92
|
+
const MAX_KEPT = MAX_CONTACTS_PER_MANIFOLD;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Position-fallback tolerance for warm-start matching: when a candidate
|
|
96
|
+
* contact has no feature id (or none of the previous-frame contacts shares
|
|
97
|
+
* its id), match by closest world_a within this 3-D distance.
|
|
98
|
+
*
|
|
99
|
+
* 2 cm matches the original PLAN.md spec for "Persistent manifold cache"
|
|
100
|
+
* — generous enough to follow small inter-frame contact migration on
|
|
101
|
+
* curved surfaces, tight enough that distinct contacts on a single
|
|
102
|
+
* manifold (typically >5 cm apart) don't get confused with each other.
|
|
103
|
+
*
|
|
104
|
+
* @type {number}
|
|
105
|
+
*/
|
|
106
|
+
const MATCH_TOL_SQR = 0.02 * 0.02;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Per-(colliderA, colliderB) feature-id salt. Each emitter numbers its
|
|
110
|
+
* features in a small private range (sphere-box voronoi 1..27, capsule-box
|
|
111
|
+
* 1..k, triangles 1..N, …), so two SUB-PAIRS of a compound body can produce
|
|
112
|
+
* identical fids for unrelated features and warm-start impulses could be
|
|
113
|
+
* inherited across collider pairs. Salting by the sub-pair index keeps every
|
|
114
|
+
* fid unique across the body pair while staying exactly representable in f64
|
|
115
|
+
* (sub_pair · 2³² + fid stays far below 2⁵³ for any realistic compound; no
|
|
116
|
+
* single-pair emitter exceeds 2³²). Sub-pair 0 — the universal
|
|
117
|
+
* single-collider case — is left unsalted, so simple bodies see unchanged
|
|
118
|
+
* fids.
|
|
119
|
+
* @type {number}
|
|
120
|
+
*/
|
|
121
|
+
const FID_PAIR_SALT = 0x100000000; // 2^32
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Distance ceiling for a feature-id warm-start match. A fid match may track
|
|
125
|
+
* a fast-sliding contact far beyond {@link MATCH_TOL_SQR} — that is its
|
|
126
|
+
* advantage over position matching — but an impulse inherited across half a
|
|
127
|
+
* metre in one frame is stale by any standard (a teleported body re-deriving
|
|
128
|
+
* the same voronoi bucket, or a fid collision between unrelated features).
|
|
129
|
+
* The position fallback keeps its own 2 cm gate.
|
|
130
|
+
* @type {number}
|
|
131
|
+
*/
|
|
132
|
+
const FID_MATCH_MAX_D2 = 0.5 * 0.5;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Scratch for the previous-frame contact snapshot taken at the top of the
|
|
136
|
+
* match-and-merge pass. Sized for {@link MAX_CONTACTS_PER_MANIFOLD}
|
|
137
|
+
* contacts, 7 floats per contact:
|
|
138
|
+
* 0 : feature_id
|
|
139
|
+
* 1, 2, 3 : world_a x, y, z (for position-fallback matching)
|
|
140
|
+
* 4, 5, 6 : j_n, j_t1, j_t2 (carried forward to the matched candidate)
|
|
141
|
+
*
|
|
142
|
+
* Snapshotting upfront decouples the read (from the slot's previous state)
|
|
143
|
+
* from the write (the new contact data + impulse copy), avoiding the
|
|
144
|
+
* read-after-write hazard when the matching mapping shuffles indices.
|
|
145
|
+
*
|
|
146
|
+
* @type {Float64Array}
|
|
147
|
+
*/
|
|
148
|
+
const prev_snapshot = new Float64Array(MAX_CONTACTS_PER_MANIFOLD * 7);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Per-prev-contact "already claimed by a candidate" flag.
|
|
152
|
+
* @type {Uint8Array}
|
|
153
|
+
*/
|
|
154
|
+
const prev_claimed = new Uint8Array(MAX_CONTACTS_PER_MANIFOLD);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* For each kept candidate, the matched prev-contact index in
|
|
158
|
+
* `[0, prev_count)` or `-1` if no match.
|
|
159
|
+
* @type {Int32Array}
|
|
160
|
+
*/
|
|
161
|
+
const cand_to_prev = new Int32Array(MAX_KEPT);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Per-candidate "already claimed" flags for {@link redetect_pair_geometry}'s
|
|
165
|
+
* 1:1 existing-contact → fresh-candidate matching. Sized to the candidate
|
|
166
|
+
* buffer capacity (64) so it covers any per-pair candidate count. Without it,
|
|
167
|
+
* several existing contacts that share one triangle's `feature_id` (the
|
|
168
|
+
* box/capsule-triangle paths emit multiple contacts per triangle) would all
|
|
169
|
+
* match the same first candidate, collapsing the manifold to duplicate witness
|
|
170
|
+
* points.
|
|
171
|
+
* @type {Uint8Array}
|
|
172
|
+
*/
|
|
173
|
+
const redetect_claimed = new Uint8Array(64);
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Per body-pair scratch buffer for candidate contacts produced by the
|
|
177
|
+
* cross-product of A's colliders × B's colliders. Sized generously for
|
|
178
|
+
* typical compound bodies (each collider-pair contributes 1..4 contacts;
|
|
179
|
+
* 64 covers up to 4 colliders per body × 4 colliders × 4 contacts = 64).
|
|
180
|
+
* @type {Float64Array}
|
|
181
|
+
*/
|
|
182
|
+
const candidates = new Float64Array(64 * CANDIDATE_STRIDE);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Maximum triangles a concave-side enumerator can produce per pair.
|
|
186
|
+
* The query AABB is bounded by the broadphase's fattened envelope of
|
|
187
|
+
* the convex-side body, so a single concave-vs-convex pair typically
|
|
188
|
+
* yields tens of triangles, not thousands. 1024 is the safety cap.
|
|
189
|
+
*
|
|
190
|
+
* For a heightmap the per-cell triangle count scales O(N²) with the
|
|
191
|
+
* shape's {@link HeightMapShape3D#tessellation} (a sub-cell quad is 2
|
|
192
|
+
* triangles, and there are N×N sub-cells per sampler cell). The bounded
|
|
193
|
+
* query AABB keeps the cell count small, so a typical pair stays well
|
|
194
|
+
* inside 1024 at moderate tessellation; the silent-drop backstop below
|
|
195
|
+
* covers any overflow at extreme values.
|
|
196
|
+
*
|
|
197
|
+
* Enumerators return the TRUE overlap count and have no bounds check of
|
|
198
|
+
* their own: writes past the scratch buffer are dropped (typed-array OOB
|
|
199
|
+
* semantics), so on overflow the consume loop MUST clamp the returned
|
|
200
|
+
* count to this cap or it reads `undefined` past the end and poisons the
|
|
201
|
+
* manifold with NaN. The worst case after clamping is a missed contact
|
|
202
|
+
* on a far edge of the filtered region, which the next-step
|
|
203
|
+
* rebroadphase corrects.
|
|
204
|
+
*
|
|
205
|
+
* @type {number}
|
|
206
|
+
*/
|
|
207
|
+
const MAX_TRIANGLES_PER_PAIR = 1024;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Per-pair scratch for the concave-side triangle decomposition.
|
|
211
|
+
* @type {Float64Array}
|
|
212
|
+
*/
|
|
213
|
+
const triangle_buffer = new Float64Array(MAX_TRIANGLES_PER_PAIR * TRIANGLE_FLOAT_STRIDE);
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Flyweight triangle shape — rebound to each successive triangle slice
|
|
217
|
+
* of `triangle_buffer` during the concave-side dispatch loop. Zero
|
|
218
|
+
* allocation per triangle.
|
|
219
|
+
* @type {Triangle3D}
|
|
220
|
+
*/
|
|
221
|
+
const triangle_shape = new Triangle3D();
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Scratch AABB buffers used only by the concave-side dispatch:
|
|
225
|
+
* - `concave_local_aabb` : convex shape's local AABB (input to oriented transform)
|
|
226
|
+
* - `concave_world_aabb` : convex shape's world AABB
|
|
227
|
+
* - `concave_query_aabb` : convex shape's AABB projected into concave's body-local frame
|
|
228
|
+
* (what the triangle enumerator filters against)
|
|
229
|
+
*/
|
|
230
|
+
const concave_local_aabb = new Float64Array(6);
|
|
231
|
+
const concave_world_aabb = new Float64Array(6);
|
|
232
|
+
const concave_query_aabb = new Float64Array(6);
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Rotate + translate a triangle's three vertices from a concave body's
|
|
236
|
+
* local frame into world space: writes 9 floats `(A_w, B_w, C_w)` into
|
|
237
|
+
* `out`. Inlined `q · v · q*` + translate per vertex (see
|
|
238
|
+
* PosedShape3D.support for the V8-inliner rationale); the operation order
|
|
239
|
+
* matches the blocks this replaced bit-exactly. Per-vertex cost ~21 flops
|
|
240
|
+
* × 3 — essentially free next to any narrowphase kernel it feeds.
|
|
241
|
+
*
|
|
242
|
+
* Shared by the sphere / box / capsule closed-form triangle fast-paths in
|
|
243
|
+
* the concave dispatch, which each carried an identical inlined copy.
|
|
244
|
+
*/
|
|
245
|
+
function triangle_vertices_to_world(out, ax, ay, az, bx, by, bz, cx, cy, cz, qx, qy, qz, qw, px, py, pz) {
|
|
246
|
+
const axi = qw * ax + qy * az - qz * ay;
|
|
247
|
+
const ayi = qw * ay + qz * ax - qx * az;
|
|
248
|
+
const azi = qw * az + qx * ay - qy * ax;
|
|
249
|
+
const awi = -qx * ax - qy * ay - qz * az;
|
|
250
|
+
|
|
251
|
+
out[0] = axi * qw + awi * -qx + ayi * -qz - azi * -qy + px;
|
|
252
|
+
out[1] = ayi * qw + awi * -qy + azi * -qx - axi * -qz + py;
|
|
253
|
+
out[2] = azi * qw + awi * -qz + axi * -qy - ayi * -qx + pz;
|
|
254
|
+
|
|
255
|
+
const bxi = qw * bx + qy * bz - qz * by;
|
|
256
|
+
const byi = qw * by + qz * bx - qx * bz;
|
|
257
|
+
const bzi = qw * bz + qx * by - qy * bx;
|
|
258
|
+
const bwi = -qx * bx - qy * by - qz * bz;
|
|
259
|
+
|
|
260
|
+
out[3] = bxi * qw + bwi * -qx + byi * -qz - bzi * -qy + px;
|
|
261
|
+
out[4] = byi * qw + bwi * -qy + bzi * -qx - bxi * -qz + py;
|
|
262
|
+
out[5] = bzi * qw + bwi * -qz + bxi * -qy - byi * -qx + pz;
|
|
263
|
+
|
|
264
|
+
const cxi = qw * cx + qy * cz - qz * cy;
|
|
265
|
+
const cyi = qw * cy + qz * cx - qx * cz;
|
|
266
|
+
const czi = qw * cz + qx * cy - qy * cx;
|
|
267
|
+
const cwi = -qx * cx - qy * cy - qz * cz;
|
|
268
|
+
|
|
269
|
+
out[6] = cxi * qw + cwi * -qx + cyi * -qz - czi * -qy + px;
|
|
270
|
+
out[7] = cyi * qw + cwi * -qy + czi * -qx - cxi * -qz + py;
|
|
271
|
+
out[8] = czi * qw + cwi * -qz + cxi * -qy - cyi * -qx + pz;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Destination for {@link triangle_vertices_to_world}. */
|
|
275
|
+
const scratch_tri_world = new Float64Array(9);
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Append one contact to the candidate buffer. Returns the new count.
|
|
279
|
+
*
|
|
280
|
+
* @param {number} count
|
|
281
|
+
* @param {number} wax
|
|
282
|
+
* @param {number} way
|
|
283
|
+
* @param {number} waz
|
|
284
|
+
* @param {number} wbx
|
|
285
|
+
* @param {number} wby
|
|
286
|
+
* @param {number} wbz
|
|
287
|
+
* @param {number} nx
|
|
288
|
+
* @param {number} ny
|
|
289
|
+
* @param {number} nz
|
|
290
|
+
* @param {number} depth
|
|
291
|
+
* @param {number} feature_id stable cross-frame ID for warm-start matching;
|
|
292
|
+
* `0` means no info — match-and-merge will fall back to position.
|
|
293
|
+
* @returns {number}
|
|
294
|
+
*/
|
|
295
|
+
function append_contact(count, wax, way, waz, wbx, wby, wbz, nx, ny, nz, depth, feature_id) {
|
|
296
|
+
if (count * CANDIDATE_STRIDE >= candidates.length){
|
|
297
|
+
return count;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const off = count * CANDIDATE_STRIDE;
|
|
301
|
+
|
|
302
|
+
candidates[off] = wax; candidates[off + 1] = way; candidates[off + 2] = waz;
|
|
303
|
+
candidates[off + 3] = wbx; candidates[off + 4] = wby; candidates[off + 5] = wbz;
|
|
304
|
+
candidates[off + 6] = nx; candidates[off + 7] = ny; candidates[off + 8] = nz;
|
|
305
|
+
candidates[off + 9] = depth;
|
|
306
|
+
candidates[off + 10] = feature_id;
|
|
307
|
+
candidates[off + 11] = g_pair_friction;
|
|
308
|
+
candidates[off + 12] = g_pair_restitution;
|
|
309
|
+
|
|
310
|
+
return count + 1;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Compute a stable voronoi-region feature id for a sphere-vs-box contact.
|
|
315
|
+
* Returns one of 27 values in `[1, 27]` based on which of the 27 voronoi
|
|
316
|
+
* regions of the box the sphere centre lies in (8 corners + 12 edges + 6
|
|
317
|
+
* faces + 1 interior). Stable across frames as long as the sphere stays
|
|
318
|
+
* in the same region — the typical case in steady-state contact.
|
|
319
|
+
*
|
|
320
|
+
* Encodes:
|
|
321
|
+
* bucket_x ∈ {0, 1, 2} = sign(lx) bucket in box-local frame
|
|
322
|
+
* bucket_y, bucket_z similarly
|
|
323
|
+
* fid = 1 + bucket_x + 3·bucket_y + 9·bucket_z → 1..27
|
|
324
|
+
*
|
|
325
|
+
* The "+1" offset ensures the result is never 0, since 0 is reserved
|
|
326
|
+
* for "no feature info, use position-fallback".
|
|
327
|
+
*
|
|
328
|
+
* @param {number} sx sphere centre x
|
|
329
|
+
* @param {number} sy
|
|
330
|
+
* @param {number} sz
|
|
331
|
+
* @param {number} bx box centre x
|
|
332
|
+
* @param {number} by
|
|
333
|
+
* @param {number} bz
|
|
334
|
+
* @param {number} bqx box quaternion x
|
|
335
|
+
* @param {number} bqy
|
|
336
|
+
* @param {number} bqz
|
|
337
|
+
* @param {number} bqw
|
|
338
|
+
* @param {number} hx box half-extent x
|
|
339
|
+
* @param {number} hy
|
|
340
|
+
* @param {number} hz
|
|
341
|
+
* @returns {number}
|
|
342
|
+
*/
|
|
343
|
+
function sphere_box_voronoi_fid(sx, sy, sz, bx, by, bz, bqx, bqy, bqz, bqw, hx, hy, hz) {
|
|
344
|
+
// Inverse-rotate (sx - bx, sy - by, sz - bz) by the box's quaternion
|
|
345
|
+
// to get the sphere centre in box-local frame. Inlined for the same
|
|
346
|
+
// V8-inliner reason described in PosedShape3D.support — see
|
|
347
|
+
// core/geom/vec3/v3_quat3_apply_inverse.js for the canonical form.
|
|
348
|
+
const dx = sx - bx;
|
|
349
|
+
const dy = sy - by;
|
|
350
|
+
const dz = sz - bz;
|
|
351
|
+
|
|
352
|
+
const tx0 = bqw * dx - bqy * dz + bqz * dy;
|
|
353
|
+
const ty0 = bqw * dy - bqz * dx + bqx * dz;
|
|
354
|
+
const tz0 = bqw * dz - bqx * dy + bqy * dx;
|
|
355
|
+
const tw0 = bqx * dx + bqy * dy + bqz * dz;
|
|
356
|
+
|
|
357
|
+
const lx = tx0 * bqw + tw0 * bqx + ty0 * bqz - tz0 * bqy;
|
|
358
|
+
const ly = ty0 * bqw + tw0 * bqy + tz0 * bqx - tx0 * bqz;
|
|
359
|
+
const lz = tz0 * bqw + tw0 * bqz + tx0 * bqy - ty0 * bqx;
|
|
360
|
+
|
|
361
|
+
const bx_b = lx <= -hx ? 0 : (lx >= hx ? 2 : 1);
|
|
362
|
+
const by_b = ly <= -hy ? 0 : (ly >= hy ? 2 : 1);
|
|
363
|
+
const bz_b = lz <= -hz ? 0 : (lz >= hz ? 2 : 1);
|
|
364
|
+
|
|
365
|
+
return 1 + bx_b + 3 * by_b + 9 * bz_b;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Multi-point contact manifold between two convex polytopes (authored
|
|
370
|
+
* ConvexHullShape3D, or a convex MeshShape3D represented as one hull). Robust
|
|
371
|
+
* GJK + EPA finds the separating axis in O(support queries) — face-count
|
|
372
|
+
* independent, where SAT's edge-pair term is prohibitive — then
|
|
373
|
+
* {@link convex_hull_clip} clips the reference/incident faces into a face-on-face
|
|
374
|
+
* patch around it (Bullet's clipHullAgainstHull). A single GJK+EPA contact can't
|
|
375
|
+
* resist a stack's toppling torque; the clipped patch holds it. No cross-frame
|
|
376
|
+
* state → reset-and-resimulate determinism.
|
|
377
|
+
*
|
|
378
|
+
* @param {number} count
|
|
379
|
+
* @param {{vertices,face_offsets,face_loops,support}} hullA in A's local frame
|
|
380
|
+
* @param {Transform} trA
|
|
381
|
+
* @param {{vertices,face_offsets,face_loops,support}} hullB in B's local frame
|
|
382
|
+
* @param {Transform} trB
|
|
383
|
+
* @param {Function} append_contact
|
|
384
|
+
* @returns {number}
|
|
385
|
+
*/
|
|
386
|
+
function hull_pair_contacts(count, hullA, trA, hullB, trB, append_contact) {
|
|
387
|
+
posed_a.setup(hullA, trA.position, trA.rotation);
|
|
388
|
+
posed_b.setup(hullB, trB.position, trB.rotation);
|
|
389
|
+
const depth = gjk_epa_penetration(epa_result, posed_a, posed_b);
|
|
390
|
+
if (!(depth > 0) || !Number.isFinite(depth)) return count;
|
|
391
|
+
|
|
392
|
+
// convex_hull_clip orients the axis B→A robustly (via vertex centroids) and
|
|
393
|
+
// writes the final normal into convex_manifold_result[0..2].
|
|
394
|
+
convex_hull_clip(convex_manifold_result,
|
|
395
|
+
hullA, trA.position, trA.rotation,
|
|
396
|
+
hullB, trB.position, trB.rotation,
|
|
397
|
+
epa_result[0], epa_result[1], epa_result[2]);
|
|
398
|
+
const nx = convex_manifold_result[0], ny = convex_manifold_result[1], nz = convex_manifold_result[2];
|
|
399
|
+
const cc = convex_manifold_result[3] | 0;
|
|
400
|
+
// Clipped points migrate across features as the hulls rotate, so leave
|
|
401
|
+
// fid = 0 and let the match-and-merge pass position-match (as box-box does).
|
|
402
|
+
for (let k = 0; k < cc; k++) {
|
|
403
|
+
const base = 4 + k * 7;
|
|
404
|
+
count = append_contact(count,
|
|
405
|
+
convex_manifold_result[base], convex_manifold_result[base + 1], convex_manifold_result[base + 2],
|
|
406
|
+
convex_manifold_result[base + 3], convex_manifold_result[base + 4], convex_manifold_result[base + 5],
|
|
407
|
+
nx, ny, nz,
|
|
408
|
+
convex_manifold_result[base + 6],
|
|
409
|
+
0);
|
|
410
|
+
}
|
|
411
|
+
return count;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Run pairwise narrowphase for one (colliderA, colliderB) tuple — dispatches
|
|
416
|
+
* by shape type and appends 0..K contacts to the candidate buffer. Returns
|
|
417
|
+
* the new candidate count.
|
|
418
|
+
*
|
|
419
|
+
* @param {number} count
|
|
420
|
+
* @param {Collider} colA
|
|
421
|
+
* @param {Transform} trA
|
|
422
|
+
* @param {Collider} colB
|
|
423
|
+
* @param {Transform} trB
|
|
424
|
+
* @returns {number}
|
|
425
|
+
*/
|
|
426
|
+
function dispatch_pair(count, colA, trA, colB, trB) {
|
|
427
|
+
const shapeA = colA.shape;
|
|
428
|
+
const shapeB = colB.shape;
|
|
429
|
+
|
|
430
|
+
// Per-contact materials: combine the two source colliders' coefficients
|
|
431
|
+
// once here (this is the only place that knows the exact collider on each
|
|
432
|
+
// side) and stamp them onto every contact this dispatch appends. The
|
|
433
|
+
// `deepest_pair_penetration` query passes bare `{shape}` adapters with no
|
|
434
|
+
// material fields — it never writes to a manifold, so 0 is fine there.
|
|
435
|
+
const fa = colA.friction, fb = colB.friction;
|
|
436
|
+
|
|
437
|
+
if (fa !== undefined && fb !== undefined) {
|
|
438
|
+
|
|
439
|
+
g_pair_friction = combine_friction(fa, fb);
|
|
440
|
+
g_pair_restitution = combine_restitution(colA.restitution, colB.restitution);
|
|
441
|
+
|
|
442
|
+
} else {
|
|
443
|
+
g_pair_friction = 0;
|
|
444
|
+
g_pair_restitution = 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// isSphereShape3D covers both UnitSphereShape3D (fixed radius 1) and
|
|
448
|
+
// SphereShape3D (arbitrary radius). Both expose `radius`.
|
|
449
|
+
const isSphereA = shapeA.isSphereShape3D === true;
|
|
450
|
+
const isSphereB = shapeB.isSphereShape3D === true;
|
|
451
|
+
// isBoxShape3D covers both UnitCubeShape3D (fixed 0.5) and BoxShape3D
|
|
452
|
+
// (arbitrary half-extents). Both expose `half_extents` as a Vector3.
|
|
453
|
+
const isBoxA = shapeA.isBoxShape3D === true;
|
|
454
|
+
const isBoxB = shapeB.isBoxShape3D === true;
|
|
455
|
+
const isCapsuleA = shapeA.isCapsuleShape3D === true;
|
|
456
|
+
const isCapsuleB = shapeB.isCapsuleShape3D === true;
|
|
457
|
+
|
|
458
|
+
// sphere-sphere
|
|
459
|
+
if (isSphereA && isSphereB) {
|
|
460
|
+
const ra = shapeA.radius, rb = shapeB.radius;
|
|
461
|
+
|
|
462
|
+
const ok = sphere_sphere_contact(
|
|
463
|
+
sphere_result,
|
|
464
|
+
trA.position.x, trA.position.y, trA.position.z,
|
|
465
|
+
trB.position.x, trB.position.y, trB.position.z,
|
|
466
|
+
ra, rb
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
if (!ok) return count;
|
|
470
|
+
|
|
471
|
+
const nx = sphere_result[0], ny = sphere_result[1], nz = sphere_result[2];
|
|
472
|
+
|
|
473
|
+
// Sphere-sphere produces exactly one contact per pair; fid = 1
|
|
474
|
+
// identifies it as a real feature (distinguishes from "no info" = 0)
|
|
475
|
+
// and is trivially stable across frames. Witnesses are the surface
|
|
476
|
+
// points along the (unit) normal, scaled by each sphere's radius.
|
|
477
|
+
return append_contact(count,
|
|
478
|
+
trA.position.x - nx * ra, trA.position.y - ny * ra, trA.position.z - nz * ra,
|
|
479
|
+
trB.position.x + nx * rb, trB.position.y + ny * rb, trB.position.z + nz * rb,
|
|
480
|
+
nx, ny, nz, sphere_result[3], 1);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// sphere ↔ box
|
|
484
|
+
if ((isSphereA && isBoxB) || (isBoxA && isSphereB)) {
|
|
485
|
+
const sphereTr = isSphereA ? trA : trB;
|
|
486
|
+
const sphereShape = isSphereA ? shapeA : shapeB;
|
|
487
|
+
const boxTr = isSphereA ? trB : trA;
|
|
488
|
+
const boxShape = isSphereA ? shapeB : shapeA;
|
|
489
|
+
const bh = boxShape.half_extents;
|
|
490
|
+
|
|
491
|
+
const ok = sphere_box_contact(
|
|
492
|
+
closed_form_result,
|
|
493
|
+
sphereTr.position.x, sphereTr.position.y, sphereTr.position.z, sphereShape.radius,
|
|
494
|
+
boxTr.position.x, boxTr.position.y, boxTr.position.z,
|
|
495
|
+
boxTr.rotation.x, boxTr.rotation.y, boxTr.rotation.z, boxTr.rotation.w,
|
|
496
|
+
bh.x, bh.y, bh.z
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
if (!ok) return count;
|
|
500
|
+
|
|
501
|
+
let nx = closed_form_result[0], ny = closed_form_result[1], nz = closed_form_result[2];
|
|
502
|
+
|
|
503
|
+
const depth = closed_form_result[3];
|
|
504
|
+
const wsx = closed_form_result[4], wsy = closed_form_result[5], wsz = closed_form_result[6];
|
|
505
|
+
const wbx = closed_form_result[7], wby = closed_form_result[8], wbz = closed_form_result[9];
|
|
506
|
+
// Feature id from the box-local voronoi region (1..27) — stable
|
|
507
|
+
// while the sphere stays on the same face / edge / vertex of the
|
|
508
|
+
// box, which is the steady-state case for resting / sliding contact.
|
|
509
|
+
|
|
510
|
+
const fid = sphere_box_voronoi_fid(
|
|
511
|
+
sphereTr.position.x, sphereTr.position.y, sphereTr.position.z,
|
|
512
|
+
boxTr.position.x, boxTr.position.y, boxTr.position.z,
|
|
513
|
+
boxTr.rotation.x, boxTr.rotation.y, boxTr.rotation.z, boxTr.rotation.w,
|
|
514
|
+
bh.x, bh.y, bh.z
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
if (isSphereA) {
|
|
518
|
+
return append_contact(count, wsx, wsy, wsz, wbx, wby, wbz, nx, ny, nz, depth, fid);
|
|
519
|
+
} else {
|
|
520
|
+
return append_contact(count, wbx, wby, wbz, wsx, wsy, wsz, -nx, -ny, -nz, depth, fid);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// box-box multi-point
|
|
525
|
+
if (isBoxA && isBoxB) {
|
|
526
|
+
const ah = shapeA.half_extents;
|
|
527
|
+
const bh = shapeB.half_extents;
|
|
528
|
+
const ok = box_box_manifold(
|
|
529
|
+
box_manifold_result,
|
|
530
|
+
trA.position.x, trA.position.y, trA.position.z,
|
|
531
|
+
trA.rotation.x, trA.rotation.y, trA.rotation.z, trA.rotation.w,
|
|
532
|
+
ah.x, ah.y, ah.z,
|
|
533
|
+
trB.position.x, trB.position.y, trB.position.z,
|
|
534
|
+
trB.rotation.x, trB.rotation.y, trB.rotation.z, trB.rotation.w,
|
|
535
|
+
bh.x, bh.y, bh.z
|
|
536
|
+
);
|
|
537
|
+
if (!ok) return count;
|
|
538
|
+
const nx = box_manifold_result[0], ny = box_manifold_result[1], nz = box_manifold_result[2];
|
|
539
|
+
const cc = box_manifold_result[3] | 0;
|
|
540
|
+
// Box-box manifolds: closed-form clipping doesn't expose stable
|
|
541
|
+
// per-contact feature ids (a contact migrates from "incident-vertex k"
|
|
542
|
+
// to "clip-intersection on edge j" as the boxes rotate). Leave
|
|
543
|
+
// fid = 0 so the match-and-merge pass uses position-fallback —
|
|
544
|
+
// the per-contact clipped points are spread by face geometry and
|
|
545
|
+
// typically stay >>MATCH_TOL apart, so position matching is
|
|
546
|
+
// unambiguous frame-to-frame.
|
|
547
|
+
for (let k = 0; k < cc; k++) {
|
|
548
|
+
const base = 4 + k * 7;
|
|
549
|
+
count = append_contact(count,
|
|
550
|
+
box_manifold_result[base], box_manifold_result[base + 1], box_manifold_result[base + 2],
|
|
551
|
+
box_manifold_result[base + 3], box_manifold_result[base + 4], box_manifold_result[base + 5],
|
|
552
|
+
nx, ny, nz,
|
|
553
|
+
box_manifold_result[base + 6],
|
|
554
|
+
0);
|
|
555
|
+
}
|
|
556
|
+
return count;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// capsule-capsule (multi-point: near-parallel overlap emits both ends of
|
|
560
|
+
// the overlap interval; everything else the single closest-point contact)
|
|
561
|
+
if (isCapsuleA && isCapsuleB) {
|
|
562
|
+
const a_shape = colA.shape, b_shape = colB.shape;
|
|
563
|
+
const n_cc = capsule_capsule_multi_contacts(
|
|
564
|
+
capsule_capsule_result,
|
|
565
|
+
trA.position.x, trA.position.y, trA.position.z,
|
|
566
|
+
trA.rotation.x, trA.rotation.y, trA.rotation.z, trA.rotation.w,
|
|
567
|
+
a_shape.radius, a_shape.height * 0.5,
|
|
568
|
+
trB.position.x, trB.position.y, trB.position.z,
|
|
569
|
+
trB.rotation.x, trB.rotation.y, trB.rotation.z, trB.rotation.w,
|
|
570
|
+
b_shape.radius, b_shape.height * 0.5
|
|
571
|
+
);
|
|
572
|
+
for (let k = 0; k < n_cc; k++) {
|
|
573
|
+
const off = k * CAPSULE_CAPSULE_CONTACT_STRIDE;
|
|
574
|
+
// fid = k + 1: stable per interval end (1-based; 0 = no info).
|
|
575
|
+
count = append_contact(count,
|
|
576
|
+
capsule_capsule_result[off], capsule_capsule_result[off + 1], capsule_capsule_result[off + 2],
|
|
577
|
+
capsule_capsule_result[off + 3], capsule_capsule_result[off + 4], capsule_capsule_result[off + 5],
|
|
578
|
+
capsule_capsule_result[off + 6], capsule_capsule_result[off + 7], capsule_capsule_result[off + 8],
|
|
579
|
+
capsule_capsule_result[off + 9], k + 1);
|
|
580
|
+
}
|
|
581
|
+
return count;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// capsule ↔ sphere
|
|
585
|
+
if ((isCapsuleA && isSphereB) || (isSphereA && isCapsuleB)) {
|
|
586
|
+
const capsuleTr = isCapsuleA ? trA : trB;
|
|
587
|
+
const capsuleShape = isCapsuleA ? colA.shape : colB.shape;
|
|
588
|
+
const sphereTr = isCapsuleA ? trB : trA;
|
|
589
|
+
const sphereShape = isCapsuleA ? colB.shape : colA.shape;
|
|
590
|
+
const ok = capsule_sphere_contact(
|
|
591
|
+
closed_form_result,
|
|
592
|
+
capsuleTr.position.x, capsuleTr.position.y, capsuleTr.position.z,
|
|
593
|
+
capsuleTr.rotation.x, capsuleTr.rotation.y, capsuleTr.rotation.z, capsuleTr.rotation.w,
|
|
594
|
+
capsuleShape.radius, capsuleShape.height * 0.5,
|
|
595
|
+
sphereTr.position.x, sphereTr.position.y, sphereTr.position.z, sphereShape.radius
|
|
596
|
+
);
|
|
597
|
+
if (!ok) return count;
|
|
598
|
+
let nx = closed_form_result[0], ny = closed_form_result[1], nz = closed_form_result[2];
|
|
599
|
+
const depth = closed_form_result[3];
|
|
600
|
+
const cap_x = closed_form_result[4], cap_y = closed_form_result[5], cap_z = closed_form_result[6];
|
|
601
|
+
const sph_x = closed_form_result[7], sph_y = closed_form_result[8], sph_z = closed_form_result[9];
|
|
602
|
+
// Single contact per capsule-sphere pair; fid = 1.
|
|
603
|
+
if (isCapsuleA) {
|
|
604
|
+
return append_contact(count, cap_x, cap_y, cap_z, sph_x, sph_y, sph_z, nx, ny, nz, depth, 1);
|
|
605
|
+
} else {
|
|
606
|
+
return append_contact(count, sph_x, sph_y, sph_z, cap_x, cap_y, cap_z, -nx, -ny, -nz, depth, 1);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// capsule ↔ box (multi-point — 1 closest-segment + up to 2 cap-centres)
|
|
611
|
+
if ((isCapsuleA && isBoxB) || (isBoxA && isCapsuleB)) {
|
|
612
|
+
const capsuleTr = isCapsuleA ? trA : trB;
|
|
613
|
+
const capsuleShape = isCapsuleA ? shapeA : shapeB;
|
|
614
|
+
const boxTr = isCapsuleA ? trB : trA;
|
|
615
|
+
const boxShape = isCapsuleA ? shapeB : shapeA;
|
|
616
|
+
const bh = boxShape.half_extents;
|
|
617
|
+
const cc = capsule_box_multi_contacts(
|
|
618
|
+
capsule_box_multi_result,
|
|
619
|
+
capsuleTr.position.x, capsuleTr.position.y, capsuleTr.position.z,
|
|
620
|
+
capsuleTr.rotation.x, capsuleTr.rotation.y, capsuleTr.rotation.z, capsuleTr.rotation.w,
|
|
621
|
+
capsuleShape.radius, capsuleShape.height * 0.5,
|
|
622
|
+
boxTr.position.x, boxTr.position.y, boxTr.position.z,
|
|
623
|
+
boxTr.rotation.x, boxTr.rotation.y, boxTr.rotation.z, boxTr.rotation.w,
|
|
624
|
+
bh.x, bh.y, bh.z
|
|
625
|
+
);
|
|
626
|
+
if (cc === 0) return count;
|
|
627
|
+
// multi_result layout per contact: cap_x/y/z (A side), box_x/y/z (B side), nx/ny/nz, depth.
|
|
628
|
+
// Feature id per sub-contact: 1 = closest-segment, 2/3 = caps. The
|
|
629
|
+
// emission order from capsule_box_multi_contacts is stable across
|
|
630
|
+
// frames for the same geometric configuration.
|
|
631
|
+
for (let k = 0; k < cc; k++) {
|
|
632
|
+
const o = k * CAPSULE_BOX_CONTACT_STRIDE;
|
|
633
|
+
const cap_x = capsule_box_multi_result[o];
|
|
634
|
+
const cap_y = capsule_box_multi_result[o + 1];
|
|
635
|
+
const cap_z = capsule_box_multi_result[o + 2];
|
|
636
|
+
const box_x = capsule_box_multi_result[o + 3];
|
|
637
|
+
const box_y = capsule_box_multi_result[o + 4];
|
|
638
|
+
const box_z = capsule_box_multi_result[o + 5];
|
|
639
|
+
const nx = capsule_box_multi_result[o + 6];
|
|
640
|
+
const ny = capsule_box_multi_result[o + 7];
|
|
641
|
+
const nz = capsule_box_multi_result[o + 8];
|
|
642
|
+
const depth = capsule_box_multi_result[o + 9];
|
|
643
|
+
const sub_fid = k + 1;
|
|
644
|
+
if (isCapsuleA) {
|
|
645
|
+
count = append_contact(count, cap_x, cap_y, cap_z, box_x, box_y, box_z, nx, ny, nz, depth, sub_fid);
|
|
646
|
+
} else {
|
|
647
|
+
count = append_contact(count, box_x, box_y, box_z, cap_x, cap_y, cap_z, -nx, -ny, -nz, depth, sub_fid);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return count;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// convex hull ↔ convex hull (multi-point clipping via GJK + EPA + face-clip).
|
|
654
|
+
if (shapeA.isConvexHullShape3D === true && shapeB.isConvexHullShape3D === true) {
|
|
655
|
+
return hull_pair_contacts(count, shapeA, trA, shapeB, trB, append_contact);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// mesh ↔ mesh. A globally-convex mesh collides as a single cached hull
|
|
659
|
+
// (one GJK + EPA + clip) — the greedy decomposition fragments even a convex
|
|
660
|
+
// mesh, so detecting convexity and routing through the hull path is the
|
|
661
|
+
// scalable fast path. When BOTH meshes are convex, use it; otherwise fall to
|
|
662
|
+
// the per-piece decomposed path (convex pieces vs convex pieces).
|
|
663
|
+
if (shapeA.isMeshShape3D === true && shapeB.isMeshShape3D === true) {
|
|
664
|
+
const hullA = get_mesh_convex_hull(shapeA);
|
|
665
|
+
const hullB = get_mesh_convex_hull(shapeB);
|
|
666
|
+
if (hullA !== null && hullB !== null) {
|
|
667
|
+
return hull_pair_contacts(count, hullA, trA, hullB, trB, append_contact);
|
|
668
|
+
}
|
|
669
|
+
return mesh_mesh_tet_contacts(count, shapeA, trA, shapeB, trB, append_contact);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// ── Concave (non-convex) path ───────────────────────────────────────
|
|
673
|
+
//
|
|
674
|
+
// If either shape has `is_convex === false`, GJK on the whole shape
|
|
675
|
+
// produces incorrect results (Minkowski difference is not convex).
|
|
676
|
+
// We decompose the concave side into triangles overlapping the
|
|
677
|
+
// convex side's AABB, then run convex per-triangle GJK + EPA.
|
|
678
|
+
//
|
|
679
|
+
// Concave-vs-concave is intentionally NOT supported in v1: the
|
|
680
|
+
// M×N triangle pairs would dominate runtime, and the physics
|
|
681
|
+
// engine's design contract requires at least one side to be
|
|
682
|
+
// static / kinematic for concave shapes anyway (the broadphase +
|
|
683
|
+
// filter should keep such pairs out of the narrowphase entirely).
|
|
684
|
+
// If one slips through, we skip rather than burn cycles.
|
|
685
|
+
const isConcaveA = shapeA.is_convex === false;
|
|
686
|
+
const isConcaveB = shapeB.is_convex === false;
|
|
687
|
+
if (isConcaveA && isConcaveB) return count;
|
|
688
|
+
if (isConcaveA || isConcaveB) {
|
|
689
|
+
const concave_col = isConcaveA ? colA : colB;
|
|
690
|
+
const concave_tr = isConcaveA ? trA : trB;
|
|
691
|
+
const convex_col = isConcaveA ? colB : colA;
|
|
692
|
+
const convex_tr = isConcaveA ? trB : trA;
|
|
693
|
+
|
|
694
|
+
// 1. Convex shape's world AABB.
|
|
695
|
+
convex_col.shape.compute_bounding_box(concave_local_aabb);
|
|
696
|
+
aabb3_transform_oriented(
|
|
697
|
+
concave_world_aabb, 0,
|
|
698
|
+
concave_local_aabb[0], concave_local_aabb[1], concave_local_aabb[2],
|
|
699
|
+
concave_local_aabb[3], concave_local_aabb[4], concave_local_aabb[5],
|
|
700
|
+
convex_tr.position.x, convex_tr.position.y, convex_tr.position.z,
|
|
701
|
+
convex_tr.rotation.x, convex_tr.rotation.y, convex_tr.rotation.z, convex_tr.rotation.w
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
// 2. Project into concave's body-local frame.
|
|
705
|
+
aabb3_transform_oriented_inverse(
|
|
706
|
+
concave_query_aabb, 0,
|
|
707
|
+
concave_world_aabb,
|
|
708
|
+
concave_tr.position.x, concave_tr.position.y, concave_tr.position.z,
|
|
709
|
+
concave_tr.rotation.x, concave_tr.rotation.y, concave_tr.rotation.z, concave_tr.rotation.w
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
// 3. Decompose concave shape into triangles overlapping the query.
|
|
713
|
+
// The enumerator returns the TRUE overlap count — clamp to the
|
|
714
|
+
// scratch capacity (overflow writes were dropped; reading past the
|
|
715
|
+
// buffer would poison the manifold with NaN).
|
|
716
|
+
let tri_count = decompose_to_triangles(
|
|
717
|
+
triangle_buffer, 0, concave_col.shape,
|
|
718
|
+
concave_query_aabb[0], concave_query_aabb[1], concave_query_aabb[2],
|
|
719
|
+
concave_query_aabb[3], concave_query_aabb[4], concave_query_aabb[5]
|
|
720
|
+
);
|
|
721
|
+
if (tri_count > MAX_TRIANGLES_PER_PAIR) tri_count = MAX_TRIANGLES_PER_PAIR;
|
|
722
|
+
if (tri_count === 0) return count;
|
|
723
|
+
|
|
724
|
+
// 4. Set up the convex side once; the concave side gets a
|
|
725
|
+
// Triangle3D rebound to each triangle in the loop. We keep
|
|
726
|
+
// the concave side as our internal "A" so EPA's sign-check
|
|
727
|
+
// convention matches the convex fallback below; the final
|
|
728
|
+
// append_contact() swaps if the original A was the convex one.
|
|
729
|
+
posed_b.setup(convex_col.shape, convex_tr.position, convex_tr.rotation);
|
|
730
|
+
posed_a.shape = triangle_shape;
|
|
731
|
+
posed_a.px = concave_tr.position.x;
|
|
732
|
+
posed_a.py = concave_tr.position.y;
|
|
733
|
+
posed_a.pz = concave_tr.position.z;
|
|
734
|
+
posed_a.qx = concave_tr.rotation.x;
|
|
735
|
+
posed_a.qy = concave_tr.rotation.y;
|
|
736
|
+
posed_a.qz = concave_tr.rotation.z;
|
|
737
|
+
posed_a.qw = concave_tr.rotation.w;
|
|
738
|
+
|
|
739
|
+
// Pre-compute the centre-axis used by EPA's sign-check loop.
|
|
740
|
+
// For convex-vs-convex this is `(B - A) = convex_centre − concave_centre`.
|
|
741
|
+
const convex_wx = convex_tr.position.x;
|
|
742
|
+
const convex_wy = convex_tr.position.y;
|
|
743
|
+
const convex_wz = convex_tr.position.z;
|
|
744
|
+
|
|
745
|
+
// Track the candidate-buffer index at the start of this
|
|
746
|
+
// concave dispatch — the per-triangle dedup pass scans from
|
|
747
|
+
// here to the current count, ignoring contacts from earlier
|
|
748
|
+
// collider pairs in the same body pair.
|
|
749
|
+
const pair_start_count = count;
|
|
750
|
+
|
|
751
|
+
// Pre-compute concave's rotation components for the q · v · q⁻¹
|
|
752
|
+
// rotations done per-triangle below (face normal + centroid).
|
|
753
|
+
const cqx = concave_tr.rotation.x;
|
|
754
|
+
const cqy = concave_tr.rotation.y;
|
|
755
|
+
const cqz = concave_tr.rotation.z;
|
|
756
|
+
const cqw = concave_tr.rotation.w;
|
|
757
|
+
const c_pos_x = concave_tr.position.x;
|
|
758
|
+
const c_pos_y = concave_tr.position.y;
|
|
759
|
+
const c_pos_z = concave_tr.position.z;
|
|
760
|
+
|
|
761
|
+
// Sphere fast-path: when the convex side is a sphere we bypass GJK+EPA
|
|
762
|
+
// entirely per triangle and use the closed-form
|
|
763
|
+
// {@link sphere_triangle_contact}. This avoids the EPA precision
|
|
764
|
+
// wall on Triangle3D (whose support function is degenerate along
|
|
765
|
+
// the face normal — all 3 vertices project to the same value),
|
|
766
|
+
// which was producing noisy depths at small penetrations and
|
|
767
|
+
// letting dropped spheres tunnel through heightmaps / meshes.
|
|
768
|
+
const isSphereConvex = convex_col.shape.isSphereShape3D === true;
|
|
769
|
+
const sphere_radius = isSphereConvex ? convex_col.shape.radius : 0;
|
|
770
|
+
|
|
771
|
+
// Box fast-path: closed-form {@link box_triangle_contact} via SAT
|
|
772
|
+
// over 13 axes + polygon clipping for face-vs-face contacts.
|
|
773
|
+
// Same motivation as the sphere path — Triangle3D's degenerate
|
|
774
|
+
// face-normal support kills EPA precision and produces noisy
|
|
775
|
+
// depths. The box path uses world-space triangle vertices.
|
|
776
|
+
const isBoxConvex = convex_col.shape.isBoxShape3D === true;
|
|
777
|
+
const box_half_extents = isBoxConvex ? convex_col.shape.half_extents : null;
|
|
778
|
+
|
|
779
|
+
// Capsule fast-path: closed-form {@link capsule_triangle_contact}
|
|
780
|
+
// via segment-vs-triangle closest-point + cap-centre sphere
|
|
781
|
+
// queries for a multi-point manifold. Same motivation as the
|
|
782
|
+
// sphere and box paths.
|
|
783
|
+
const isCapsuleConvex = convex_col.shape.isCapsuleShape3D === true;
|
|
784
|
+
const capsule_shape = isCapsuleConvex ? convex_col.shape : null;
|
|
785
|
+
|
|
786
|
+
for (let i = 0; i < tri_count; i++) {
|
|
787
|
+
const tri_offset = i * TRIANGLE_FLOAT_STRIDE;
|
|
788
|
+
triangle_shape.bind(triangle_buffer, tri_offset);
|
|
789
|
+
|
|
790
|
+
const ax = triangle_buffer[tri_offset ];
|
|
791
|
+
const ay = triangle_buffer[tri_offset + 1];
|
|
792
|
+
const az = triangle_buffer[tri_offset + 2];
|
|
793
|
+
|
|
794
|
+
const bx = triangle_buffer[tri_offset + 3];
|
|
795
|
+
const by = triangle_buffer[tri_offset + 4];
|
|
796
|
+
const bz = triangle_buffer[tri_offset + 5];
|
|
797
|
+
|
|
798
|
+
const cx_v = triangle_buffer[tri_offset + 6];
|
|
799
|
+
const cy_v = triangle_buffer[tri_offset + 7];
|
|
800
|
+
const cz_v = triangle_buffer[tri_offset + 8];
|
|
801
|
+
|
|
802
|
+
// Triangle decomposition emits a stable per-triangle feature_id
|
|
803
|
+
// at offset 9 (TRIANGLE_FEATURE_ID_OFFSET) — same triangle of
|
|
804
|
+
// the same shape gets the same id across frames. This is the
|
|
805
|
+
// gold-standard fid for the match-and-merge pass.
|
|
806
|
+
const tri_fid = triangle_buffer[tri_offset + 9];
|
|
807
|
+
|
|
808
|
+
// Triangle face normal in body-local frame: (B − A) × (C − A).
|
|
809
|
+
// Winding convention (CCW from outside) gives an outward face
|
|
810
|
+
// normal — the heightmap / mesh enumerators both promise this.
|
|
811
|
+
const e1x_l = bx - ax, e1y_l = by - ay, e1z_l = bz - az;
|
|
812
|
+
const e2x_l = cx_v - ax, e2y_l = cy_v - ay, e2z_l = cz_v - az;
|
|
813
|
+
|
|
814
|
+
const fnx_l = e1y_l * e2z_l - e1z_l * e2y_l;
|
|
815
|
+
const fny_l = e1z_l * e2x_l - e1x_l * e2z_l;
|
|
816
|
+
const fnz_l = e1x_l * e2y_l - e1y_l * e2x_l;
|
|
817
|
+
|
|
818
|
+
// Rotate face normal to world via concave's quaternion
|
|
819
|
+
// (q · v · q⁻¹). Inlined for V8 inliner — see PosedShape3D.support.
|
|
820
|
+
const fnix = cqw * fnx_l + cqy * fnz_l - cqz * fny_l;
|
|
821
|
+
const fniy = cqw * fny_l + cqz * fnx_l - cqx * fnz_l;
|
|
822
|
+
const fniz = cqw * fnz_l + cqx * fny_l - cqy * fnx_l;
|
|
823
|
+
const fniw = -cqx * fnx_l - cqy * fny_l - cqz * fnz_l;
|
|
824
|
+
|
|
825
|
+
const fnx_w = fnix * cqw - fniw * cqx - fniy * cqz + fniz * cqy;
|
|
826
|
+
const fny_w = fniy * cqw - fniw * cqy - fniz * cqx + fnix * cqz;
|
|
827
|
+
const fnz_w = fniz * cqw - fniw * cqz - fnix * cqy + fniy * cqx;
|
|
828
|
+
|
|
829
|
+
// Sphere-vs-triangle closed-form fast-path.
|
|
830
|
+
if (isSphereConvex) {
|
|
831
|
+
|
|
832
|
+
// Rotate each triangle vertex from concave-local to world
|
|
833
|
+
// via the shared helper.
|
|
834
|
+
triangle_vertices_to_world(
|
|
835
|
+
scratch_tri_world,
|
|
836
|
+
ax, ay, az, bx, by, bz, cx_v, cy_v, cz_v,
|
|
837
|
+
cqx, cqy, cqz, cqw,
|
|
838
|
+
c_pos_x, c_pos_y, c_pos_z
|
|
839
|
+
);
|
|
840
|
+
const ax_w = scratch_tri_world[0], ay_w = scratch_tri_world[1], az_w = scratch_tri_world[2];
|
|
841
|
+
const bx_w = scratch_tri_world[3], by_w = scratch_tri_world[4], bz_w = scratch_tri_world[5];
|
|
842
|
+
const cx_w = scratch_tri_world[6], cy_w = scratch_tri_world[7], cz_w = scratch_tri_world[8];
|
|
843
|
+
|
|
844
|
+
const ok = sphere_triangle_contact(
|
|
845
|
+
sphere_triangle_result,
|
|
846
|
+
convex_wx, convex_wy, convex_wz, sphere_radius,
|
|
847
|
+
ax_w, ay_w, az_w,
|
|
848
|
+
bx_w, by_w, bz_w,
|
|
849
|
+
cx_w, cy_w, cz_w
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
if (!ok) continue;
|
|
853
|
+
|
|
854
|
+
// sphere_triangle_contact's normal points from the
|
|
855
|
+
// triangle surface toward the sphere centre — same
|
|
856
|
+
// direction as the post-sign-check EPA MTV in the
|
|
857
|
+
// fallback path below (concave A → convex B).
|
|
858
|
+
const sd = sphere_triangle_result[3];
|
|
859
|
+
const n_t2s_x = sphere_triangle_result[0];
|
|
860
|
+
const n_t2s_y = sphere_triangle_result[1];
|
|
861
|
+
const n_t2s_z = sphere_triangle_result[2];
|
|
862
|
+
|
|
863
|
+
// One-sided rejection: the sphere must lie on the
|
|
864
|
+
// outward side of the triangle. If the contact normal
|
|
865
|
+
// opposes the face normal, the sphere is behind /
|
|
866
|
+
// inside the solid — skip rather than push it deeper.
|
|
867
|
+
if (n_t2s_x * fnx_w + n_t2s_y * fny_w + n_t2s_z * fnz_w <= 0) continue;
|
|
868
|
+
|
|
869
|
+
// Stored normal convention is "B → A". `nx, ny, nz` here
|
|
870
|
+
// points convex → concave (which the existing EPA branch
|
|
871
|
+
// also produces just before append). Dedup uses the
|
|
872
|
+
// post-swap stored_n so adjacent-triangle duplicates
|
|
873
|
+
// collapse the same way regardless of code path.
|
|
874
|
+
const nx_s = -n_t2s_x;
|
|
875
|
+
const ny_s = -n_t2s_y;
|
|
876
|
+
const nz_s = -n_t2s_z;
|
|
877
|
+
|
|
878
|
+
const stored_nx_s = isConcaveA ? nx_s : -nx_s;
|
|
879
|
+
const stored_ny_s = isConcaveA ? ny_s : -ny_s;
|
|
880
|
+
const stored_nz_s = isConcaveA ? nz_s : -nz_s;
|
|
881
|
+
let is_duplicate_s = false;
|
|
882
|
+
for (let k = pair_start_count; k < count; k++) {
|
|
883
|
+
const ko = k * CANDIDATE_STRIDE;
|
|
884
|
+
const dnx = candidates[ko + 6] - stored_nx_s;
|
|
885
|
+
const dny = candidates[ko + 7] - stored_ny_s;
|
|
886
|
+
const dnz = candidates[ko + 8] - stored_nz_s;
|
|
887
|
+
if (dnx * dnx + dny * dny + dnz * dnz < 0.001) {
|
|
888
|
+
is_duplicate_s = true;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
if (is_duplicate_s) continue;
|
|
893
|
+
|
|
894
|
+
// Surface witnesses from the closed-form solver:
|
|
895
|
+
// result[4..6] = sphere surface point (convex side)
|
|
896
|
+
// result[7..9] = triangle closest point (concave side)
|
|
897
|
+
// Use the actual witnesses rather than body centres —
|
|
898
|
+
// unlike the EPA fallback (which uses body centres
|
|
899
|
+
// because flat-faced support witnesses can be arbitrarily
|
|
900
|
+
// far from the contact patch), closest-point-on-triangle
|
|
901
|
+
// is exact and lies on the contact patch.
|
|
902
|
+
const sphere_wx = sphere_triangle_result[4];
|
|
903
|
+
const sphere_wy = sphere_triangle_result[5];
|
|
904
|
+
const sphere_wz = sphere_triangle_result[6];
|
|
905
|
+
const tri_wx = sphere_triangle_result[7];
|
|
906
|
+
const tri_wy = sphere_triangle_result[8];
|
|
907
|
+
const tri_wz = sphere_triangle_result[9];
|
|
908
|
+
if (isConcaveA) {
|
|
909
|
+
count = append_contact(count,
|
|
910
|
+
tri_wx, tri_wy, tri_wz,
|
|
911
|
+
sphere_wx, sphere_wy, sphere_wz,
|
|
912
|
+
nx_s, ny_s, nz_s, sd, tri_fid);
|
|
913
|
+
} else {
|
|
914
|
+
count = append_contact(count,
|
|
915
|
+
sphere_wx, sphere_wy, sphere_wz,
|
|
916
|
+
tri_wx, tri_wy, tri_wz,
|
|
917
|
+
-nx_s, -ny_s, -nz_s, sd, tri_fid);
|
|
918
|
+
}
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// Box-vs-triangle closed-form fast-path.
|
|
923
|
+
if (isBoxConvex) {
|
|
924
|
+
// Rotate each triangle vertex from concave-local to world
|
|
925
|
+
// via the shared helper.
|
|
926
|
+
triangle_vertices_to_world(
|
|
927
|
+
scratch_tri_world,
|
|
928
|
+
ax, ay, az, bx, by, bz, cx_v, cy_v, cz_v,
|
|
929
|
+
cqx, cqy, cqz, cqw,
|
|
930
|
+
c_pos_x, c_pos_y, c_pos_z
|
|
931
|
+
);
|
|
932
|
+
const ax_w = scratch_tri_world[0], ay_w = scratch_tri_world[1], az_w = scratch_tri_world[2];
|
|
933
|
+
const bx_w = scratch_tri_world[3], by_w = scratch_tri_world[4], bz_w = scratch_tri_world[5];
|
|
934
|
+
const cx_w = scratch_tri_world[6], cy_w = scratch_tri_world[7], cz_w = scratch_tri_world[8];
|
|
935
|
+
|
|
936
|
+
const ok = box_triangle_contact(
|
|
937
|
+
box_triangle_result,
|
|
938
|
+
convex_tr.position.x, convex_tr.position.y, convex_tr.position.z,
|
|
939
|
+
convex_tr.rotation.x, convex_tr.rotation.y, convex_tr.rotation.z, convex_tr.rotation.w,
|
|
940
|
+
box_half_extents.x, box_half_extents.y, box_half_extents.z,
|
|
941
|
+
ax_w, ay_w, az_w,
|
|
942
|
+
bx_w, by_w, bz_w,
|
|
943
|
+
cx_w, cy_w, cz_w
|
|
944
|
+
);
|
|
945
|
+
if (!ok) continue;
|
|
946
|
+
|
|
947
|
+
// Same convention as sphere_triangle: result normal points
|
|
948
|
+
// from triangle surface toward box centre. To match the
|
|
949
|
+
// EPA branch's `nx, ny, nz` (which points convex →
|
|
950
|
+
// concave = box → triangle), negate.
|
|
951
|
+
const n_t2box_x = box_triangle_result[0];
|
|
952
|
+
const n_t2box_y = box_triangle_result[1];
|
|
953
|
+
const n_t2box_z = box_triangle_result[2];
|
|
954
|
+
|
|
955
|
+
// One-sided rejection: the box must lie on the outward
|
|
956
|
+
// side of the triangle. If the contact normal opposes
|
|
957
|
+
// the face normal, the box is inside the solid → skip.
|
|
958
|
+
if (n_t2box_x * fnx_w + n_t2box_y * fny_w + n_t2box_z * fnz_w <= 0) continue;
|
|
959
|
+
|
|
960
|
+
const nx_b = -n_t2box_x;
|
|
961
|
+
const ny_b = -n_t2box_y;
|
|
962
|
+
const nz_b = -n_t2box_z;
|
|
963
|
+
const stored_nx_b = isConcaveA ? nx_b : -nx_b;
|
|
964
|
+
const stored_ny_b = isConcaveA ? ny_b : -ny_b;
|
|
965
|
+
const stored_nz_b = isConcaveA ? nz_b : -nz_b;
|
|
966
|
+
|
|
967
|
+
// Emit each clipped contact. The contact count from
|
|
968
|
+
// box_triangle_contact is at most 4; combined with the
|
|
969
|
+
// existing per-pair candidate cap (64 entries), tens of
|
|
970
|
+
// overlapping triangles per pair are safely accommodated.
|
|
971
|
+
const cc = box_triangle_result[3] | 0;
|
|
972
|
+
for (let k = 0; k < cc; k++) {
|
|
973
|
+
const base = 4 + k * 7;
|
|
974
|
+
const t_wx = box_triangle_result[base];
|
|
975
|
+
const t_wy = box_triangle_result[base + 1];
|
|
976
|
+
const t_wz = box_triangle_result[base + 2];
|
|
977
|
+
const b_wx = box_triangle_result[base + 3];
|
|
978
|
+
const b_wy = box_triangle_result[base + 4];
|
|
979
|
+
const b_wz = box_triangle_result[base + 5];
|
|
980
|
+
const d_k = box_triangle_result[base + 6];
|
|
981
|
+
|
|
982
|
+
// Dedup against earlier candidates in THIS dispatch
|
|
983
|
+
// (adjacent triangles can produce coincident contacts
|
|
984
|
+
// — same as the sphere and EPA paths).
|
|
985
|
+
let is_duplicate_k = false;
|
|
986
|
+
for (let q = pair_start_count; q < count; q++) {
|
|
987
|
+
const qo = q * CANDIDATE_STRIDE;
|
|
988
|
+
const dnx = candidates[qo + 6] - stored_nx_b;
|
|
989
|
+
const dny = candidates[qo + 7] - stored_ny_b;
|
|
990
|
+
const dnz = candidates[qo + 8] - stored_nz_b;
|
|
991
|
+
if (dnx * dnx + dny * dny + dnz * dnz < 0.001) {
|
|
992
|
+
// Same normal; check positions too (a
|
|
993
|
+
// multi-point manifold has distinct points
|
|
994
|
+
// with the same normal — those should NOT
|
|
995
|
+
// be deduped). Compare the world-A side
|
|
996
|
+
// (triangle surface or box surface depending
|
|
997
|
+
// on dispatcher swap).
|
|
998
|
+
const pa_x = isConcaveA ? t_wx : b_wx;
|
|
999
|
+
const pa_y = isConcaveA ? t_wy : b_wy;
|
|
1000
|
+
const pa_z = isConcaveA ? t_wz : b_wz;
|
|
1001
|
+
const dpx = candidates[qo] - pa_x;
|
|
1002
|
+
const dpy = candidates[qo + 1] - pa_y;
|
|
1003
|
+
const dpz = candidates[qo + 2] - pa_z;
|
|
1004
|
+
if (dpx * dpx + dpy * dpy + dpz * dpz < 1e-6) {
|
|
1005
|
+
is_duplicate_k = true;
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (is_duplicate_k) continue;
|
|
1011
|
+
|
|
1012
|
+
if (isConcaveA) {
|
|
1013
|
+
count = append_contact(count,
|
|
1014
|
+
t_wx, t_wy, t_wz,
|
|
1015
|
+
b_wx, b_wy, b_wz,
|
|
1016
|
+
nx_b, ny_b, nz_b, d_k, tri_fid);
|
|
1017
|
+
} else {
|
|
1018
|
+
count = append_contact(count,
|
|
1019
|
+
b_wx, b_wy, b_wz,
|
|
1020
|
+
t_wx, t_wy, t_wz,
|
|
1021
|
+
-nx_b, -ny_b, -nz_b, d_k, tri_fid);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// Capsule-vs-triangle closed-form fast-path.
|
|
1028
|
+
if (isCapsuleConvex) {
|
|
1029
|
+
// Rotate each triangle vertex from concave-local to world
|
|
1030
|
+
// via the shared helper.
|
|
1031
|
+
triangle_vertices_to_world(
|
|
1032
|
+
scratch_tri_world,
|
|
1033
|
+
ax, ay, az, bx, by, bz, cx_v, cy_v, cz_v,
|
|
1034
|
+
cqx, cqy, cqz, cqw,
|
|
1035
|
+
c_pos_x, c_pos_y, c_pos_z
|
|
1036
|
+
);
|
|
1037
|
+
const ax_w = scratch_tri_world[0], ay_w = scratch_tri_world[1], az_w = scratch_tri_world[2];
|
|
1038
|
+
const bx_w = scratch_tri_world[3], by_w = scratch_tri_world[4], bz_w = scratch_tri_world[5];
|
|
1039
|
+
const cx_w = scratch_tri_world[6], cy_w = scratch_tri_world[7], cz_w = scratch_tri_world[8];
|
|
1040
|
+
|
|
1041
|
+
const cap_cc = capsule_triangle_contact(
|
|
1042
|
+
capsule_triangle_result,
|
|
1043
|
+
convex_tr.position.x, convex_tr.position.y, convex_tr.position.z,
|
|
1044
|
+
convex_tr.rotation.x, convex_tr.rotation.y, convex_tr.rotation.z, convex_tr.rotation.w,
|
|
1045
|
+
capsule_shape.radius, capsule_shape.height * 0.5,
|
|
1046
|
+
ax_w, ay_w, az_w,
|
|
1047
|
+
bx_w, by_w, bz_w,
|
|
1048
|
+
cx_w, cy_w, cz_w
|
|
1049
|
+
);
|
|
1050
|
+
if (cap_cc === 0) continue;
|
|
1051
|
+
|
|
1052
|
+
// Each sub-contact's normal can be distinct (a flat
|
|
1053
|
+
// capsule produces primary + endpoint contacts whose
|
|
1054
|
+
// normals all point ≈ same direction, but an edge or
|
|
1055
|
+
// vertex contact at a cap can deviate). Apply
|
|
1056
|
+
// face-normal rejection per-contact.
|
|
1057
|
+
for (let k = 0; k < cap_cc; k++) {
|
|
1058
|
+
const base = k * CAPSULE_TRIANGLE_CONTACT_STRIDE;
|
|
1059
|
+
const cap_x = capsule_triangle_result[base];
|
|
1060
|
+
const cap_y = capsule_triangle_result[base + 1];
|
|
1061
|
+
const cap_z = capsule_triangle_result[base + 2];
|
|
1062
|
+
const ct_x = capsule_triangle_result[base + 3];
|
|
1063
|
+
const ct_y = capsule_triangle_result[base + 4];
|
|
1064
|
+
const ct_z = capsule_triangle_result[base + 5];
|
|
1065
|
+
const n_t2cap_x = capsule_triangle_result[base + 6];
|
|
1066
|
+
const n_t2cap_y = capsule_triangle_result[base + 7];
|
|
1067
|
+
const n_t2cap_z = capsule_triangle_result[base + 8];
|
|
1068
|
+
const d_c = capsule_triangle_result[base + 9];
|
|
1069
|
+
|
|
1070
|
+
// One-sided face-normal rejection: capsule must be
|
|
1071
|
+
// on the outward side of the triangle.
|
|
1072
|
+
if (n_t2cap_x * fnx_w + n_t2cap_y * fny_w + n_t2cap_z * fnz_w <= 0) continue;
|
|
1073
|
+
|
|
1074
|
+
// Stored normal "convex → concave" = "capsule →
|
|
1075
|
+
// triangle" = negated t2cap.
|
|
1076
|
+
const nx_c = -n_t2cap_x;
|
|
1077
|
+
const ny_c = -n_t2cap_y;
|
|
1078
|
+
const nz_c = -n_t2cap_z;
|
|
1079
|
+
const stored_nx_c = isConcaveA ? nx_c : -nx_c;
|
|
1080
|
+
const stored_ny_c = isConcaveA ? ny_c : -ny_c;
|
|
1081
|
+
const stored_nz_c = isConcaveA ? nz_c : -nz_c;
|
|
1082
|
+
|
|
1083
|
+
// Dedup against earlier candidates in THIS dispatch.
|
|
1084
|
+
let is_duplicate_c = false;
|
|
1085
|
+
for (let q = pair_start_count; q < count; q++) {
|
|
1086
|
+
const qo = q * CANDIDATE_STRIDE;
|
|
1087
|
+
const dnx = candidates[qo + 6] - stored_nx_c;
|
|
1088
|
+
const dny = candidates[qo + 7] - stored_ny_c;
|
|
1089
|
+
const dnz = candidates[qo + 8] - stored_nz_c;
|
|
1090
|
+
if (dnx * dnx + dny * dny + dnz * dnz < 0.001) {
|
|
1091
|
+
const pa_x = isConcaveA ? ct_x : cap_x;
|
|
1092
|
+
const pa_y = isConcaveA ? ct_y : cap_y;
|
|
1093
|
+
const pa_z = isConcaveA ? ct_z : cap_z;
|
|
1094
|
+
const dpx = candidates[qo] - pa_x;
|
|
1095
|
+
const dpy = candidates[qo + 1] - pa_y;
|
|
1096
|
+
const dpz = candidates[qo + 2] - pa_z;
|
|
1097
|
+
if (dpx * dpx + dpy * dpy + dpz * dpz < 1e-6) {
|
|
1098
|
+
is_duplicate_c = true;
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
if (is_duplicate_c) continue;
|
|
1104
|
+
|
|
1105
|
+
if (isConcaveA) {
|
|
1106
|
+
count = append_contact(count,
|
|
1107
|
+
ct_x, ct_y, ct_z,
|
|
1108
|
+
cap_x, cap_y, cap_z,
|
|
1109
|
+
nx_c, ny_c, nz_c, d_c, tri_fid);
|
|
1110
|
+
} else {
|
|
1111
|
+
count = append_contact(count,
|
|
1112
|
+
cap_x, cap_y, cap_z,
|
|
1113
|
+
ct_x, ct_y, ct_z,
|
|
1114
|
+
-nx_c, -ny_c, -nz_c, d_c, tri_fid);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// Robust GJK + EPA (see gjk/gjk_epa_penetration.js): returns the
|
|
1121
|
+
// penetration depth and writes a UNIT axis into epa_result. We scale
|
|
1122
|
+
// it to the MTV vector (ex,ey,ez) the tuned sign-check / one-sided
|
|
1123
|
+
// rejection / dedup below already consume. The old gjk_with_axis +
|
|
1124
|
+
// expanding_polytope_algorithm pair was replaced because it returned
|
|
1125
|
+
// a non-minimal axis on degenerate simplices (see memory:
|
|
1126
|
+
// feedback_epa_unreliable_polytopes); MPR is kept as a secondary
|
|
1127
|
+
// safety net for the rare case the robust query reports no overlap.
|
|
1128
|
+
let ex, ey, ez, depth;
|
|
1129
|
+
const pen_depth = gjk_epa_penetration(epa_result, posed_a, posed_b);
|
|
1130
|
+
if (pen_depth > 0 && Number.isFinite(pen_depth)) {
|
|
1131
|
+
ex = epa_result[0] * pen_depth; ey = epa_result[1] * pen_depth; ez = epa_result[2] * pen_depth;
|
|
1132
|
+
depth = pen_depth;
|
|
1133
|
+
} else {
|
|
1134
|
+
if (!mpr(epa_result, 0, posed_a, posed_b)) continue;
|
|
1135
|
+
ex = epa_result[0]; ey = epa_result[1]; ez = epa_result[2];
|
|
1136
|
+
depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
|
|
1137
|
+
if (!(depth > 0) || !Number.isFinite(depth)) continue;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// Sign-check: validate MTV direction against (convex −
|
|
1141
|
+
// triangle_centroid). EPA's polytope-closest-face normal
|
|
1142
|
+
// can come out on the wrong side of the origin; this flip
|
|
1143
|
+
// canonicalises MTV to point from triangle (A) toward the
|
|
1144
|
+
// convex shape (B).
|
|
1145
|
+
const cent_lx = (ax + bx + cx_v) / 3;
|
|
1146
|
+
const cent_ly = (ay + by + cy_v) / 3;
|
|
1147
|
+
const cent_lz = (az + bz + cz_v) / 3;
|
|
1148
|
+
// Inlined q · v · q* + translate.
|
|
1149
|
+
const cix = cqw * cent_lx + cqy * cent_lz - cqz * cent_ly;
|
|
1150
|
+
const ciy = cqw * cent_ly + cqz * cent_lx - cqx * cent_lz;
|
|
1151
|
+
const ciz = cqw * cent_lz + cqx * cent_ly - cqy * cent_lx;
|
|
1152
|
+
const ciw = -cqx * cent_lx - cqy * cent_ly - cqz * cent_lz;
|
|
1153
|
+
const cent_wx = cix * cqw + ciw * -cqx + ciy * -cqz - ciz * -cqy + c_pos_x;
|
|
1154
|
+
const cent_wy = ciy * cqw + ciw * -cqy + ciz * -cqx - cix * -cqz + c_pos_y;
|
|
1155
|
+
const cent_wz = ciz * cqw + ciw * -cqz + cix * -cqy - ciy * -cqx + c_pos_z;
|
|
1156
|
+
|
|
1157
|
+
const tri_ab_x = convex_wx - cent_wx;
|
|
1158
|
+
const tri_ab_y = convex_wy - cent_wy;
|
|
1159
|
+
const tri_ab_z = convex_wz - cent_wz;
|
|
1160
|
+
if (ex * tri_ab_x + ey * tri_ab_y + ez * tri_ab_z < 0) {
|
|
1161
|
+
ex = -ex; ey = -ey; ez = -ez;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// One-sided rejection (post-sign-check). MTV now points
|
|
1165
|
+
// from triangle (A) toward convex shape (B). For a CCW
|
|
1166
|
+
// outward-wound triangle, the convex shape is on the
|
|
1167
|
+
// OUTWARD side iff MTV aligns with the face normal. If it
|
|
1168
|
+
// opposes the face normal, the convex shape is on the
|
|
1169
|
+
// back / inward side — invalid for heightmap/mesh (it's
|
|
1170
|
+
// inside the solid). Skip the triangle rather than push
|
|
1171
|
+
// the body deeper into the solid through the opposite
|
|
1172
|
+
// face on the next step.
|
|
1173
|
+
if (ex * fnx_w + ey * fny_w + ez * fnz_w <= 0) continue;
|
|
1174
|
+
|
|
1175
|
+
// After the validated flip, MTV points from triangle
|
|
1176
|
+
// (concave-side A) into convex (B). Stored normal is
|
|
1177
|
+
// "B → A" so we negate. Final A/B order matches
|
|
1178
|
+
// append_contact's contract: original A first, original B
|
|
1179
|
+
// second, normal "from original B toward original A".
|
|
1180
|
+
const inv = 1 / depth;
|
|
1181
|
+
const nx = -ex * inv;
|
|
1182
|
+
const ny = -ey * inv;
|
|
1183
|
+
const nz = -ez * inv;
|
|
1184
|
+
|
|
1185
|
+
// Dedup against earlier contacts emitted in THIS dispatch.
|
|
1186
|
+
// Adjacent triangles (heightmap cells sharing a diagonal;
|
|
1187
|
+
// mesh triangles sharing an edge or vertex) often report
|
|
1188
|
+
// identical contacts (same normal, same body-centre
|
|
1189
|
+
// application points), and feeding duplicates to the
|
|
1190
|
+
// sequential-impulse solver makes it escalate the impulse
|
|
1191
|
+
// across iterations without bound. We deduplicate by
|
|
1192
|
+
// contact normal within a small angular threshold: same
|
|
1193
|
+
// body pair + same normal + same body-centre positions =
|
|
1194
|
+
// the same physical contact, only one copy belongs in the
|
|
1195
|
+
// manifold.
|
|
1196
|
+
const stored_nx = isConcaveA ? nx : -nx;
|
|
1197
|
+
const stored_ny = isConcaveA ? ny : -ny;
|
|
1198
|
+
const stored_nz = isConcaveA ? nz : -nz;
|
|
1199
|
+
let is_duplicate = false;
|
|
1200
|
+
for (let k = pair_start_count; k < count; k++) {
|
|
1201
|
+
const ko = k * CANDIDATE_STRIDE;
|
|
1202
|
+
const dnx = candidates[ko + 6] - stored_nx;
|
|
1203
|
+
const dny = candidates[ko + 7] - stored_ny;
|
|
1204
|
+
const dnz = candidates[ko + 8] - stored_nz;
|
|
1205
|
+
if (dnx * dnx + dny * dny + dnz * dnz < 0.001) {
|
|
1206
|
+
is_duplicate = true;
|
|
1207
|
+
break;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (is_duplicate) continue;
|
|
1211
|
+
|
|
1212
|
+
// Contact application points: body centres rather than
|
|
1213
|
+
// the triangle's centroid. The existing GJK+EPA fallback
|
|
1214
|
+
// (below) uses the same convention — for vertical contacts
|
|
1215
|
+
// (sphere/box on a flat surface, the common case), the
|
|
1216
|
+
// lever arm r × n vanishes and the impulse resolves
|
|
1217
|
+
// cleanly.
|
|
1218
|
+
if (isConcaveA) {
|
|
1219
|
+
count = append_contact(count,
|
|
1220
|
+
c_pos_x, c_pos_y, c_pos_z,
|
|
1221
|
+
convex_wx, convex_wy, convex_wz,
|
|
1222
|
+
nx, ny, nz, depth, tri_fid);
|
|
1223
|
+
} else {
|
|
1224
|
+
count = append_contact(count,
|
|
1225
|
+
convex_wx, convex_wy, convex_wz,
|
|
1226
|
+
c_pos_x, c_pos_y, c_pos_z,
|
|
1227
|
+
-nx, -ny, -nz, depth, tri_fid);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return count;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// Robust GJK + EPA fallback for any convex pair without a closed form or a
|
|
1235
|
+
// dedicated branch above (e.g. a primitive vs an authored ConvexHullShape3D,
|
|
1236
|
+
// a cylinder/cone). gjk_epa_penetration returns the depth and writes a UNIT
|
|
1237
|
+
// axis into epa_result; we scale to the MTV vector (ex,ey,ez) the body-centre
|
|
1238
|
+
// sign-guard below consumes. Replaces the old gjk_with_axis +
|
|
1239
|
+
// expanding_polytope_algorithm pair, which returned a non-minimal axis on the
|
|
1240
|
+
// degenerate simplices its GJK produced (see memory:
|
|
1241
|
+
// feedback_epa_unreliable_polytopes). MPR is kept as a secondary safety net.
|
|
1242
|
+
posed_a.setup(colA.shape, trA.position, trA.rotation);
|
|
1243
|
+
posed_b.setup(colB.shape, trB.position, trB.rotation);
|
|
1244
|
+
|
|
1245
|
+
let ex, ey, ez, depth;
|
|
1246
|
+
const pen_depth = gjk_epa_penetration(epa_result, posed_a, posed_b);
|
|
1247
|
+
if (pen_depth > 0 && Number.isFinite(pen_depth)) {
|
|
1248
|
+
ex = epa_result[0] * pen_depth; ey = epa_result[1] * pen_depth; ez = epa_result[2] * pen_depth;
|
|
1249
|
+
depth = pen_depth;
|
|
1250
|
+
} else {
|
|
1251
|
+
if (!mpr(epa_result, 0, posed_a, posed_b)) return count;
|
|
1252
|
+
ex = epa_result[0]; ey = epa_result[1]; ez = epa_result[2];
|
|
1253
|
+
depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
|
|
1254
|
+
if (!(depth > 0) || !Number.isFinite(depth)) return count;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// EPA's output vector should point along the minimum-translation
|
|
1258
|
+
// axis from A into B (the direction you'd push B by to separate).
|
|
1259
|
+
// On non-convergent EPA — common on smooth high-poly colliders like
|
|
1260
|
+
// a torus knot, where the polytope can't tighten onto the true
|
|
1261
|
+
// closest face within the iteration cap — the fallback returns
|
|
1262
|
+
// *some* face's normal, and that face can be on either side of the
|
|
1263
|
+
// origin. Resulting MTV occasionally points B *into* A instead of
|
|
1264
|
+
// *away from* A; the solver then sees a "separating" relative
|
|
1265
|
+
// velocity, clamps the normal impulse to zero, and the bodies pass
|
|
1266
|
+
// straight through each other.
|
|
1267
|
+
//
|
|
1268
|
+
// Validate against the vector from body A's centre to body B's
|
|
1269
|
+
// centre — EPA's direction must correlate positively with it. Flip
|
|
1270
|
+
// if not. For convex bodies whose origin is inside the geometry,
|
|
1271
|
+
// body-centre-to-body-centre is a strong proxy for the correct
|
|
1272
|
+
// separation direction. For pathological cases (deeply
|
|
1273
|
+
// interpenetrating bodies with coincident centres) the dot product
|
|
1274
|
+
// is near zero and we leave EPA's guess intact.
|
|
1275
|
+
const ab_x = trB.position.x - trA.position.x;
|
|
1276
|
+
const ab_y = trB.position.y - trA.position.y;
|
|
1277
|
+
const ab_z = trB.position.z - trA.position.z;
|
|
1278
|
+
if (ex * ab_x + ey * ab_y + ez * ab_z < 0) {
|
|
1279
|
+
ex = -ex; ey = -ey; ez = -ez;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
const inv = 1 / depth;
|
|
1283
|
+
const nx = -ex * inv, ny = -ey * inv, nz = -ez * inv; // stored normal, B → A
|
|
1284
|
+
|
|
1285
|
+
// Contact application points: body centres rather than support-function
|
|
1286
|
+
// witnesses. The natural-sounding alternative — `posed_a.support(+EPA_dir)`
|
|
1287
|
+
// and `posed_b.support(-EPA_dir)` — interacts badly with flat-faced
|
|
1288
|
+
// supports: a large floor's support in `+Y` returns a *corner* (the box
|
|
1289
|
+
// support is multi-valued along an axis-aligned direction and picks the
|
|
1290
|
+
// sign-tied corner), which can be tens of metres from the actual
|
|
1291
|
+
// contact patch. That blows up the solver's lever arm `r × n` and
|
|
1292
|
+
// collapses `m_eff` to ~0, leaving the impulse vanishingly small.
|
|
1293
|
+
//
|
|
1294
|
+
// Body centres give `r ‖ n` for vertical contacts (sphere/knot landing
|
|
1295
|
+
// on a floor — the common case), so `r × n = 0` and `m_eff = invM`
|
|
1296
|
+
// resolves the impact cleanly. For oblique contacts the application
|
|
1297
|
+
// point lies on the line between centres, which is the right-ish lever
|
|
1298
|
+
// arm for translational impulse and degrades gracefully on angular
|
|
1299
|
+
// response. A future closed-form mesh-vs-box path will compute a
|
|
1300
|
+
// proper face-projected witness; until then, body centres are the
|
|
1301
|
+
// robust fallback for the GJK+EPA route.
|
|
1302
|
+
// GJK+EPA fallback has no stable per-frame feature info; emit fid = 0
|
|
1303
|
+
// so match-and-merge uses position-fallback. Single contact per pair.
|
|
1304
|
+
return append_contact(count,
|
|
1305
|
+
trA.position.x, trA.position.y, trA.position.z,
|
|
1306
|
+
trB.position.x, trB.position.y, trB.position.z,
|
|
1307
|
+
nx, ny, nz,
|
|
1308
|
+
depth, 0
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// Reusable single-pair adapters for the penetration query below — no per-call
|
|
1313
|
+
// allocation. dispatch_pair only reads `.shape` off a collider and
|
|
1314
|
+
// `.position` / `.rotation` off a transform, so these minimal stand-ins are
|
|
1315
|
+
// all it needs.
|
|
1316
|
+
const _pp_colA = { shape: null };
|
|
1317
|
+
const _pp_colB = { shape: null };
|
|
1318
|
+
const _pp_trA = { position: null, rotation: null };
|
|
1319
|
+
const _pp_trB = { position: null, rotation: null };
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Single-pair penetration query: the depth and world normal of the DEEPEST
|
|
1324
|
+
* contact the narrowphase would generate for one posed shape pair.
|
|
1325
|
+
*
|
|
1326
|
+
* Routes through the exact same {@link dispatch_pair} the contact solver
|
|
1327
|
+
* consumes — closed-form for every sphere / box / capsule pair (box-box via
|
|
1328
|
+
* SAT, so the true minimum-translation axis is found rather than the
|
|
1329
|
+
* centroid-seeded portal MPR would pick), triangle decomposition + closed-form
|
|
1330
|
+
* per triangle for convex-vs-concave, and GJK + EPA (+ MPR) for any other
|
|
1331
|
+
* convex pair. The deepest contact's depth is the minimum-translation distance
|
|
1332
|
+
* and its normal is the MTV axis, so the result is correct for every shape pair
|
|
1333
|
+
* the engine can build and agrees bit-for-bit with what the solver acts on.
|
|
1334
|
+
*
|
|
1335
|
+
* The normal follows the narrowphase's stored convention: a unit vector
|
|
1336
|
+
* pointing from B toward A — the direction to translate A to separate it.
|
|
1337
|
+
*
|
|
1338
|
+
* Concave-vs-concave is not dispatched (the narrowphase skips it) and returns
|
|
1339
|
+
* 0; callers needing to reject that case must check `is_convex` themselves.
|
|
1340
|
+
*
|
|
1341
|
+
* Not re-entrant: shares the module-level candidate / scratch buffers with
|
|
1342
|
+
* {@link narrowphase_step}. Intended for main-thread queries run outside a
|
|
1343
|
+
* step (depenetration, overlap depth, tooling) — never from inside one.
|
|
1344
|
+
*
|
|
1345
|
+
* @param {Float64Array|number[]} out_normal length ≥ 3; receives the unit B→A
|
|
1346
|
+
* normal on penetration (untouched when the return value is 0)
|
|
1347
|
+
* @param {AbstractShape3D} shapeA
|
|
1348
|
+
* @param {{x:number,y:number,z:number}} posA
|
|
1349
|
+
* @param {{x:number,y:number,z:number,w:number}} rotA
|
|
1350
|
+
* @param {AbstractShape3D} shapeB
|
|
1351
|
+
* @param {{x:number,y:number,z:number}} posB
|
|
1352
|
+
* @param {{x:number,y:number,z:number,w:number}} rotB
|
|
1353
|
+
* @returns {number} deepest penetration depth (> 0) or 0 if separated
|
|
1354
|
+
*/
|
|
1355
|
+
export function deepest_pair_penetration(out_normal, shapeA, posA, rotA, shapeB, posB, rotB) {
|
|
1356
|
+
_pp_colA.shape = shapeA;
|
|
1357
|
+
_pp_trA.position = posA;
|
|
1358
|
+
_pp_trA.rotation = rotA;
|
|
1359
|
+
_pp_colB.shape = shapeB;
|
|
1360
|
+
_pp_trB.position = posB;
|
|
1361
|
+
_pp_trB.rotation = rotB;
|
|
1362
|
+
|
|
1363
|
+
const n = dispatch_pair(0, _pp_colA, _pp_trA, _pp_colB, _pp_trB);
|
|
1364
|
+
if (n === 0) {
|
|
1365
|
+
return 0;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// Deepest contact = the minimum-translation depth; its stored normal is the
|
|
1369
|
+
// separation axis. (For multi-point manifolds — box-box, capsule-box, a
|
|
1370
|
+
// convex straddling several mesh triangles — every point shares the
|
|
1371
|
+
// separating axis, so the max depth along it is the distance to separate.)
|
|
1372
|
+
let best_depth = -1;
|
|
1373
|
+
let best_off = 0;
|
|
1374
|
+
for (let i = 0; i < n; i++) {
|
|
1375
|
+
const off = i * CANDIDATE_STRIDE;
|
|
1376
|
+
const d = candidates[off + 9];
|
|
1377
|
+
if (d > best_depth) {
|
|
1378
|
+
best_depth = d;
|
|
1379
|
+
best_off = off;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
if (!(best_depth > 0) || !Number.isFinite(best_depth)) {
|
|
1384
|
+
return 0;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
out_normal[0] = candidates[best_off + 6];
|
|
1388
|
+
out_normal[1] = candidates[best_off + 7];
|
|
1389
|
+
out_normal[2] = candidates[best_off + 8];
|
|
1390
|
+
|
|
1391
|
+
return best_depth;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* For every pair in `pair_list`, do a cross-product over A's collider list ×
|
|
1396
|
+
* B's collider list, accumulate candidate contacts, reduce to ≤4, and write
|
|
1397
|
+
* to the manifold slot.
|
|
1398
|
+
*
|
|
1399
|
+
* @param {PairList} pair_list
|
|
1400
|
+
* @param {ManifoldStore} manifolds
|
|
1401
|
+
* @param {Array<Array<{collider: Collider, transform: Transform}>>} lists
|
|
1402
|
+
* per-body collider lists, indexed by body-storage slot index. Typically
|
|
1403
|
+
* `system.__body_collider_lists` — passed in directly so this helper
|
|
1404
|
+
* has no dependency on `PhysicsSystem`.
|
|
1405
|
+
*/
|
|
1406
|
+
export function narrowphase_step(pair_list, manifolds, lists) {
|
|
1407
|
+
const count = pair_list.count;
|
|
1408
|
+
|
|
1409
|
+
for (let i = 0; i < count; i++) {
|
|
1410
|
+
const idA = pair_list.get_a(i);
|
|
1411
|
+
const idB = pair_list.get_b(i);
|
|
1412
|
+
|
|
1413
|
+
const idxA = body_id_index(idA);
|
|
1414
|
+
const idxB = body_id_index(idB);
|
|
1415
|
+
|
|
1416
|
+
const list_a = lists[idxA];
|
|
1417
|
+
const list_b = lists[idxB];
|
|
1418
|
+
|
|
1419
|
+
const slot = manifolds.find(idA, idB);
|
|
1420
|
+
|
|
1421
|
+
if (list_a === undefined || list_b === undefined
|
|
1422
|
+
|| list_a.length === 0 || list_b.length === 0
|
|
1423
|
+
) {
|
|
1424
|
+
|
|
1425
|
+
manifolds.clear_contacts(slot);
|
|
1426
|
+
continue;
|
|
1427
|
+
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
let cand_count = 0;
|
|
1431
|
+
|
|
1432
|
+
const la_len = list_a.length;
|
|
1433
|
+
const lb_len = list_b.length;
|
|
1434
|
+
|
|
1435
|
+
let sub_pair = 0;
|
|
1436
|
+
for (let a = 0; a < la_len; a++) {
|
|
1437
|
+
const ea = list_a[a];
|
|
1438
|
+
|
|
1439
|
+
for (let b = 0; b < lb_len; b++) {
|
|
1440
|
+
const eb = list_b[b];
|
|
1441
|
+
|
|
1442
|
+
const before = cand_count;
|
|
1443
|
+
cand_count = dispatch_pair(
|
|
1444
|
+
cand_count,
|
|
1445
|
+
ea.collider,
|
|
1446
|
+
ea.transform,
|
|
1447
|
+
eb.collider,
|
|
1448
|
+
eb.transform
|
|
1449
|
+
);
|
|
1450
|
+
|
|
1451
|
+
// Salt this sub-pair's fids ({@link FID_PAIR_SALT}) so a
|
|
1452
|
+
// compound body cannot fid-match — and inherit warm-start
|
|
1453
|
+
// impulses — across different collider pairs. fid 0 stays 0.
|
|
1454
|
+
if (sub_pair !== 0) {
|
|
1455
|
+
const salt = sub_pair * FID_PAIR_SALT;
|
|
1456
|
+
for (let c = before; c < cand_count; c++) {
|
|
1457
|
+
const co = c * CANDIDATE_STRIDE;
|
|
1458
|
+
if (candidates[co + 10] !== 0) candidates[co + 10] += salt;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
sub_pair++;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (cand_count === 0) {
|
|
1466
|
+
// No contacts this frame for an existing manifold. Keep the
|
|
1467
|
+
// slot in the cache (the grace window in advance_frame() will
|
|
1468
|
+
// evict it if this persists), but zero out impulses and
|
|
1469
|
+
// contact count — there's nothing for the solver to act on
|
|
1470
|
+
// and stale impulses would mislead next frame's warm-start
|
|
1471
|
+
// if contact re-establishes at a different feature.
|
|
1472
|
+
manifolds.clear_contacts(slot);
|
|
1473
|
+
continue;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
const kept = reduce_manifold_contacts(candidates, cand_count, CANDIDATE_STRIDE, MAX_KEPT, 9);
|
|
1477
|
+
|
|
1478
|
+
// ── Match-and-merge: feature-id (with position fallback) ──────
|
|
1479
|
+
//
|
|
1480
|
+
// Snapshot prev-frame state for matching + impulse carry-over.
|
|
1481
|
+
const data = manifolds.data_buffer;
|
|
1482
|
+
const slot_off = manifolds.slot_data_offset(slot);
|
|
1483
|
+
const prev_count_raw = manifolds.contact_count(slot);
|
|
1484
|
+
const prev_count = prev_count_raw > MAX_CONTACTS_PER_MANIFOLD
|
|
1485
|
+
? MAX_CONTACTS_PER_MANIFOLD
|
|
1486
|
+
: prev_count_raw;
|
|
1487
|
+
for (let j = 0; j < prev_count; j++) {
|
|
1488
|
+
const off = slot_off + j * CONTACT_STRIDE;
|
|
1489
|
+
const snap_off = j * 7;
|
|
1490
|
+
prev_snapshot[snap_off] = data[off + 13]; // feature_id
|
|
1491
|
+
prev_snapshot[snap_off + 1] = data[off]; // world_a x
|
|
1492
|
+
prev_snapshot[snap_off + 2] = data[off + 1]; // world_a y
|
|
1493
|
+
prev_snapshot[snap_off + 3] = data[off + 2]; // world_a z
|
|
1494
|
+
prev_snapshot[snap_off + 4] = data[off + 10]; // j_n
|
|
1495
|
+
prev_snapshot[snap_off + 5] = data[off + 11]; // j_t1
|
|
1496
|
+
prev_snapshot[snap_off + 6] = data[off + 12]; // j_t2
|
|
1497
|
+
prev_claimed[j] = 0;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
// For each new candidate, find a matching prev contact.
|
|
1501
|
+
// Step 1: feature-id match (only if BOTH sides have a non-zero
|
|
1502
|
+
// feature_id — fid = 0 means "no info"). Same-fid prev
|
|
1503
|
+
// contacts are disambiguated by NEAREST previous witness:
|
|
1504
|
+
// a fid identifies the FEATURE (e.g. a triangle), not the
|
|
1505
|
+
// contact point — the box/capsule-triangle paths emit up
|
|
1506
|
+
// to 4 contacts sharing one triangle's fid, and the
|
|
1507
|
+
// reducer reorders them frame to frame, so first-match
|
|
1508
|
+
// would shuffle warm-start impulses between a face's own
|
|
1509
|
+
// contact points. (redetect_pair_geometry documents and
|
|
1510
|
+
// fixes the same failure for the per-substep path.)
|
|
1511
|
+
// Step 2: position-fallback within MATCH_TOL_SQR.
|
|
1512
|
+
for (let k = 0; k < kept; k++) {
|
|
1513
|
+
const cand_off = k * CANDIDATE_STRIDE;
|
|
1514
|
+
const cand_fid = candidates[cand_off + 10];
|
|
1515
|
+
const cand_ax = candidates[cand_off];
|
|
1516
|
+
const cand_ay = candidates[cand_off + 1];
|
|
1517
|
+
const cand_az = candidates[cand_off + 2];
|
|
1518
|
+
|
|
1519
|
+
let best_prev = -1;
|
|
1520
|
+
if (cand_fid !== 0) {
|
|
1521
|
+
// Gated by FID_MATCH_MAX_D2: a fid recomputed half a metre
|
|
1522
|
+
// away (teleport, fid collision) must not inherit impulses.
|
|
1523
|
+
let best_d2 = FID_MATCH_MAX_D2;
|
|
1524
|
+
for (let j = 0; j < prev_count; j++) {
|
|
1525
|
+
if (prev_claimed[j]) continue;
|
|
1526
|
+
if (prev_snapshot[j * 7] !== cand_fid) continue;
|
|
1527
|
+
const snap_off = j * 7;
|
|
1528
|
+
const dx = prev_snapshot[snap_off + 1] - cand_ax;
|
|
1529
|
+
const dy = prev_snapshot[snap_off + 2] - cand_ay;
|
|
1530
|
+
const dz = prev_snapshot[snap_off + 3] - cand_az;
|
|
1531
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
1532
|
+
if (d2 < best_d2) { best_d2 = d2; best_prev = j; }
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
if (best_prev === -1) {
|
|
1536
|
+
let best_d2 = MATCH_TOL_SQR;
|
|
1537
|
+
for (let j = 0; j < prev_count; j++) {
|
|
1538
|
+
if (prev_claimed[j]) continue;
|
|
1539
|
+
const snap_off = j * 7;
|
|
1540
|
+
const dx = prev_snapshot[snap_off + 1] - cand_ax;
|
|
1541
|
+
const dy = prev_snapshot[snap_off + 2] - cand_ay;
|
|
1542
|
+
const dz = prev_snapshot[snap_off + 3] - cand_az;
|
|
1543
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
1544
|
+
if (d2 < best_d2) { best_d2 = d2; best_prev = j; }
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
cand_to_prev[k] = best_prev;
|
|
1548
|
+
if (best_prev !== -1) prev_claimed[best_prev] = 1;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// Reset count without zeroing the data slab — set_contact below
|
|
1552
|
+
// will overwrite geometry, and matched candidates will inherit
|
|
1553
|
+
// the impulses we snapshotted above (written back at the new
|
|
1554
|
+
// slot index after set_contact).
|
|
1555
|
+
manifolds.begin_refill(slot);
|
|
1556
|
+
|
|
1557
|
+
for (let k = 0; k < kept; k++) {
|
|
1558
|
+
const off = k * CANDIDATE_STRIDE;
|
|
1559
|
+
// Target slot index = k (we write candidates 0..kept-1 into
|
|
1560
|
+
// slot indices 0..kept-1). The impulse carry-over below
|
|
1561
|
+
// copies the matched prev contact's impulses into THIS k,
|
|
1562
|
+
// so the geometric and warm-start state stay correlated
|
|
1563
|
+
// even if the matching mapping permuted the order.
|
|
1564
|
+
manifolds.set_contact(
|
|
1565
|
+
slot, k,
|
|
1566
|
+
candidates[off], candidates[off + 1], candidates[off + 2],
|
|
1567
|
+
candidates[off + 3], candidates[off + 4], candidates[off + 5],
|
|
1568
|
+
candidates[off + 6], candidates[off + 7], candidates[off + 8],
|
|
1569
|
+
candidates[off + 9],
|
|
1570
|
+
candidates[off + 10],
|
|
1571
|
+
candidates[off + 11], candidates[off + 12]
|
|
1572
|
+
);
|
|
1573
|
+
const prev_j = cand_to_prev[k];
|
|
1574
|
+
if (prev_j !== -1) {
|
|
1575
|
+
// Copy prev_j's impulse to this slot index.
|
|
1576
|
+
const dst_off = slot_off + k * CONTACT_STRIDE;
|
|
1577
|
+
const src_off = prev_j * 7;
|
|
1578
|
+
data[dst_off + 10] = prev_snapshot[src_off + 4];
|
|
1579
|
+
data[dst_off + 11] = prev_snapshot[src_off + 5];
|
|
1580
|
+
data[dst_off + 12] = prev_snapshot[src_off + 6];
|
|
1581
|
+
} else {
|
|
1582
|
+
// No match — explicitly zero the impulses, since this
|
|
1583
|
+
// slot index may have stale data from an earlier frame's
|
|
1584
|
+
// contact at the same index.
|
|
1585
|
+
manifolds.clear_impulses(slot, k);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
/**
|
|
1592
|
+
* Re-detect contact GEOMETRY for one existing manifold slot at the bodies'
|
|
1593
|
+
* current poses, updating the witness points / normal / depth of the slot's
|
|
1594
|
+
* existing contacts in place. Does NOT change the contact count, the
|
|
1595
|
+
* feature ids, or the accumulated impulses — it only refreshes geometry.
|
|
1596
|
+
*
|
|
1597
|
+
* This is the per-substep concave path (TGS): for a contact pair involving a
|
|
1598
|
+
* concave body, the contact *feature* (which triangle is deepest, and its
|
|
1599
|
+
* normal) genuinely changes as the body rocks, so the solver's cheap analytic
|
|
1600
|
+
* refresh — which freezes the feature for the whole outer step — pumps energy
|
|
1601
|
+
* in. Re-running the narrowphase geometry each substep gives a fresh,
|
|
1602
|
+
* correct normal so the body settles instead of rocking. Convex pairs keep
|
|
1603
|
+
* the analytic refresh and never call this (their feature is stable).
|
|
1604
|
+
*
|
|
1605
|
+
* Matching is by feature id (stable per-triangle for the decomposition path),
|
|
1606
|
+
* so a contact's geometry tracks the same triangle across substeps. A contact
|
|
1607
|
+
* whose triangle isn't found this substep keeps its previous geometry (a rare
|
|
1608
|
+
* transient; the once-per-frame {@link narrowphase_step} re-establishes the
|
|
1609
|
+
* contact set next outer step). Count never changes here, so the solver's
|
|
1610
|
+
* per-contact scratch (sized once at prepare) stays aligned.
|
|
1611
|
+
*
|
|
1612
|
+
* @param {ManifoldStore} manifolds
|
|
1613
|
+
* @param {number} slot
|
|
1614
|
+
* @param {Array<{collider: Collider, transform: Transform}>} list_a
|
|
1615
|
+
* @param {Array<{collider: Collider, transform: Transform}>} list_b
|
|
1616
|
+
*/
|
|
1617
|
+
export function redetect_pair_geometry(manifolds, slot, list_a, list_b) {
|
|
1618
|
+
if (list_a === undefined || list_b === undefined) return;
|
|
1619
|
+
const la_len = list_a.length;
|
|
1620
|
+
const lb_len = list_b.length;
|
|
1621
|
+
if (la_len === 0 || lb_len === 0) return;
|
|
1622
|
+
|
|
1623
|
+
const count = manifolds.contact_count(slot);
|
|
1624
|
+
if (count === 0) return;
|
|
1625
|
+
|
|
1626
|
+
let cc = 0;
|
|
1627
|
+
let sub_pair = 0;
|
|
1628
|
+
for (let a = 0; a < la_len; a++) {
|
|
1629
|
+
const ea = list_a[a];
|
|
1630
|
+
for (let b = 0; b < lb_len; b++) {
|
|
1631
|
+
const eb = list_b[b];
|
|
1632
|
+
const before = cc;
|
|
1633
|
+
cc = dispatch_pair(cc, ea.collider, ea.transform, eb.collider, eb.transform);
|
|
1634
|
+
// Stored fids are sub-pair-salted (see narrowphase_step's dispatch
|
|
1635
|
+
// loop) — salt the redetected candidates identically or no fid
|
|
1636
|
+
// would ever match for a compound body's non-first sub-pair.
|
|
1637
|
+
if (sub_pair !== 0) {
|
|
1638
|
+
const salt = sub_pair * FID_PAIR_SALT;
|
|
1639
|
+
for (let c = before; c < cc; c++) {
|
|
1640
|
+
const co = c * CANDIDATE_STRIDE;
|
|
1641
|
+
if (candidates[co + 10] !== 0) candidates[co + 10] += salt;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
sub_pair++;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
if (cc === 0) return; // nothing re-detected this substep — keep frozen geometry
|
|
1648
|
+
|
|
1649
|
+
const data = manifolds.data_buffer;
|
|
1650
|
+
const slot_off = manifolds.slot_data_offset(slot);
|
|
1651
|
+
|
|
1652
|
+
// Match each existing contact to a DISTINCT fresh candidate. feature_id
|
|
1653
|
+
// identifies the TRIANGLE, not the contact point — the box/capsule-triangle
|
|
1654
|
+
// paths emit several contacts for one triangle, all sharing that triangle's
|
|
1655
|
+
// single fid (a flat box-on-heightmap cell yields fids like [6,6,6,7]). A
|
|
1656
|
+
// plain first-match-by-fid therefore maps every same-fid existing contact
|
|
1657
|
+
// onto the SAME candidate, collapsing the manifold to duplicate witness
|
|
1658
|
+
// points → a degenerate support polygon the solver can't damp (the
|
|
1659
|
+
// box-on-heightmap rattle). So: gate by fid, disambiguate same-fid
|
|
1660
|
+
// candidates by NEAREST previous witness (world-A) position, and claim each
|
|
1661
|
+
// candidate so no two existing contacts take the same one. For the common
|
|
1662
|
+
// unique-fid case (sphere/mesh: one contact per triangle) this picks that
|
|
1663
|
+
// single candidate exactly once — identical to the old behaviour.
|
|
1664
|
+
for (let k = 0; k < cc; k++) redetect_claimed[k] = 0;
|
|
1665
|
+
|
|
1666
|
+
for (let j = 0; j < count; j++) {
|
|
1667
|
+
const off = slot_off + j * CONTACT_STRIDE;
|
|
1668
|
+
const fid = data[off + 13];
|
|
1669
|
+
if (fid === 0) continue; // no feature info to match on
|
|
1670
|
+
|
|
1671
|
+
// Previous witness (world-A) of this existing contact — the anchor we
|
|
1672
|
+
// disambiguate same-fid candidates against.
|
|
1673
|
+
const pax = data[off];
|
|
1674
|
+
const pay = data[off + 1];
|
|
1675
|
+
const paz = data[off + 2];
|
|
1676
|
+
|
|
1677
|
+
let best_k = -1;
|
|
1678
|
+
let best_d2 = Infinity;
|
|
1679
|
+
for (let k = 0; k < cc; k++) {
|
|
1680
|
+
if (redetect_claimed[k] === 1) continue;
|
|
1681
|
+
const co = k * CANDIDATE_STRIDE;
|
|
1682
|
+
if (candidates[co + 10] !== fid) continue;
|
|
1683
|
+
const dx = candidates[co] - pax;
|
|
1684
|
+
const dy = candidates[co + 1] - pay;
|
|
1685
|
+
const dz = candidates[co + 2] - paz;
|
|
1686
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
1687
|
+
if (d2 < best_d2) {
|
|
1688
|
+
best_d2 = d2;
|
|
1689
|
+
best_k = k;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
// Position fallback (mirrors narrowphase_step's match-and-merge). A
|
|
1694
|
+
// single triangle's clipped contact count is NOT stable across sub-mm
|
|
1695
|
+
// pose changes — a box straddling a cell seam can have one triangle
|
|
1696
|
+
// yield 4 points one substep and 3 the next — so an existing contact can
|
|
1697
|
+
// outnumber this substep's same-fid candidates. Freezing its stale
|
|
1698
|
+
// witness then duplicates a sibling contact's point, leaving a
|
|
1699
|
+
// degenerate (sub-dimensional) manifold. Instead, claim the nearest
|
|
1700
|
+
// unclaimed candidate of ANY fid: every contact keeps a DISTINCT live
|
|
1701
|
+
// witness. The fid label is left intact and re-resolved by the next
|
|
1702
|
+
// once-per-step narrowphase. (At a fixed pose the same-fid match always
|
|
1703
|
+
// succeeds, so this never fires for the depth-equality guards or the
|
|
1704
|
+
// one-contact-per-triangle sphere/mesh paths.)
|
|
1705
|
+
if (best_k === -1) {
|
|
1706
|
+
for (let k = 0; k < cc; k++) {
|
|
1707
|
+
if (redetect_claimed[k] === 1) continue;
|
|
1708
|
+
const co = k * CANDIDATE_STRIDE;
|
|
1709
|
+
const dx = candidates[co] - pax;
|
|
1710
|
+
const dy = candidates[co + 1] - pay;
|
|
1711
|
+
const dz = candidates[co + 2] - paz;
|
|
1712
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
1713
|
+
if (d2 < best_d2) {
|
|
1714
|
+
best_d2 = d2;
|
|
1715
|
+
best_k = k;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
if (best_k === -1) continue; // no unclaimed candidate at all this substep — keep frozen geometry
|
|
1721
|
+
|
|
1722
|
+
redetect_claimed[best_k] = 1;
|
|
1723
|
+
const co = best_k * CANDIDATE_STRIDE;
|
|
1724
|
+
// Overwrite geometry only: witnesses, normal, depth. (Count, feature
|
|
1725
|
+
// ids and accumulated impulses are intentionally left untouched — see
|
|
1726
|
+
// the function contract.)
|
|
1727
|
+
data[off] = candidates[co];
|
|
1728
|
+
data[off + 1] = candidates[co + 1];
|
|
1729
|
+
data[off + 2] = candidates[co + 2];
|
|
1730
|
+
data[off + 3] = candidates[co + 3];
|
|
1731
|
+
data[off + 4] = candidates[co + 4];
|
|
1732
|
+
data[off + 5] = candidates[co + 5];
|
|
1733
|
+
data[off + 6] = candidates[co + 6];
|
|
1734
|
+
data[off + 7] = candidates[co + 7];
|
|
1735
|
+
data[off + 8] = candidates[co + 8];
|
|
1736
|
+
data[off + 9] = candidates[co + 9];
|
|
1737
|
+
}
|
|
1738
|
+
}
|