@woosh/meep-engine 3.37.0 → 3.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts +11 -0
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +30 -0
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_aabb.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_aabb.js +28 -7
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +15 -0
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +41 -0
- package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts +12 -0
- package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.js +27 -0
- package/src/core/geom/3d/gjk/gjk.js +3 -3
- package/src/core/geom/3d/gjk/gjk_distance.d.ts +94 -0
- package/src/core/geom/3d/gjk/gjk_distance.d.ts.map +1 -0
- package/src/core/geom/3d/gjk/gjk_distance.js +782 -0
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts +5 -4
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/gjk_epa_penetration.js +14 -9
- package/src/core/geom/3d/gjk/minkowski_support.d.ts +11 -7
- package/src/core/geom/3d/gjk/minkowski_support.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/minkowski_support.js +33 -9
- package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/mpr.js +26 -5
- package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.d.ts +15 -0
- package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.d.ts.map +1 -1
- package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.js +106 -33
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts +2 -1
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts.map +1 -1
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +4 -8
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_array.d.ts +32 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_array.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_array.js +85 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_scalar.d.ts +3 -3
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_scalar.d.ts.map +1 -1
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_scalar.js +24 -34
- package/src/core/geom/3d/quaternion/quat3_integrate.d.ts +17 -0
- package/src/core/geom/3d/quaternion/quat3_integrate.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_integrate.js +45 -4
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts +16 -0
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_multiply.js +25 -0
- package/src/core/geom/3d/quaternion/quat3_nlerp.d.ts +18 -0
- package/src/core/geom/3d/quaternion/quat3_nlerp.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_nlerp.js +45 -0
- package/src/core/geom/3d/quaternion/quat3_shortest_arc.d.ts +17 -0
- package/src/core/geom/3d/quaternion/quat3_shortest_arc.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_shortest_arc.js +155 -94
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +12 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +31 -0
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts +20 -6
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/AbstractShape3D.js +20 -6
- package/src/core/geom/3d/shape/BoxShape3D.d.ts +1 -1
- package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/BoxShape3D.js +5 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +1 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.js +5 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts +25 -11
- package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.js +392 -22
- package/src/core/geom/3d/shape/CylinderShape3D.d.ts +8 -7
- package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CylinderShape3D.js +12 -7
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +51 -8
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +260 -14
- package/src/core/geom/3d/shape/MeshShape3D.d.ts +61 -7
- package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/MeshShape3D.js +111 -20
- package/src/core/geom/3d/shape/PointShape3D.d.ts +1 -1
- package/src/core/geom/3d/shape/PointShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PointShape3D.js +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.d.ts +9 -0
- package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.js +36 -6
- package/src/core/geom/3d/shape/SphereShape3D.d.ts +1 -1
- package/src/core/geom/3d/shape/SphereShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/SphereShape3D.js +5 -1
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts +12 -10
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +53 -19
- package/src/core/geom/3d/shape/Triangle3D.d.ts +1 -1
- package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/Triangle3D.js +5 -1
- package/src/core/geom/3d/shape/UnionShape3D.d.ts +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +19 -2
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +14 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -1
- package/src/core/geom/3d/shape/sdf/sdf3_box.js +67 -5
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +14 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -1
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +61 -3
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +14 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -1
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +63 -4
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +15 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -1
- package/src/core/geom/3d/shape/sdf/sdf3_plane.js +64 -2
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +21 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -1
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +66 -3
- package/src/core/geom/3d/shape/shape3_mesh_from_geometry.d.ts +2 -0
- package/src/core/geom/3d/shape/shape3_mesh_from_geometry.d.ts.map +1 -1
- package/src/core/geom/3d/shape/shape3_mesh_from_geometry.js +7 -0
- package/src/core/geom/3d/shape/util/mesh_compute_triangle_edge_flags.d.ts +41 -0
- package/src/core/geom/3d/shape/util/mesh_compute_triangle_edge_flags.d.ts.map +1 -0
- package/src/core/geom/3d/shape/util/mesh_compute_triangle_edge_flags.js +538 -0
- package/src/core/geom/3d/sphere/harmonics/sh_basis_at.d.ts +31 -0
- package/src/core/geom/3d/sphere/harmonics/sh_basis_at.d.ts.map +1 -0
- package/src/core/geom/3d/sphere/harmonics/sh_basis_at.js +85 -0
- package/src/core/geom/3d/sphere/harmonics/sh_vmf_window.d.ts +18 -0
- package/src/core/geom/3d/sphere/harmonics/sh_vmf_window.d.ts.map +1 -0
- package/src/core/geom/3d/sphere/harmonics/sh_vmf_window.js +19 -0
- package/src/core/geom/3d/triangle/TriangleEdgeFlags.d.ts +49 -0
- package/src/core/geom/3d/triangle/TriangleEdgeFlags.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/TriangleEdgeFlags.js +55 -0
- package/src/core/geom/3d/triangle/tri3_classify_shared_edge.d.ts +42 -0
- package/src/core/geom/3d/triangle/tri3_classify_shared_edge.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/tri3_classify_shared_edge.js +85 -0
- package/src/core/geom/3d/triangle/tri3_closest_point.d.ts +13 -0
- package/src/core/geom/3d/triangle/tri3_closest_point.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_closest_point.js +36 -1
- package/src/core/geom/3d/triangle/tri3_closest_point_barycentric.d.ts +14 -0
- package/src/core/geom/3d/triangle/tri3_closest_point_barycentric.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_closest_point_barycentric.js +40 -0
- package/src/core/geom/vec3/v3_quaternion_apply.d.ts +19 -0
- package/src/core/geom/vec3/v3_quaternion_apply.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_quaternion_apply.js +32 -0
- package/src/core/geom/vec3/v3_quaternion_apply_inverse.d.ts +19 -0
- package/src/core/geom/vec3/v3_quaternion_apply_inverse.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_quaternion_apply_inverse.js +32 -0
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +135 -10
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +338 -105
- package/src/engine/control/first-person/abilities/Ability.d.ts +14 -5
- package/src/engine/control/first-person/abilities/Ability.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Ability.js +14 -5
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/LedgeGrab.js +16 -12
- package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Mantle.js +5 -1
- package/src/engine/control/first-person/abilities/Slide.js +1 -1
- package/src/engine/control/first-person/collision/KinematicMover.d.ts +92 -14
- package/src/engine/control/first-person/collision/KinematicMover.d.ts.map +1 -1
- package/src/engine/control/first-person/collision/KinematicMover.js +218 -37
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +5 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +17 -10
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +27 -13
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +6 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts +11 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts.map +1 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.js +10 -0
- package/src/engine/ecs/transform/Transform64.d.ts +4 -2
- package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
- package/src/engine/ecs/transform/Transform64.js +10 -16
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +16 -0
- package/src/engine/graphics/ecs/water/Water.d.ts +26 -34
- package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/Water.js +42 -36
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +38 -62
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts +6 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.js +27 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_2_3.d.ts +12 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_2_3.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_2_3.js +45 -0
- package/src/engine/graphics/ecs/water/WaterWaves.d.ts +33 -0
- package/src/engine/graphics/ecs/water/WaterWaves.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterWaves.js +46 -0
- package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.d.ts +17 -0
- package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.js +26 -0
- package/src/engine/graphics/texture/3d/scs3d_sample_linear.d.ts +22 -0
- package/src/engine/graphics/texture/3d/scs3d_sample_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/3d/scs3d_sample_linear.js +43 -1
- package/src/engine/graphics/texture/sampler/Sampler2D.d.ts +29 -3
- package/src/engine/graphics/texture/sampler/Sampler2D.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/Sampler2D.js +102 -14
- package/src/engine/graphics3/WaterSystem.d.ts +58 -6
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +423 -293
- package/src/engine/interpolation/BinaryInterpolationAdapter.d.ts +10 -4
- package/src/engine/interpolation/BinaryInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/BinaryInterpolationAdapter.js +11 -5
- package/src/engine/interpolation/InterpolationLog.d.ts +11 -5
- package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationLog.js +12 -6
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +39 -8
- package/src/engine/interpolation/PoseInterpolationAdapter.d.ts +1 -1
- package/src/engine/interpolation/PoseInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/PoseInterpolationAdapter.js +51 -22
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +18 -23
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts +1 -1
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +3 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts +1 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.js +3 -1
- package/src/engine/network/adapters/Vector3InterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/Vector3InterpolationAdapter.js +5 -2
- package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
- package/src/engine/physics/body/SolverBodyState.js +4 -5
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +12 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +28 -3
- package/src/engine/physics/ccd/linear_sweep.d.ts +42 -12
- package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
- package/src/engine/physics/ccd/linear_sweep.js +1131 -97
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +26 -14
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +221 -52
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +30 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +117 -24
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +46 -3
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +116 -68
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +2 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +10 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +36 -14
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +15 -2
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +17 -2
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +78 -53
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +18 -20
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +185 -128
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +46 -39
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +41 -36
- package/src/engine/physics/cloth/playground/garment_build.js +6 -6
- package/src/engine/physics/cloth/playground/garment_main.js +18 -14
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +8 -5
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +8 -5
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +15 -15
- package/src/engine/physics/cloth/solver/find_non_finite_cloth_state.d.ts +5 -0
- package/src/engine/physics/cloth/solver/find_non_finite_cloth_state.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/find_non_finite_cloth_state.js +32 -9
- package/src/engine/physics/constraint/solve_constraints.d.ts +50 -8
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
- package/src/engine/physics/constraint/solve_constraints.js +703 -429
- package/src/engine/physics/contact/ManifoldStore.d.ts +12 -0
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
- package/src/engine/physics/contact/ManifoldStore.js +32 -0
- package/src/engine/physics/ecs/BodyKind.d.ts +16 -8
- package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
- package/src/engine/physics/ecs/BodyKind.js +16 -8
- package/src/engine/physics/ecs/Collider.d.ts +7 -2
- package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
- package/src/engine/physics/ecs/Collider.js +7 -2
- package/src/engine/physics/ecs/PhysicsEvents.d.ts +13 -0
- package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsEvents.js +13 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +320 -36
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +810 -96
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +5 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +11 -9
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +7 -5
- package/src/engine/physics/fluid/ecs/fluid_reanchor_field.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/fluid_reanchor_field.js +9 -7
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +3 -4
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.js +9 -7
- package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.js +65 -43
- package/src/engine/physics/inertia/MASS_PROPERTIES_SIZE.d.ts +23 -0
- package/src/engine/physics/inertia/MASS_PROPERTIES_SIZE.d.ts.map +1 -0
- package/src/engine/physics/inertia/MASS_PROPERTIES_SIZE.js +22 -0
- package/src/engine/physics/inertia/convex_hull_mass_properties.d.ts +29 -0
- package/src/engine/physics/inertia/convex_hull_mass_properties.d.ts.map +1 -0
- package/src/engine/physics/inertia/convex_hull_mass_properties.js +117 -0
- package/src/engine/physics/inertia/mass_properties_accumulate.d.ts +24 -0
- package/src/engine/physics/inertia/mass_properties_accumulate.d.ts.map +1 -0
- package/src/engine/physics/inertia/mass_properties_accumulate.js +93 -0
- package/src/engine/physics/inertia/primitive_mass_properties.d.ts +46 -0
- package/src/engine/physics/inertia/primitive_mass_properties.d.ts.map +1 -0
- package/src/engine/physics/inertia/primitive_mass_properties.js +118 -0
- package/src/engine/physics/inertia/rigid_body_set_mass_properties.d.ts +27 -0
- package/src/engine/physics/inertia/rigid_body_set_mass_properties.d.ts.map +1 -0
- package/src/engine/physics/inertia/rigid_body_set_mass_properties.js +62 -0
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +67 -25
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +149 -26
- package/src/engine/physics/integration/integrate_position.d.ts +18 -19
- package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_position.js +40 -37
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +13 -4
- package/src/engine/physics/island/IslandBuilder.d.ts +124 -6
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
- package/src/engine/physics/island/IslandBuilder.js +322 -19
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts +13 -0
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +95 -39
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +40 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_triangle_contact.js +415 -120
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts +63 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_contacts.js +234 -46
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +13 -0
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_triangle_contact.js +141 -93
- package/src/engine/physics/narrowphase/compute_penetration.d.ts +29 -11
- package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/compute_penetration.js +157 -34
- package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +76 -0
- package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/convex_convex_manifold.js +243 -48
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +13 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +28 -12
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +13 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +27 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_triangle_edge_flags.d.ts +42 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_triangle_edge_flags.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_triangle_edge_flags.js +250 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +27 -11
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +291 -12
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +7 -1
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +7 -1
- package/src/engine/physics/narrowphase/decomposition/triangle_edge_flags.d.ts +35 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_edge_flags.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_edge_flags.js +61 -0
- package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts +54 -0
- package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/hull_sphere_contact.js +244 -0
- package/src/engine/physics/narrowphase/mesh_convex_hull.js +5 -1
- package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.d.ts +2 -0
- package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +56 -31
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts +6 -5
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +2185 -483
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +56 -5
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +546 -5
- package/src/engine/physics/narrowphase/refine_ray_concave.d.ts +29 -2
- package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/refine_ray_concave.js +628 -75
- package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +3 -2
- package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/refine_ray_hit.js +3 -2
- package/src/engine/physics/narrowphase/rigid_subject_pose.d.ts +27 -0
- package/src/engine/physics/narrowphase/rigid_subject_pose.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/rigid_subject_pose.js +96 -0
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts +14 -0
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_box_contact.js +51 -5
- package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +12 -0
- package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_sphere_contact.js +30 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +12 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_triangle_contact.js +37 -8
- package/src/engine/physics/narrowphase/support_feature_manifold.d.ts +139 -0
- package/src/engine/physics/narrowphase/support_feature_manifold.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/support_feature_manifold.js +949 -0
- package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts +32 -13
- package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts.map +1 -1
- package/src/engine/physics/queries/PhysicsSurfacePoint.js +36 -13
- package/src/engine/physics/queries/convex_overlaps_shape.d.ts +27 -0
- package/src/engine/physics/queries/convex_overlaps_shape.d.ts.map +1 -0
- package/src/engine/physics/queries/convex_overlaps_shape.js +169 -0
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
- package/src/engine/physics/queries/overlap_shape.js +57 -79
- package/src/engine/physics/queries/raycast.d.ts +10 -4
- package/src/engine/physics/queries/raycast.d.ts.map +1 -1
- package/src/engine/physics/queries/raycast.js +133 -9
- package/src/engine/physics/queries/shape_cast.d.ts +55 -24
- package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
- package/src/engine/physics/queries/shape_cast.js +2061 -245
- package/src/engine/physics/solver/apply_impulse_to_body.d.ts +32 -10
- package/src/engine/physics/solver/apply_impulse_to_body.d.ts.map +1 -1
- package/src/engine/physics/solver/apply_impulse_to_body.js +69 -28
- package/src/engine/physics/solver/solve_contacts.d.ts +65 -18
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +458 -234
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
- package/src/engine/physics/vehicle/RaycastVehicle.js +5 -6
- package/src/shade/assets/textures/split_sum.bin +0 -0
- package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUQueue.js +2 -1
- package/src/shade/playground/path_traced_media/README.md +78 -0
- package/src/shade/playground/path_traced_media/capture_radiance.d.ts +33 -0
- package/src/shade/playground/path_traced_media/capture_radiance.d.ts.map +1 -0
- package/src/shade/playground/path_traced_media/capture_radiance.js +174 -0
- package/src/shade/playground/path_traced_media/checks.d.ts +160 -0
- package/src/shade/playground/path_traced_media/checks.d.ts.map +1 -0
- package/src/shade/playground/path_traced_media/checks.js +921 -0
- package/src/shade/playground/path_traced_media/index.html +71 -0
- package/src/shade/playground/path_traced_media/main.d.ts +2 -0
- package/src/shade/playground/path_traced_media/main.d.ts.map +1 -0
- package/src/shade/playground/path_traced_media/main.js +440 -0
- package/src/shade/playground/path_traced_media/make_wave_pool_geometry.d.ts +26 -0
- package/src/shade/playground/path_traced_media/make_wave_pool_geometry.d.ts.map +1 -0
- package/src/shade/playground/path_traced_media/make_wave_pool_geometry.js +117 -0
- package/src/shade/playground/path_traced_media/views.d.ts +21 -0
- package/src/shade/playground/path_traced_media/views.d.ts.map +1 -0
- package/src/shade/playground/path_traced_media/views.js +161 -0
- package/src/shade/playground/sh_exponential/README.md +43 -0
- package/src/shade/playground/sh_exponential/index.html +59 -0
- package/src/shade/playground/sh_exponential/main.d.ts +2 -0
- package/src/shade/playground/sh_exponential/main.d.ts.map +1 -0
- package/src/shade/playground/sh_exponential/main.js +571 -0
- package/src/shade/playground/sh_exponential/sh_exp_playground_shaders.d.ts +46 -0
- package/src/shade/playground/sh_exponential/sh_exp_playground_shaders.d.ts.map +1 -0
- package/src/shade/playground/sh_exponential/sh_exp_playground_shaders.js +270 -0
- package/src/shade/playground/water_refraction/README.md +158 -0
- package/src/shade/playground/water_refraction/index.html +40 -0
- package/src/shade/playground/water_refraction/main.d.ts +2 -0
- package/src/shade/playground/water_refraction/main.d.ts.map +1 -0
- package/src/shade/playground/water_refraction/main.js +202 -0
- package/src/shade/playground/water_refraction/world.d.ts +39 -0
- package/src/shade/playground/water_refraction/world.d.ts.map +1 -0
- package/src/shade/playground/water_refraction/world.js +141 -0
- package/src/shade/renderer/Renderer.d.ts +2 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +27 -0
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts +2 -3
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +9 -1
- package/src/shade/renderer/geometry/sdf/chunk_scene_point_query_volume_sign.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/chunk_scene_point_query_volume_sign.js +6 -4
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +1 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_rand1.d.ts +7 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_rand1.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_rand1.js +12 -12
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_spherical.d.ts +4 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_spherical.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/sampling/chunk_direction_by_index_spherical.js +13 -9
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.js +2 -0
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +3 -0
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.js +4 -9
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +20 -10
- package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts +8 -0
- package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts +0 -6
- package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/load_environment_map.d.ts +2 -1
- package/src/shade/renderer/light/environment/rgbe/load_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/load_environment_map.js +2 -1
- package/src/shade/renderer/light/environment/sh_exponential/README.md +171 -0
- package/src/shade/renderer/light/environment/sh_exponential/SHExpEncoder.d.ts +170 -0
- package/src/shade/renderer/light/environment/sh_exponential/SHExpEncoder.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/SHExpEncoder.js +377 -0
- package/src/shade/renderer/light/environment/sh_exponential/SH_EXP_ENCODE_PARAMETERS_STRUCT.d.ts +16 -0
- package/src/shade/renderer/light/environment/sh_exponential/SH_EXP_ENCODE_PARAMETERS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/SH_EXP_ENCODE_PARAMETERS_STRUCT.js +27 -0
- package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.d.ts +21 -0
- package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.js +53 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_design_row.d.ts +33 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_design_row.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_design_row.js +90 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_fit_samples.d.ts +28 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_fit_samples.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_fit_samples.js +92 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_layout.d.ts +39 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_layout.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_layout.js +44 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_solve_matrix.d.ts +42 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_solve_matrix.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/sh_exp_solve_matrix.js +123 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.d.ts +30 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.js +147 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_log_floor.d.ts +24 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_log_floor.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_log_floor.js +79 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_project.d.ts +17 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_project.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_project.js +99 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_reference_reflectance.d.ts +24 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_reference_reflectance.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_reference_reflectance.js +104 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_solve.d.ts +12 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_solve.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_solve.js +93 -0
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +1 -0
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.js +4 -0
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.js +4 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/PIXEL_TEXTURE_ORM.d.ts +1 -1
- package/src/shade/renderer/material/PIXEL_TEXTURE_ORM.d.ts.map +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.d.ts +15 -0
- package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.js +17 -0
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +36 -2
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +218 -18
- package/src/shade/renderer/material/resident/INDIRECT_MATERIAL_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/INDIRECT_MATERIAL_STRUCT.js +10 -0
- package/src/shade/renderer/medium/MEDIA_TABLE_STRUCT.d.ts +17 -0
- package/src/shade/renderer/medium/MEDIA_TABLE_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/medium/MEDIA_TABLE_STRUCT.js +24 -0
- package/src/shade/renderer/medium/MEDIUM_PHASE_LOBE_KIND.d.ts +24 -0
- package/src/shade/renderer/medium/MEDIUM_PHASE_LOBE_KIND.d.ts.map +1 -0
- package/src/shade/renderer/medium/MEDIUM_PHASE_LOBE_KIND.js +18 -0
- package/src/shade/renderer/medium/MEDIUM_STRUCT.d.ts +20 -0
- package/src/shade/renderer/medium/MEDIUM_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/medium/MEDIUM_STRUCT.js +43 -0
- package/src/shade/renderer/medium/ParticipatingMedium.d.ts +108 -0
- package/src/shade/renderer/medium/ParticipatingMedium.d.ts.map +1 -0
- package/src/shade/renderer/medium/ParticipatingMedium.js +204 -0
- package/src/shade/renderer/medium/chunk_medium_lobe_phase.d.ts +13 -0
- package/src/shade/renderer/medium/chunk_medium_lobe_phase.d.ts.map +1 -0
- package/src/shade/renderer/medium/chunk_medium_lobe_phase.js +33 -0
- package/src/shade/renderer/medium/participating_medium_serialization.d.ts +32 -0
- package/src/shade/renderer/medium/participating_medium_serialization.d.ts.map +1 -0
- package/src/shade/renderer/medium/participating_medium_serialization.js +181 -0
- package/src/shade/renderer/medium/phase/MediumPhaseFunction.d.ts +48 -0
- package/src/shade/renderer/medium/phase/MediumPhaseFunction.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/MediumPhaseFunction.js +42 -0
- package/src/shade/renderer/medium/phase/PhaseCornetteShanks.d.ts +23 -0
- package/src/shade/renderer/medium/phase/PhaseCornetteShanks.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseCornetteShanks.js +45 -0
- package/src/shade/renderer/medium/phase/PhaseDraine.d.ts +30 -0
- package/src/shade/renderer/medium/phase/PhaseDraine.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseDraine.js +58 -0
- package/src/shade/renderer/medium/phase/PhaseFournierForand.d.ts +24 -0
- package/src/shade/renderer/medium/phase/PhaseFournierForand.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseFournierForand.js +53 -0
- package/src/shade/renderer/medium/phase/PhaseHenyeyGreenstein.d.ts +21 -0
- package/src/shade/renderer/medium/phase/PhaseHenyeyGreenstein.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseHenyeyGreenstein.js +43 -0
- package/src/shade/renderer/medium/phase/PhaseJendersieDeon.d.ts +25 -0
- package/src/shade/renderer/medium/phase/PhaseJendersieDeon.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseJendersieDeon.js +66 -0
- package/src/shade/renderer/medium/phase/PhaseRayleigh.d.ts +9 -0
- package/src/shade/renderer/medium/phase/PhaseRayleigh.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseRayleigh.js +21 -0
- package/src/shade/renderer/medium/phase/PhaseWaterMolecular.d.ts +28 -0
- package/src/shade/renderer/medium/phase/PhaseWaterMolecular.d.ts.map +1 -0
- package/src/shade/renderer/medium/phase/PhaseWaterMolecular.js +49 -0
- package/src/shade/renderer/medium/water/WATER_DEFAULT_PATH_LENGTHS.d.ts +10 -0
- package/src/shade/renderer/medium/water/WATER_DEFAULT_PATH_LENGTHS.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/WATER_DEFAULT_PATH_LENGTHS.js +25 -0
- package/src/shade/renderer/medium/water/water_iop_from_appearance.d.ts +47 -0
- package/src/shade/renderer/medium/water/water_iop_from_appearance.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_iop_from_appearance.js +174 -0
- package/src/shade/renderer/medium/water/water_iop_from_constituents.d.ts +57 -0
- package/src/shade/renderer/medium/water/water_iop_from_constituents.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_iop_from_constituents.js +242 -0
- package/src/shade/renderer/medium/water/water_iop_jerlov.d.ts +41 -0
- package/src/shade/renderer/medium/water/water_iop_jerlov.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_iop_jerlov.js +231 -0
- package/src/shade/renderer/medium/water/water_iop_spectral_reference.d.ts +66 -0
- package/src/shade/renderer/medium/water/water_iop_spectral_reference.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_iop_spectral_reference.js +223 -0
- package/src/shade/renderer/medium/water/water_medium_from_iop.d.ts +96 -0
- package/src/shade/renderer/medium/water/water_medium_from_iop.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_medium_from_iop.js +145 -0
- package/src/shade/renderer/medium/water/water_presets.d.ts +69 -0
- package/src/shade/renderer/medium/water/water_presets.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_presets.js +119 -0
- package/src/shade/renderer/medium/water/water_rgb_from_spectral.d.ts +69 -0
- package/src/shade/renderer/medium/water/water_rgb_from_spectral.d.ts.map +1 -0
- package/src/shade/renderer/medium/water/water_rgb_from_spectral.js +341 -0
- package/src/shade/renderer/particles/DESIGN.md +4 -2
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +1 -1
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_voxel_fade.d.ts +26 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_voxel_fade.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_voxel_fade.js +71 -0
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +16 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +6 -13
- package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +520 -0
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +1 -0
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.js +2 -0
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +188 -185
- package/src/shade/renderer/path_tracer/shader/STANDARD_MATERIAL_DATA_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/STANDARD_MATERIAL_DATA_STRUCT.js +4 -1
- package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.d.ts +13 -0
- package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.js +29 -0
- package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.d.ts +79 -0
- package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.js +360 -70
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +4 -3
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_beam.d.ts +24 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_beam.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_beam.js +99 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_connect.d.ts +68 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_connect.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_connect.js +263 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_constraint.d.ts +55 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_constraint.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_constraint.js +148 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light.d.ts +17 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light.js +41 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light_sample.d.ts +20 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light_sample.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_light_sample.js +105 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle.d.ts +28 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle.js +97 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle_of_hit.d.ts +12 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle_of_hit.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/manifold/chunk_manifold_triangle_of_hit.js +46 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_interface.d.ts +25 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_interface.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_interface.js +75 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_path.d.ts +54 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_path.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_path.js +245 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_phase.d.ts +42 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_phase.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_phase.js +236 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_scatter_nee.d.ts +24 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_scatter_nee.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_scatter_nee.js +97 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_stack.d.ts +57 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_stack.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_stack.js +222 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_transport.d.ts +88 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_transport.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_transport.js +304 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_volumes.d.ts +35 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_volumes.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/media/chunk_medium_volumes.js +137 -0
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.js +85 -84
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.d.ts +8 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.js +9 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +28 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +17 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts +13 -7
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.js +13 -7
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +309 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +54 -9
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +9 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_footprint_bias.d.ts +33 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_footprint_bias.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_footprint_bias.js +45 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.js +6 -2
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.js +11 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.js +19 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.d.ts +2 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.js +4 -2
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +5 -3
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.js +8 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_level_word.d.ts +14 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_level_word.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_level_word.js +28 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_lut_entry.d.ts +10 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_lut_entry.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_lut_entry.js +18 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_marks.d.ts +19 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_marks.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_marks.js +44 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_step_count.d.ts +10 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_step_count.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp_step_count.js +17 -0
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +23 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_build_warp.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_build_warp.js +163 -64
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +4 -8
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +4 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +5 -0
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.d.ts +12 -1
- package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.js +22 -3
- package/src/shade/renderer/shader/chunk/atmosphere/phase/chunk_sample_henyey_greenstein_cos.d.ts +18 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/chunk_sample_henyey_greenstein_cos.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/chunk_sample_henyey_greenstein_cos.js +31 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_phase_fournier_forand.d.ts +43 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_phase_fournier_forand.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_phase_fournier_forand.js +153 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_sample_fournier_forand.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_sample_fournier_forand.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/chunk_sample_fournier_forand.js +57 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/fournier_forand_parameters_from_backscatter.d.ts +45 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/fournier_forand_parameters_from_backscatter.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/ff/fournier_forand_parameters_from_backscatter.js +109 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_phase_draine.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_phase_draine.js +6 -3
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine.js +49 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine_cos.d.ts +18 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine_cos.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/chunk_sample_draine_cos.js +18 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/brdf/dfg/chunk_integrate_brdf.d.ts +3 -0
- package/src/shade/renderer/shader/chunk/brdf/dfg/chunk_integrate_brdf.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/brdf/dfg/chunk_integrate_brdf.js +3 -0
- package/src/shade/renderer/shader/chunk/brdf/dfg/shader_split_sum_dgf_lut.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/brdf/dfg/shader_split_sum_dgf_lut.js +3 -1
- package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_dielectric.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_dielectric.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_dielectric.js +53 -0
- package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.d.ts → chunk_plane_ray_raycast.d.ts} +2 -2
- package/src/shade/renderer/shader/chunk/geometry/plane/chunk_plane_ray_raycast.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_scene_point_query_is_inside_geometry.d.ts +7 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_scene_point_query_is_inside_geometry.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_scene_point_query_is_inside_geometry.js +12 -60
- package/src/shade/renderer/shader/chunk/geometry/sphere/chunk_compute_spherical_excess.d.ts +26 -6
- package/src/shade/renderer/shader/chunk/geometry/sphere/chunk_compute_spherical_excess.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/sphere/chunk_compute_spherical_excess.js +30 -20
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_directional.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_directional.js +3 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_point.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_point.js +3 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_spot.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_importance_spot.js +3 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_receiver_cosine.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_receiver_cosine.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/light/sample/chunk_light_receiver_cosine.js +25 -0
- package/src/shade/renderer/shader/chunk/light/sample/chunk_select_light_importance.d.ts +9 -2
- package/src/shade/renderer/shader/chunk/light/sample/chunk_select_light_importance.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/sample/chunk_select_light_importance.js +33 -10
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts +4 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.js +135 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_band_of_index.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_band_of_index.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_band_of_index.js +30 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_basis_function.d.ts +19 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_basis_function.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_basis_function.js +73 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_vmf_window.d.ts +19 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_vmf_window.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh_vmf_window.js +25 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/SH_EXP_P4Q2_PROBE_STRUCT.d.ts +17 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/SH_EXP_P4Q2_PROBE_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/SH_EXP_P4Q2_PROBE_STRUCT.js +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_p4q2_base_reflectance.d.ts +26 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_p4q2_base_reflectance.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_p4q2_base_reflectance.js +55 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_split_sum.d.ts +52 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_split_sum.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/exponential/chunk_sh_exp_split_sum.js +65 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_basis_at.js +229 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh10_color_evaluate_vmf.js +278 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh2_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh2_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh2_color_evaluate_vmf.js +58 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh3_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh3_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh3_color_evaluate_vmf.js +75 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_basis_at.js +70 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh4_color_evaluate_vmf.js +95 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_basis_at.js +89 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh5_color_evaluate_vmf.js +118 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_basis_at.js +111 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh6_color_evaluate_vmf.js +144 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_basis_at.js +136 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh7_color_evaluate_vmf.js +173 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_basis_at.js +164 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh8_color_evaluate_vmf.js +205 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_basis_at.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_basis_at.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_basis_at.js +195 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_color_evaluate_vmf.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_color_evaluate_vmf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/generated/chunk_sh9_color_evaluate_vmf.js +240 -0
- package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.d.ts +0 -6
- package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.js +46 -1
- package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts +7 -7
- package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.js +7 -7
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +42 -10
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +104 -48
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +20 -4
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +186 -74
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts +2 -1
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/Shadowmap.js +2 -1
- package/src/shade/renderer/shadow/map/csm/CSM_CASCADE_STRUCT.d.ts +30 -0
- package/src/shade/renderer/shadow/map/csm/CSM_CASCADE_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/csm/CSM_CASCADE_STRUCT.js +52 -0
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts +14 -0
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.js +20 -0
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_DEFAULT_CASCADE_COUNT.d.ts +8 -0
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_DEFAULT_CASCADE_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_DEFAULT_CASCADE_COUNT.js +7 -0
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +8 -6
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +28 -34
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_csm_compute_cascade_blended.d.ts +3 -2
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_csm_compute_cascade_blended.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_csm_compute_cascade_blended.js +19 -14
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +4 -3
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +12 -7
- package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts +4 -4
- package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.js +4 -4
- package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.js +39 -17
- package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.js +5 -36
- package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.js +3 -2
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts +1 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +49 -35
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts +4 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.js +8 -9
- package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.js +2 -2
- package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/decode_tile_address.js +15 -23
- package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.js +6 -9
- package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.js +19 -9
- package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.js +18 -6
- package/src/shade/renderer/texture/util/BLACK_PIXEL_TEXTURE.d.ts +1 -1
- package/src/shade/renderer/texture/util/BLACK_PIXEL_TEXTURE.d.ts.map +1 -1
- package/src/shade/renderer/texture/util/PIXEL_TEXTURE_NORMAL.d.ts +18 -1
- package/src/shade/renderer/texture/util/PIXEL_TEXTURE_NORMAL.d.ts.map +1 -1
- package/src/shade/renderer/texture/util/PIXEL_TEXTURE_NORMAL.js +24 -3
- package/src/shade/renderer/texture/util/WHITE_PIXEL_TEXTURE.d.ts +1 -1
- package/src/shade/renderer/texture/util/WHITE_PIXEL_TEXTURE.d.ts.map +1 -1
- package/src/shade/renderer/texture/util/get_single_pixel_texture.d.ts +0 -1
- package/src/shade/renderer/texture/util/get_single_pixel_texture.d.ts.map +1 -1
- package/src/shade/renderer/texture/util/get_single_pixel_texture.js +2 -23
- package/src/shade/renderer/texture/util/single_pixel_texture_from_sampler.d.ts +11 -0
- package/src/shade/renderer/texture/util/single_pixel_texture_from_sampler.d.ts.map +1 -0
- package/src/shade/renderer/texture/util/single_pixel_texture_from_sampler.js +34 -0
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts +17 -8
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +35 -64
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts +21 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.js +70 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volumes_iterate.d.ts +31 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volumes_iterate.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volumes_iterate.js +86 -0
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +2 -4
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +6 -7
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +7 -7
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +72 -27
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +275 -138
- package/src/shade/renderer/water/chunk_water_gi.d.ts +14 -0
- package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -0
- package/src/shade/renderer/water/chunk_water_gi.js +56 -0
- package/src/shade/renderer/water/chunk_water_transport.d.ts +7 -0
- package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -0
- package/src/shade/renderer/water/chunk_water_transport.js +105 -0
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +29 -0
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/GPUWaterBodies.js +116 -0
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts +23 -0
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.js +42 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_derived.d.ts +9 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_derived.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_derived.js +55 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_scattering.d.ts +8 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_scattering.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/chunk_water_medium_scattering.js +17 -0
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +8 -0
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +30 -0
- package/src/shade/renderer/water/optics/chunk_water_inscatter.d.ts +28 -0
- package/src/shade/renderer/water/optics/chunk_water_inscatter.d.ts.map +1 -0
- package/src/shade/renderer/water/optics/chunk_water_inscatter.js +123 -0
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts +23 -0
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts.map +1 -0
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts +18 -0
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts.map +1 -0
- package/src/shade/renderer/water/optics/chunk_water_optics.d.ts +12 -0
- package/src/shade/renderer/water/optics/chunk_water_optics.d.ts.map +1 -0
- package/src/shade/renderer/water/optics/chunk_water_optics.js +75 -0
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +27 -0
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -0
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +74 -0
- package/src/shade/renderer/water/shader_water.d.ts +15 -26
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +373 -213
- package/src/shade/renderer/water/shader_water_avboit.d.ts +12 -0
- package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -0
- package/src/shade/renderer/water/shader_water_avboit.js +268 -0
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +98 -0
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +408 -0
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts +12 -0
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.js +27 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts +14 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.js +49 -0
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +15 -0
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/chunk_water_wave.js +48 -0
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts +9 -0
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.js +47 -0
- package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts +10 -0
- package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_surface_write.js +51 -0
- package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts +12 -0
- package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_wave_step.js +54 -0
- package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts +13 -0
- package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/water_surface_grid_indices.js +39 -0
- package/src/shade/renderer/water/water_missing_receiver_path.d.ts +17 -0
- package/src/shade/renderer/water/water_missing_receiver_path.d.ts.map +1 -0
- package/src/shade/renderer/water/water_missing_receiver_path.js +40 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +247 -23
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +18 -14
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +61 -6
- package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts +0 -29
- package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/geometry/plane/plane_ray_raycast.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts +0 -29
- package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.js +0 -43
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASCADE_COUNT.d.ts +0 -7
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASCADE_COUNT.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASCADE_COUNT.js +0 -6
|
@@ -1,52 +1,161 @@
|
|
|
1
1
|
import { assert } from "../../../core/assert.js";
|
|
2
2
|
import { bvh_query_user_data_intersects_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_intersects_aabb.js";
|
|
3
3
|
import { returnTrue } from "../../../core/function/returnTrue.js";
|
|
4
|
+
import { lowbias32 } from "../../../core/math/hash/lowbias32.js";
|
|
4
5
|
import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
|
|
6
|
+
import { aabb3_transform_oriented_inverse } from "../../../core/geom/3d/aabb/aabb3_transform_oriented_inverse.js";
|
|
5
7
|
import { body_id_index } from "../body/BodyStorage.js";
|
|
6
8
|
import { gjk } from "../../../core/geom/3d/gjk/gjk.js";
|
|
9
|
+
import {
|
|
10
|
+
GJK_DISTANCE_RELATIVE_GAP,
|
|
11
|
+
gjk_distance,
|
|
12
|
+
gjk_simplex_translate_b,
|
|
13
|
+
GJKSimplex
|
|
14
|
+
} from "../../../core/geom/3d/gjk/gjk_distance.js";
|
|
7
15
|
import { mpr } from "../../../core/geom/3d/gjk/mpr.js";
|
|
8
16
|
import { PosedShape3D } from "../../../core/geom/3d/shape/PosedShape3D.js";
|
|
17
|
+
import { Triangle3D } from "../../../core/geom/3d/shape/Triangle3D.js";
|
|
18
|
+
import { tri3_closest_point } from "../../../core/geom/3d/triangle/tri3_closest_point.js";
|
|
19
|
+
import { v3_quaternion_apply } from "../../../core/geom/vec3/v3_quaternion_apply.js";
|
|
20
|
+
import { v3_quaternion_apply_inverse } from "../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
|
|
21
|
+
import { TriangleEdgeFlags } from "../../../core/geom/3d/triangle/TriangleEdgeFlags.js";
|
|
22
|
+
import { decompose_to_triangles } from "../narrowphase/decomposition/decompose_to_triangles.js";
|
|
23
|
+
import { TRIANGLE_FEATURE_ID_OFFSET, TRIANGLE_FLOAT_STRIDE } from "../narrowphase/decomposition/triangle_buffer_layout.js";
|
|
24
|
+
import { triangle_edge_flags } from "../narrowphase/decomposition/triangle_edge_flags.js";
|
|
25
|
+
import { heightmap_box_triangles } from "../narrowphase/refine_ray_concave.js";
|
|
26
|
+
import { rigid_subject_pose } from "../narrowphase/rigid_subject_pose.js";
|
|
27
|
+
import { PENETRATION_SLOP } from "../solver/solve_contacts.js";
|
|
28
|
+
import { Transform64 } from "../../ecs/transform/Transform64.js";
|
|
9
29
|
|
|
10
30
|
/**
|
|
11
|
-
*
|
|
12
|
-
* the sweep length
|
|
13
|
-
*
|
|
14
|
-
* world-scale tolerance), but we cap on relative tolerance so a
|
|
15
|
-
* 10 m sweep doesn't insist on sub-micron precision.
|
|
31
|
+
* The face shortcut's probe distance, and the bracket search's stopping width,
|
|
32
|
+
* as a fraction of the sweep length: precise enough for any practical sweep
|
|
33
|
+
* without a 10 m sweep insisting on sub-micron precision.
|
|
16
34
|
* @type {number}
|
|
17
35
|
*/
|
|
18
36
|
const TOI_TOLERANCE = 1e-4;
|
|
19
37
|
|
|
20
38
|
/**
|
|
21
|
-
* Maximum bisection iterations. `log2(1 / TOI_TOLERANCE)`
|
|
22
|
-
* for any practical sweep; this is the hard upper bound to prevent
|
|
39
|
+
* Maximum bisection iterations of the bracket search. `log2(1 / TOI_TOLERANCE)`
|
|
40
|
+
* is enough for any practical sweep; this is the hard upper bound to prevent
|
|
23
41
|
* pathological inputs (NaN ray, etc.) from hanging the query.
|
|
24
42
|
* @type {number}
|
|
25
43
|
*/
|
|
26
44
|
const MAX_BISECTION = 32;
|
|
27
45
|
|
|
28
46
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* its AABB's extent (true for spheres / boxes / capsules); the slab
|
|
35
|
-
* intersection keeps that interval small even for kilometre-scale
|
|
36
|
-
* sweeps, so this isn't the limit it would otherwise be.
|
|
47
|
+
* Samples of the bracket search's coarse scan for an overlapping moment. Only
|
|
48
|
+
* the fallback for an advancement that did not converge: 32 samples step clean
|
|
49
|
+
* over any feature thinner than 1/32 of the window they cover (a thin beam, a
|
|
50
|
+
* plank or a 1 mm box at an oblique pose — 186 of 300 crossings of a 2 cm beam
|
|
51
|
+
* at 45° were missed when this was the search).
|
|
37
52
|
* @type {number}
|
|
38
53
|
*/
|
|
39
54
|
const COARSE_STEPS = 32;
|
|
40
55
|
|
|
56
|
+
/**
|
|
57
|
+
* The separation at which conservative advancement parks the swept shape short
|
|
58
|
+
* of a candidate: the reported pose is apart from it by at least this, and by
|
|
59
|
+
* no more than this plus {@link ADVANCE_TOLERANCE}. Box3D parks at its linear
|
|
60
|
+
* slop; this sits a tenth of {@link CONTACT_EPSILON} out, far under any skin a
|
|
61
|
+
* caller keeps — and, being apart, it is a pose the narrowphase (which reports
|
|
62
|
+
* only positive penetration) does not call a contact.
|
|
63
|
+
* @type {number}
|
|
64
|
+
*/
|
|
65
|
+
const ADVANCE_TARGET = 1e-5;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* How far past {@link ADVANCE_TARGET} the advancement may stop. Box3D's ratio,
|
|
69
|
+
* a quarter of the target.
|
|
70
|
+
* @type {number}
|
|
71
|
+
*/
|
|
72
|
+
const ADVANCE_TOLERANCE = 0.25 * ADVANCE_TARGET;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* How exactly the advancement asks the distance kernel for its gap on the way
|
|
76
|
+
* in. It steps by the gap's lower bound along that bound's normal, which is
|
|
77
|
+
* safe for any plane that separates the two, and a sweep that does not close
|
|
78
|
+
* on such a plane can never touch: neither needs the closest one. A bound this
|
|
79
|
+
* far under the truth shortens a step by no more than this, so the step still
|
|
80
|
+
* lands within {@link ADVANCE_TOLERANCE} of the target. What the touch is
|
|
81
|
+
* judged and reported by — its gap, its normal, whether the sweep still closes
|
|
82
|
+
* on it — is asked again at full precision once the bound is inside the touch
|
|
83
|
+
* band: a 2.5e-6 gap leaves a curved pair's normal up to half a degree off, and
|
|
84
|
+
* a body the sweep stopped at a corner kept up to 2 m/s of slide along it.
|
|
85
|
+
*
|
|
86
|
+
* The kernel's own stop, a 1e-10 relative gap, ran a sphere's queries 23
|
|
87
|
+
* iterations on average, a quarter to a third of them to its 32-iteration
|
|
88
|
+
* cap; asked this loosely on the way in, a sphere's casts at a mesh or a
|
|
89
|
+
* heightmap run in 0.63 to 0.76 of the time, a capsule's in 0.78 to 0.89.
|
|
90
|
+
* @type {number}
|
|
91
|
+
*/
|
|
92
|
+
const ADVANCE_DISTANCE_TOLERANCE = ADVANCE_TOLERANCE;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Contacts that begin within this of each other along the sweep are one
|
|
96
|
+
* instant for ranking candidates, and a triangle FACE struck in that instant
|
|
97
|
+
* wins over anything else — another triangle's edge, a convex collider. A
|
|
98
|
+
* shape landing flat on a mesh face meets the seam to the face's other half at
|
|
99
|
+
* the very instant it meets the face, and the edge's contact, read off the
|
|
100
|
+
* closest points, carries its own normal: a box landing on a cube face read
|
|
101
|
+
* one 21° off it.
|
|
102
|
+
* @type {number}
|
|
103
|
+
*/
|
|
104
|
+
const SIMULTANEOUS = ADVANCE_TARGET;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Most distance queries one candidate's advancement runs before it is taken
|
|
108
|
+
* as not converging and handed to the bracket search. A flat approach closes
|
|
109
|
+
* in one step and a curved one in a few; a near-graze converges linearly, the
|
|
110
|
+
* gap quartering per step, and takes about ten from metres away.
|
|
111
|
+
* @type {number}
|
|
112
|
+
*/
|
|
113
|
+
const ADVANCE_MAX_ITERATIONS = 32;
|
|
114
|
+
|
|
41
115
|
const swept_aabb = new Float64Array(6);
|
|
42
116
|
const local_aabb = new Float64Array(6);
|
|
43
117
|
const initial_aabb = new Float64Array(6);
|
|
44
118
|
const target_local_aabb = new Float64Array(6);
|
|
45
119
|
const target_world_aabb = new Float64Array(6);
|
|
46
120
|
|
|
47
|
-
// GJK simplex buffer (used to detect overlap
|
|
121
|
+
// GJK simplex buffer (used to detect overlap at a sample pose).
|
|
48
122
|
const simplex_buf = new Float64Array(12);
|
|
49
123
|
|
|
124
|
+
/**
|
|
125
|
+
* The distance kernel's simplex and result, for conservative advancement. The
|
|
126
|
+
* simplex is carried from one advancement step to the next (the swept shape
|
|
127
|
+
* only translates between them), so each query starts where the last ended.
|
|
128
|
+
*/
|
|
129
|
+
const distance_simplex = new GJKSimplex();
|
|
130
|
+
const distance_result = new Float64Array(10);
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The contact normal of the last {@link cast_candidate} hit found by
|
|
134
|
+
* advancement — the separating direction from the candidate to the swept shape
|
|
135
|
+
* at the reported pose — and whether there is one ({@link cast_has_normal}).
|
|
136
|
+
*/
|
|
137
|
+
const cast_normal = new Float64Array(3);
|
|
138
|
+
let cast_has_normal = false;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* When the contact of the last {@link cast_candidate} hit actually begins, as
|
|
142
|
+
* near as it is known: a face's opening exactly, advancement's stop plus the
|
|
143
|
+
* gap it stopped short by over the closing speed, otherwise the reported time
|
|
144
|
+
* itself. Candidates are ranked by it rather than by the time they report: an
|
|
145
|
+
* advancement parks {@link ADVANCE_TARGET} short of its contact, so ranked by
|
|
146
|
+
* report it beat a face struck at the same instant — a sphere landing on a mesh
|
|
147
|
+
* face a millimetre from the seam took the neighbour's seam edge, 1.1° off.
|
|
148
|
+
* @type {number}
|
|
149
|
+
*/
|
|
150
|
+
let cast_touch_t = 0;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Whether an advancement that ran out of iterations has been reported (once
|
|
154
|
+
* per process).
|
|
155
|
+
* @type {boolean}
|
|
156
|
+
*/
|
|
157
|
+
let advance_exhaustion_reported = false;
|
|
158
|
+
|
|
50
159
|
// Scratch for MPR's MTV output — same vec3 convention as EPA: direction
|
|
51
160
|
// is "A's interior into B" with the magnitude being the depth. We use
|
|
52
161
|
// MPR for the contact-normal recovery at the kiss point because it
|
|
@@ -57,7 +166,7 @@ const mpr_result = new Float64Array(3);
|
|
|
57
166
|
/**
|
|
58
167
|
* Long-lived PosedShape3D adapters for the swept shape and the
|
|
59
168
|
* candidate's collider. Both are re-bound per query — the swept one
|
|
60
|
-
* also gets its position field re-written every
|
|
169
|
+
* also gets its position field re-written at every sample pose
|
|
61
170
|
* without re-running `setup()`, since shape and rotation are
|
|
62
171
|
* constant through the sweep.
|
|
63
172
|
*/
|
|
@@ -71,6 +180,290 @@ const candidate_posed = new PosedShape3D();
|
|
|
71
180
|
*/
|
|
72
181
|
let scratch_candidates = new Uint32Array(64);
|
|
73
182
|
|
|
183
|
+
/**
|
|
184
|
+
* "Already tested in this query" stamps, indexed by body index. Every collider
|
|
185
|
+
* of a body owns a separate broadphase leaf carrying that body's id, so a
|
|
186
|
+
* compound body arrives in {@link scratch_candidates} once per overlapping
|
|
187
|
+
* collider, and each arrival tests all of its colliders: a sweep along a row
|
|
188
|
+
* of K children ran K² collider casts (64 children: 4,096 casts, 0.54 ms).
|
|
189
|
+
* Stamped rather than cleared so the cost stays O(1) per query; the same
|
|
190
|
+
* scheme as `overlap_shape`'s.
|
|
191
|
+
* @type {Int32Array}
|
|
192
|
+
*/
|
|
193
|
+
let scratch_seen = new Int32Array(64);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Stamp written into {@link scratch_seen} by the query in progress. Starts
|
|
197
|
+
* at 1 so a freshly zeroed (or freshly grown) slot never reads as seen.
|
|
198
|
+
* @type {number}
|
|
199
|
+
*/
|
|
200
|
+
let seen_stamp = 0;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Whether a {@link shape_cast} is in progress. Its candidates, the triangles
|
|
204
|
+
* under it and every pose it tests are module state, so a cast started from
|
|
205
|
+
* inside one — from its filter — would overwrite the outer's half-finished
|
|
206
|
+
* scan (it reported no hit at all).
|
|
207
|
+
*
|
|
208
|
+
* The refusal is an assert, and a consumer's production build strips asserts:
|
|
209
|
+
* there nothing refuses it, and the outer cast misses without a word. A contact
|
|
210
|
+
* filter that runs a shapeCast is the case that bites: the CCD sweep asks it
|
|
211
|
+
* from inside its own cast, and with asserts stripped 200 of 200 fast spheres
|
|
212
|
+
* fired at a 2 cm wall went through it.
|
|
213
|
+
* @type {boolean}
|
|
214
|
+
*/
|
|
215
|
+
let shape_cast_running = false;
|
|
216
|
+
|
|
217
|
+
const NESTED_SHAPE_CAST = 'shape_cast: called from inside a shape_cast, from its filter. A cast keeps its working'
|
|
218
|
+
+ ' state in module scratch, so it cannot run inside another; a raycast or an overlap can. A contact filter'
|
|
219
|
+
+ ' (PhysicsSystem.setContactFilter) is one such filter: the CCD sweep asks it from inside its cast.';
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Most triangles of one concave collider a sweep is tested against at once: the
|
|
223
|
+
* bound on {@link triangle_buffer}'s growth, the same 65,536 as the narrowphase,
|
|
224
|
+
* `compute_penetration`, `overlap_shape` and the ray's `refine_ray_concave`.
|
|
225
|
+
* A sweep whose box takes in more is walked a piece at a time, as the ray's is,
|
|
226
|
+
* each piece short enough for its box to fit; only a piece too short to split
|
|
227
|
+
* further — a pile of triangles in one spot — is tested against the first
|
|
228
|
+
* 65,536, and that is reported once. Unbounded, the scratch grew with the
|
|
229
|
+
* sweep's box, 80 bytes a triangle: a 140 m cast across a 100 m floor of 320,000
|
|
230
|
+
* triangles kept 25.6 MB of them.
|
|
231
|
+
* @type {number}
|
|
232
|
+
*/
|
|
233
|
+
const MAX_TRIANGLES_PER_PAIR = 1 << 16;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Shortest piece of a sweep worth splitting further, as a fraction of it — the
|
|
237
|
+
* ray's `MIN_PIECE_FRACTION`.
|
|
238
|
+
* @type {number}
|
|
239
|
+
*/
|
|
240
|
+
const MIN_PIECE_FRACTION = 1 / (1 << 20);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Whether a piece too short to split has overflowed (once per process).
|
|
244
|
+
* @type {boolean}
|
|
245
|
+
*/
|
|
246
|
+
let triangle_overflow_reported = false;
|
|
247
|
+
|
|
248
|
+
/** The swept box of one piece of the sweep. */
|
|
249
|
+
const piece_aabb = new Float64Array(6);
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* A concave target's triangles that may overlap the swept AABB, in the target's
|
|
253
|
+
* local frame, laid out as {@link decompose_to_triangles} writes them. Grows by
|
|
254
|
+
* doubling when a sweep covers more triangles than it holds — a dropped triangle
|
|
255
|
+
* is a hole in the surface, and the sweep would pass straight through it — up
|
|
256
|
+
* to {@link MAX_TRIANGLES_PER_PAIR}; the high-water mark is kept.
|
|
257
|
+
* @type {Float64Array}
|
|
258
|
+
*/
|
|
259
|
+
let triangle_buffer = new Float64Array(256 * TRIANGLE_FLOAT_STRIDE);
|
|
260
|
+
|
|
261
|
+
/** The swept AABB re-expressed in a concave target's local frame. */
|
|
262
|
+
const concave_query_aabb = new Float64Array(6);
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* The world pose of the mesh or heightmap a rigid TransformedShape3D collider wraps: the collider's
|
|
266
|
+
* pose composed with the wrapper's ({@link rigid_subject_pose}). And its copy for the winner, which
|
|
267
|
+
* the next wrapped collider would otherwise move.
|
|
268
|
+
*/
|
|
269
|
+
const subject_pose = new Transform64();
|
|
270
|
+
const best_subject_pose = new Transform64();
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The triangle under test, in its collider's local frame, and that collider's
|
|
274
|
+
* transform. `candidate_is_triangle` says whether `candidate_posed` is posing
|
|
275
|
+
* it (rather than a convex collider).
|
|
276
|
+
*/
|
|
277
|
+
const triangle_local = new Float64Array(9);
|
|
278
|
+
/** @type {Transform64|null} */
|
|
279
|
+
let triangle_tr = null;
|
|
280
|
+
let candidate_is_triangle = false;
|
|
281
|
+
|
|
282
|
+
/** The nearest triangle hit so far, kept for the normal probe after the scan. */
|
|
283
|
+
const best_triangle_local = new Float64Array(9);
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* {@link triangle_local} relative to an ANCHOR point on the triangle, and the
|
|
287
|
+
* flyweight shape bound to it; `candidate_posed` poses it at the anchor.
|
|
288
|
+
*
|
|
289
|
+
* Anchoring is what lets the convex machinery below run on a triangle. GJK
|
|
290
|
+
* does not care where a shape's origin is, but MPR takes the posed shape's
|
|
291
|
+
* position as a point INSIDE it (its V0) and reports the depth along the ray
|
|
292
|
+
* from V0 through the origin — and the normal probes close on that position.
|
|
293
|
+
* A mesh's own origin can be metres off any one triangle, so the anchor must
|
|
294
|
+
* be ON the triangle: its centroid while sweeping, and for a normal probe the
|
|
295
|
+
* point of the triangle nearest the probed shape, which aims MPR's ray down
|
|
296
|
+
* the contact normal. The centroid would not do there: from a contact near the
|
|
297
|
+
* triangle's edge — the seam between two triangles of one flat face — the ray
|
|
298
|
+
* to it leaves through the edge, and MPR reports a normal tilted ~16° off the
|
|
299
|
+
* face it struck.
|
|
300
|
+
*/
|
|
301
|
+
const triangle_vertices = new Float64Array(9);
|
|
302
|
+
const triangle_shape = new Triangle3D().bind(triangle_vertices, 0);
|
|
303
|
+
|
|
304
|
+
/** Scratch: a point in a collider's frame, and the same point in world space. */
|
|
305
|
+
const anchor_local = new Float64Array(3);
|
|
306
|
+
const anchor_world = new Float64Array(3);
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* The part of the sweep that can touch the triangle under test, written by
|
|
310
|
+
* {@link load_triangle}; empty (`enter > exit`) when the sweep does not close
|
|
311
|
+
* on its plane.
|
|
312
|
+
*/
|
|
313
|
+
let triangle_window_enter = Infinity;
|
|
314
|
+
let triangle_window_exit = -Infinity;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* How far the swept shape reaches across the plane of the triangle under test
|
|
318
|
+
* as the sweep starts, when the sweep closes on that plane; written by
|
|
319
|
+
* {@link load_triangle}.
|
|
320
|
+
* @type {number}
|
|
321
|
+
*/
|
|
322
|
+
let triangle_start_depth = Infinity;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* When the swept shape's centre passes through the triangle under test — its
|
|
326
|
+
* plane, within its edges — or `Infinity` when it does not; written by
|
|
327
|
+
* {@link load_triangle}.
|
|
328
|
+
* @type {number}
|
|
329
|
+
*/
|
|
330
|
+
let triangle_centre_crossing = Infinity;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Whether the triangle under test is one the sweep does NOT close on, so that
|
|
334
|
+
* its edges may still be met ({@link triangle_edges_to_sweep}); written by
|
|
335
|
+
* {@link load_triangle}, with what that needs: the concave shape it came from,
|
|
336
|
+
* the plane's unit normal in that shape's frame facing the sweep's start, and
|
|
337
|
+
* the nearest the sweep's origin comes to the plane.
|
|
338
|
+
* @type {boolean}
|
|
339
|
+
*/
|
|
340
|
+
let triangle_edges_pending = false;
|
|
341
|
+
/** @type {AbstractShape3D|null} */
|
|
342
|
+
let triangle_edge_shape = null;
|
|
343
|
+
const triangle_plane_local = new Float64Array(3);
|
|
344
|
+
let triangle_edge_nearest = 0;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* One edge of the triangle under test, as a segment — a triangle whose last two
|
|
348
|
+
* vertices coincide — relative to the edge's midpoint, where `candidate_posed`
|
|
349
|
+
* poses it.
|
|
350
|
+
*/
|
|
351
|
+
const edge_vertices = new Float64Array(9);
|
|
352
|
+
const edge_shape = new Triangle3D().bind(edge_vertices, 0);
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Where the triangle under test sits in {@link triangle_buffer}, and how many
|
|
356
|
+
* triangles of its collider the buffer holds — for the search for its
|
|
357
|
+
* neighbours in {@link triangle_edges_to_sweep}.
|
|
358
|
+
*/
|
|
359
|
+
let triangle_offset = 0;
|
|
360
|
+
let triangle_count = 0;
|
|
361
|
+
|
|
362
|
+
/** Scratch: the contact normal of the best edge hit so far. */
|
|
363
|
+
const edge_normal = new Float64Array(3);
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* The point of the swept shape that reaches the plane of the triangle under
|
|
367
|
+
* test first — its support toward the plane — at the sweep's origin; written by
|
|
368
|
+
* {@link load_triangle} when the sweep closes on the plane.
|
|
369
|
+
*/
|
|
370
|
+
const triangle_touch_origin = new Float64Array(3);
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Whether the swept shape, reaching the plane of the triangle under test at
|
|
374
|
+
* `t` (its window's opening), reaches it on the triangle: whether the point
|
|
375
|
+
* that touches the plane first ({@link triangle_touch_origin}, carried along
|
|
376
|
+
* the sweep to `t`) lies within the triangle's edges. A point on an edge
|
|
377
|
+
* counts — the seam of a face split in two belongs to both halves.
|
|
378
|
+
*
|
|
379
|
+
* @param {number} dx unit sweep direction
|
|
380
|
+
* @param {number} dy
|
|
381
|
+
* @param {number} dz
|
|
382
|
+
* @param {number} t
|
|
383
|
+
* @returns {boolean}
|
|
384
|
+
*/
|
|
385
|
+
function triangle_touch_inside(dx, dy, dz, t) {
|
|
386
|
+
const tr = triangle_tr;
|
|
387
|
+
v3_quaternion_apply_inverse(
|
|
388
|
+
anchor_local, 0,
|
|
389
|
+
triangle_touch_origin[0] + dx * t - tr.translation_x,
|
|
390
|
+
triangle_touch_origin[1] + dy * t - tr.translation_y,
|
|
391
|
+
triangle_touch_origin[2] + dz * t - tr.translation_z,
|
|
392
|
+
tr.rotation_x, tr.rotation_y, tr.rotation_z, tr.rotation_w
|
|
393
|
+
);
|
|
394
|
+
const px = anchor_local[0], py = anchor_local[1], pz = anchor_local[2];
|
|
395
|
+
const v = triangle_local;
|
|
396
|
+
|
|
397
|
+
const e1x = v[3] - v[0], e1y = v[4] - v[1], e1z = v[5] - v[2];
|
|
398
|
+
const e2x = v[6] - v[0], e2y = v[7] - v[1], e2z = v[8] - v[2];
|
|
399
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
400
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
401
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
402
|
+
|
|
403
|
+
// the point is on the inner side of every edge: (edge × to-point) · normal ≥ 0
|
|
404
|
+
for (let k = 0; k < 3; k++) {
|
|
405
|
+
const a = 3 * k, b = 3 * ((k + 1) % 3);
|
|
406
|
+
const ex = v[b] - v[a], ey = v[b + 1] - v[a + 1], ez = v[b + 2] - v[a + 2];
|
|
407
|
+
const qx = px - v[a], qy = py - v[a + 1], qz = pz - v[a + 2];
|
|
408
|
+
const cx = ey * qz - ez * qy;
|
|
409
|
+
const cy = ez * qx - ex * qz;
|
|
410
|
+
const cz = ex * qy - ey * qx;
|
|
411
|
+
if (cx * nx + cy * ny + cz * nz < 0) return false;
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The world normal of the triangle under test, facing the sweep's start —
|
|
418
|
+
* written by {@link load_triangle} when the sweep closes on it — and a support
|
|
419
|
+
* point scratch.
|
|
420
|
+
*/
|
|
421
|
+
const plane_normal = new Float64Array(3);
|
|
422
|
+
const support_point = new Float64Array(3);
|
|
423
|
+
|
|
424
|
+
/** The reversed {@link plane_normal}, the direction the swept shape's near support is asked along. */
|
|
425
|
+
const plane_normal_reversed = new Float64Array(3);
|
|
426
|
+
|
|
427
|
+
/** The sweep's origin [0..2] and unit direction [3..5] in a concave collider's frame. */
|
|
428
|
+
const local_sweep = new Float64Array(6);
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Whether the last {@link cast_candidate} hit was a triangle FACE contact —
|
|
432
|
+
* the shape met the triangle where it first reached its plane — whose normal
|
|
433
|
+
* is the face's.
|
|
434
|
+
* @type {boolean}
|
|
435
|
+
*/
|
|
436
|
+
let cast_face = false;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* The contact normal the nearest hit so far came with, when it came with one:
|
|
440
|
+
* a triangle face's, or the separating direction advancement stopped on.
|
|
441
|
+
*/
|
|
442
|
+
const best_normal = new Float64Array(3);
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* What the last successful {@link shape_cast} struck, in world space: the
|
|
446
|
+
* convex collider, or the triangle of a concave one (its vertices kept here,
|
|
447
|
+
* the collider's frame). Read through {@link shape_cast_struck_support}.
|
|
448
|
+
*/
|
|
449
|
+
const struck_posed = new PosedShape3D();
|
|
450
|
+
const struck_triangle_vertices = new Float64Array(9);
|
|
451
|
+
const struck_triangle_shape = new Triangle3D().bind(struck_triangle_vertices, 0);
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* {@link cast_candidate}: the sweep does not reach this candidate before the
|
|
455
|
+
* limit, or steps over it.
|
|
456
|
+
* @type {number}
|
|
457
|
+
*/
|
|
458
|
+
const CAST_MISS = -1;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* {@link cast_candidate}: the shape starts inside this candidate and cannot
|
|
462
|
+
* move at all.
|
|
463
|
+
* @type {number}
|
|
464
|
+
*/
|
|
465
|
+
const CAST_BLOCKED = -2;
|
|
466
|
+
|
|
74
467
|
/**
|
|
75
468
|
* Depths at or below this are not a contact. A kissing pair is not always
|
|
76
469
|
* numerically exact — MPR returns a few microns of "overlap" for a sphere
|
|
@@ -107,10 +500,65 @@ const NORMAL_PROBE_OFFSET = 0.01;
|
|
|
107
500
|
*/
|
|
108
501
|
const probe_normal = new Float64Array(3);
|
|
109
502
|
|
|
503
|
+
/**
|
|
504
|
+
* Pose {@link triangle_local} as `candidate_posed`, anchored at the point
|
|
505
|
+
* `(lx, ly, lz)` of the triangle (in its collider's frame) — see
|
|
506
|
+
* {@link triangle_vertices}.
|
|
507
|
+
*
|
|
508
|
+
* @param {number} lx
|
|
509
|
+
* @param {number} ly
|
|
510
|
+
* @param {number} lz
|
|
511
|
+
*/
|
|
512
|
+
function anchor_triangle(lx, ly, lz) {
|
|
513
|
+
for (let i = 0; i < 9; i += 3) {
|
|
514
|
+
triangle_vertices[i] = triangle_local[i] - lx;
|
|
515
|
+
triangle_vertices[i + 1] = triangle_local[i + 1] - ly;
|
|
516
|
+
triangle_vertices[i + 2] = triangle_local[i + 2] - lz;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const tr = triangle_tr;
|
|
520
|
+
const qx = tr.rotation_x, qy = tr.rotation_y, qz = tr.rotation_z, qw = tr.rotation_w;
|
|
521
|
+
v3_quaternion_apply(anchor_world, 0, lx, ly, lz, qx, qy, qz, qw);
|
|
522
|
+
candidate_posed.setup_components(
|
|
523
|
+
triangle_shape,
|
|
524
|
+
tr.translation_x + anchor_world[0],
|
|
525
|
+
tr.translation_y + anchor_world[1],
|
|
526
|
+
tr.translation_z + anchor_world[2],
|
|
527
|
+
qx, qy, qz, qw
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Anchor the triangle under test at its point nearest the world point
|
|
533
|
+
* `(px, py, pz)`.
|
|
534
|
+
*
|
|
535
|
+
* @param {number} px
|
|
536
|
+
* @param {number} py
|
|
537
|
+
* @param {number} pz
|
|
538
|
+
*/
|
|
539
|
+
function anchor_triangle_nearest(px, py, pz) {
|
|
540
|
+
const tr = triangle_tr;
|
|
541
|
+
v3_quaternion_apply_inverse(
|
|
542
|
+
anchor_local, 0,
|
|
543
|
+
px - tr.translation_x, py - tr.translation_y, pz - tr.translation_z,
|
|
544
|
+
tr.rotation_x, tr.rotation_y, tr.rotation_z, tr.rotation_w
|
|
545
|
+
);
|
|
546
|
+
const v = triangle_local;
|
|
547
|
+
tri3_closest_point(
|
|
548
|
+
anchor_local, 0,
|
|
549
|
+
anchor_local[0], anchor_local[1], anchor_local[2],
|
|
550
|
+
v[0], v[1], v[2],
|
|
551
|
+
v[3], v[4], v[5],
|
|
552
|
+
v[6], v[7], v[8]
|
|
553
|
+
);
|
|
554
|
+
anchor_triangle(anchor_local[0], anchor_local[1], anchor_local[2]);
|
|
555
|
+
}
|
|
556
|
+
|
|
110
557
|
/**
|
|
111
558
|
* Recover the target's outward surface normal by running MPR on
|
|
112
559
|
* `swept_posed` displaced to `(px, py, pz)` against `candidate_posed`
|
|
113
|
-
* (both must already be bound by the caller).
|
|
560
|
+
* (both must already be bound by the caller). A triangle target is first
|
|
561
|
+
* re-anchored at its point nearest the probe pose.
|
|
114
562
|
*
|
|
115
563
|
* Returns `false` — leaving `out` untouched — when MPR reports no depth worth
|
|
116
564
|
* the name (at or below {@link CONTACT_EPSILON}). That is not an MPR failure
|
|
@@ -120,33 +568,34 @@ const probe_normal = new Float64Array(3);
|
|
|
120
568
|
* not an overlap".
|
|
121
569
|
*
|
|
122
570
|
* Sign-validation: MPR's polytope can settle on either side of the origin
|
|
123
|
-
* for highly symmetric configurations, so we dot against the
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* direction — i.e. the negated
|
|
571
|
+
* for highly symmetric configurations, so we dot against the axis to the
|
|
572
|
+
* target's centre (`candidate_posed`'s position) and flip if needed (same
|
|
573
|
+
* pattern as `narrowphase_step`'s EPA path). The stored normal is the
|
|
574
|
+
* target's outward surface normal — `B → A` direction — i.e. the negated
|
|
575
|
+
* (validated) MTV.
|
|
127
576
|
*
|
|
128
577
|
* @param {Float64Array} out receives the unit normal on success
|
|
129
578
|
* @param {number} px swept shape's probe centre
|
|
130
579
|
* @param {number} py
|
|
131
580
|
* @param {number} pz
|
|
132
|
-
* @param {Transform64} target_tr the target body's transform (centre for the
|
|
133
|
-
* sign check)
|
|
134
581
|
* @returns {boolean}
|
|
135
582
|
*/
|
|
136
|
-
function probe_contact_normal(out, px, py, pz
|
|
583
|
+
function probe_contact_normal(out, px, py, pz) {
|
|
137
584
|
swept_posed.px = px;
|
|
138
585
|
swept_posed.py = py;
|
|
139
586
|
swept_posed.pz = pz;
|
|
140
587
|
|
|
588
|
+
if (candidate_is_triangle) anchor_triangle_nearest(px, py, pz);
|
|
589
|
+
|
|
141
590
|
if (!mpr(mpr_result, 0, swept_posed, candidate_posed)) return false;
|
|
142
591
|
|
|
143
592
|
let ex = mpr_result[0], ey = mpr_result[1], ez = mpr_result[2];
|
|
144
593
|
const depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
|
|
145
594
|
if (!(depth > CONTACT_EPSILON) || !Number.isFinite(depth)) return false;
|
|
146
595
|
|
|
147
|
-
const ab_x =
|
|
148
|
-
const ab_y =
|
|
149
|
-
const ab_z =
|
|
596
|
+
const ab_x = candidate_posed.px - px;
|
|
597
|
+
const ab_y = candidate_posed.py - py;
|
|
598
|
+
const ab_z = candidate_posed.pz - pz;
|
|
150
599
|
if (ex * ab_x + ey * ab_y + ez * ab_z < 0) {
|
|
151
600
|
ex = -ex; ey = -ey; ez = -ez;
|
|
152
601
|
}
|
|
@@ -180,8 +629,9 @@ function probe_contact_normal(out, px, py, pz, target_tr) {
|
|
|
180
629
|
* probe 1 separates them further. Either way MPR reports zero depth, and zero
|
|
181
630
|
* depth carries no direction.
|
|
182
631
|
*
|
|
183
|
-
* So probe 2 displaces toward the target's CENTRE
|
|
184
|
-
*
|
|
632
|
+
* So probe 2 displaces toward the target's CENTRE — a convex collider's
|
|
633
|
+
* origin, or a triangle's point nearest the contact pose — which is interior to
|
|
634
|
+
* it (MPR's own precondition) and so closes on it from any contact orientation.
|
|
185
635
|
* It starts from the CONTACT pose rather than probe 1's — anchoring it at
|
|
186
636
|
* probe 1's pose lets a sweep directly away from the surface cancel the two
|
|
187
637
|
* displacements against each other and land back on the tangency it was trying
|
|
@@ -211,21 +661,24 @@ function probe_contact_normal(out, px, py, pz, target_tr) {
|
|
|
211
661
|
* @param {number} dx unit sweep direction
|
|
212
662
|
* @param {number} dy
|
|
213
663
|
* @param {number} dz
|
|
214
|
-
* @param {Transform64} target_tr the target body's transform
|
|
215
664
|
* @returns {boolean} false when every probe degenerates — `out` is untouched
|
|
216
665
|
*/
|
|
217
|
-
function recover_contact_normal(out, cx, cy, cz, dx, dy, dz
|
|
666
|
+
function recover_contact_normal(out, cx, cy, cz, dx, dy, dz) {
|
|
218
667
|
if (probe_contact_normal(
|
|
219
668
|
out,
|
|
220
669
|
cx + dx * NORMAL_PROBE_OFFSET,
|
|
221
670
|
cy + dy * NORMAL_PROBE_OFFSET,
|
|
222
671
|
cz + dz * NORMAL_PROBE_OFFSET,
|
|
223
|
-
target_tr,
|
|
224
672
|
)) return true;
|
|
225
673
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
674
|
+
// A triangle's centre for this purpose is its point nearest the contact
|
|
675
|
+
// pose: straight down the contact normal for a face, which is what the
|
|
676
|
+
// probe should close along.
|
|
677
|
+
if (candidate_is_triangle) anchor_triangle_nearest(cx, cy, cz);
|
|
678
|
+
|
|
679
|
+
const ab_x = candidate_posed.px - cx;
|
|
680
|
+
const ab_y = candidate_posed.py - cy;
|
|
681
|
+
const ab_z = candidate_posed.pz - cz;
|
|
229
682
|
const ab_len = Math.sqrt(ab_x * ab_x + ab_y * ab_y + ab_z * ab_z);
|
|
230
683
|
// Coincident centres leave no direction to close along, and the shapes are
|
|
231
684
|
// then as overlapped as they get — probe 1 already had its answer. The
|
|
@@ -237,11 +690,1228 @@ function recover_contact_normal(out, cx, cy, cz, dx, dy, dz, target_tr) {
|
|
|
237
690
|
// in log2(ab_len / NORMAL_PROBE_OFFSET) steps. Stopping there keeps the
|
|
238
691
|
// probe on the near side of the target's centre.
|
|
239
692
|
for (let d = NORMAL_PROBE_OFFSET; d < ab_len; d *= 2) {
|
|
240
|
-
if (probe_contact_normal(out, cx + ux * d, cy + uy * d, cz + uz * d
|
|
693
|
+
if (probe_contact_normal(out, cx + ux * d, cy + uy * d, cz + uz * d)) return true;
|
|
694
|
+
}
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Time of impact of `swept_posed` — swept from `(ox, oy, oz)` along unit
|
|
700
|
+
* `(dx, dy, dz)` — against the one convex `candidate_posed`, searched on
|
|
701
|
+
* `[0, t_limit)`. Both must already be bound by the caller (shape and
|
|
702
|
+
* rotation for the swept one; shape and full pose for the candidate), and
|
|
703
|
+
* `swept_aabb` / `initial_aabb` must hold this sweep's bounds.
|
|
704
|
+
*
|
|
705
|
+
* A convex collider is one candidate; a concave one is as many candidates as
|
|
706
|
+
* it has triangles under the sweep, each run through here on its own, so
|
|
707
|
+
* every rule below — the initial-overlap semantics included — holds per
|
|
708
|
+
* triangle exactly as it holds per collider.
|
|
709
|
+
*
|
|
710
|
+
* @param {number} ox
|
|
711
|
+
* @param {number} oy
|
|
712
|
+
* @param {number} oz
|
|
713
|
+
* @param {number} dx
|
|
714
|
+
* @param {number} dy
|
|
715
|
+
* @param {number} dz
|
|
716
|
+
* @param {number} t_limit only an impact strictly before this is wanted
|
|
717
|
+
* @param {number} stop_width the face shortcut's probe distance, and the
|
|
718
|
+
* bracket search's resolution
|
|
719
|
+
* @param {boolean} skip_initial_overlaps see {@link shape_cast}
|
|
720
|
+
* @param {number} window_enter the sweep can first touch the candidate no
|
|
721
|
+
* earlier than this (`-Infinity` when nothing narrower than its AABB is
|
|
722
|
+
* known)…
|
|
723
|
+
* @param {number} window_exit …and no later than this; an empty window
|
|
724
|
+
* (`enter > exit`) means the candidate is only tested for overlap at the
|
|
725
|
+
* start, and never swept. A finite window is a triangle's PLANE window (see
|
|
726
|
+
* {@link load_triangle}), and opens the face shortcut below.
|
|
727
|
+
* @returns {number} the time of impact (a pose still apart from the
|
|
728
|
+
* candidate), {@link CAST_MISS}, or {@link CAST_BLOCKED}; {@link cast_face}
|
|
729
|
+
* says whether it was a face contact, and {@link cast_has_normal} whether
|
|
730
|
+
* {@link cast_normal} holds its contact normal
|
|
731
|
+
*/
|
|
732
|
+
function cast_candidate(ox, oy, oz, dx, dy, dz, t_limit, stop_width, skip_initial_overlaps, window_enter, window_exit) {
|
|
733
|
+
cast_face = false;
|
|
734
|
+
cast_has_normal = false;
|
|
735
|
+
|
|
736
|
+
const empty_window = !(window_enter <= window_exit);
|
|
737
|
+
// a triangle whose face is not swept may still have edges that are
|
|
738
|
+
const edges_pending = empty_window && candidate_is_triangle && triangle_edges_pending;
|
|
739
|
+
|
|
740
|
+
// Under CCD semantics a candidate that is never swept is a miss whether it
|
|
741
|
+
// overlaps the start (skipped) or not — all there is to ask of a triangle
|
|
742
|
+
// not closed on is whether the shape meets one of its edges, the cheapest
|
|
743
|
+
// tests first (most triangles have none to sweep: a floor's are all flat).
|
|
744
|
+
// Whether the shape starts in the triangle is asked only of an edge it
|
|
745
|
+
// would otherwise hit (see `cast_triangle_edges`).
|
|
746
|
+
if (empty_window && skip_initial_overlaps) {
|
|
747
|
+
const edges = edges_pending ? triangle_edges_to_sweep(ox, oy, oz, skip_initial_overlaps) : 0;
|
|
748
|
+
return edges !== 0
|
|
749
|
+
? cast_triangle_edges(ox, oy, oz, dx, dy, dz, t_limit, stop_width, skip_initial_overlaps, edges)
|
|
750
|
+
: CAST_MISS;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// The candidate's tight world AABB. A candidate whose AABB misses the
|
|
754
|
+
// whole swept volume can neither overlap the shape at the start nor be
|
|
755
|
+
// reached along the sweep — the cheap answer for most of a concave
|
|
756
|
+
// target's triangles, which are enumerated without a height filter.
|
|
757
|
+
candidate_posed.shape.compute_bounding_box(target_local_aabb);
|
|
758
|
+
aabb3_transform_oriented(
|
|
759
|
+
target_world_aabb, 0,
|
|
760
|
+
target_local_aabb[0], target_local_aabb[1], target_local_aabb[2],
|
|
761
|
+
target_local_aabb[3], target_local_aabb[4], target_local_aabb[5],
|
|
762
|
+
candidate_posed.px, candidate_posed.py, candidate_posed.pz,
|
|
763
|
+
candidate_posed.qx, candidate_posed.qy, candidate_posed.qz, candidate_posed.qw
|
|
764
|
+
);
|
|
765
|
+
if (target_world_aabb[0] > swept_aabb[3] || target_world_aabb[3] < swept_aabb[0]
|
|
766
|
+
|| target_world_aabb[1] > swept_aabb[4] || target_world_aabb[4] < swept_aabb[1]
|
|
767
|
+
|| target_world_aabb[2] > swept_aabb[5] || target_world_aabb[5] < swept_aabb[2]) {
|
|
768
|
+
return CAST_MISS;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Already overlapping at t = 0? There is no time of impact to search
|
|
772
|
+
// for: the shapes never come into contact, they start in it. Under CCD
|
|
773
|
+
// semantics it is a resting contact to step over — skip THIS candidate
|
|
774
|
+
// only, and keep scanning for real blockers.
|
|
775
|
+
//
|
|
776
|
+
// Under kinematic semantics targets are SOLID: a shape that starts
|
|
777
|
+
// genuinely inside one is blocked where it stands, `t = 0`, whatever
|
|
778
|
+
// direction it is trying to sweep. Nothing can beat that, so stop
|
|
779
|
+
// scanning. Getting out is depenetration's job, not the sweep's.
|
|
780
|
+
//
|
|
781
|
+
// Exact TANGENCY is the exception, and it needs one. A zero-depth
|
|
782
|
+
// touch is not "inside" anything — the shape is resting against a
|
|
783
|
+
// face, or flush with a brush seam, and is free to slide along it or
|
|
784
|
+
// leave. It also survives depenetration, which has no depth to push
|
|
785
|
+
// out of, so it persists frame after frame.
|
|
786
|
+
//
|
|
787
|
+
// Reporting it as a `t = 0` hit ends the scan, and that is the whole
|
|
788
|
+
// problem: the caller is handed a contact it correctly judges harmless
|
|
789
|
+
// for this direction and concludes the sweep is clear, while the body
|
|
790
|
+
// it was actually about to hit was never tested. A character flush
|
|
791
|
+
// against a wall falls through the floor that way. So a tangency
|
|
792
|
+
// blocks only when the sweep drives INTO it, and otherwise steps aside
|
|
793
|
+
// and lets the scan continue.
|
|
794
|
+
//
|
|
795
|
+
// MPR's depth at the START pose is what separates the two: positive
|
|
796
|
+
// means genuine overlap, none means tangency. Tangency is also exactly
|
|
797
|
+
// where the normal is hardest to recover, hence the second probe; if
|
|
798
|
+
// even that degenerates there is no normal to judge with and the
|
|
799
|
+
// contact blocks, stopping short being the safe failure.
|
|
800
|
+
//
|
|
801
|
+
// A triangle whose plane the shape has not reached yet (its window opens
|
|
802
|
+
// after t = 0) cannot overlap it at the start, and needs no test.
|
|
803
|
+
//
|
|
804
|
+
// Under CCD semantics two triangles a body starts in are not skipped. One
|
|
805
|
+
// its centre goes through — the plane, within the edges — is a tunnel
|
|
806
|
+
// however deep the body starts, and blocks it where it stands, with the
|
|
807
|
+
// face's normal. One it rests on, in by no more than the solver's slop,
|
|
808
|
+
// that the sweep closes on by more than the slop (its window is open) is
|
|
809
|
+
// judged as a kinematic tangency is: only a sweep driving into it is
|
|
810
|
+
// stopped. Skipped, a 0.4 m box left on a mesh plate by a clamp and pushed
|
|
811
|
+
// down at 100 m/s went through it in one step.
|
|
812
|
+
swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
|
|
813
|
+
if (!(window_enter > 0 && !empty_window) && gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
814
|
+
if (skip_initial_overlaps) {
|
|
815
|
+
if (candidate_is_triangle && !empty_window && triangle_centre_crossing < t_limit) {
|
|
816
|
+
cast_face = true;
|
|
817
|
+
cast_touch_t = 0;
|
|
818
|
+
return CAST_BLOCKED;
|
|
819
|
+
}
|
|
820
|
+
if (!(candidate_is_triangle && !empty_window && triangle_start_depth <= PENETRATION_SLOP)) {
|
|
821
|
+
return CAST_MISS;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (!probe_contact_normal(probe_normal, ox, oy, oz)) {
|
|
826
|
+
const known = recover_contact_normal(probe_normal, ox, oy, oz, dx, dy, dz);
|
|
827
|
+
if (known) {
|
|
828
|
+
// Both vectors are unit, so this is the sine of the angle
|
|
829
|
+
// between the sweep and the contact plane. Zero means
|
|
830
|
+
// exactly parallel — sliding along the face — and positive
|
|
831
|
+
// means leaving it; neither blocks. The tolerance matters
|
|
832
|
+
// because the parallel case sits right on the sign change,
|
|
833
|
+
// and an MPR-recovered normal carries ~1e-6 of angular
|
|
834
|
+
// noise: without it a sweep ALONG a face flips to
|
|
835
|
+
// "head-on" on solver noise alone.
|
|
836
|
+
const into = dx * probe_normal[0] + dy * probe_normal[1] + dz * probe_normal[2];
|
|
837
|
+
if (into > -GRAZING_SINE_EPSILON) return CAST_MISS;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
cast_touch_t = 0;
|
|
842
|
+
return CAST_BLOCKED;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (empty_window) {
|
|
846
|
+
// Not closed on: only an edge is left to meet.
|
|
847
|
+
const edges = edges_pending ? triangle_edges_to_sweep(ox, oy, oz, skip_initial_overlaps) : 0;
|
|
848
|
+
return edges !== 0
|
|
849
|
+
? cast_triangle_edges(ox, oy, oz, dx, dy, dz, t_limit, stop_width, skip_initial_overlaps, edges)
|
|
850
|
+
: CAST_MISS;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// ── Slab intersection: narrow the search interval analytically ─
|
|
854
|
+
//
|
|
855
|
+
// Intersect the candidate's tight world AABB with the swept shape's
|
|
856
|
+
// AABB sliding along the sweep direction. The result is the t-interval
|
|
857
|
+
// `[t_aabb_enter, t_aabb_exit]` during which the two AABBs overlap.
|
|
858
|
+
// Outside this interval the actual shapes can't overlap either (AABB is
|
|
859
|
+
// a superset of the shape), so we get to skip all of [0, t_aabb_enter)
|
|
860
|
+
// and (t_aabb_exit, t_limit] without testing.
|
|
861
|
+
//
|
|
862
|
+
// This is the key to making `shapeCast` scale to long sweeps:
|
|
863
|
+
// a 1 km cast of a 1 m sphere against another 1 m sphere has an
|
|
864
|
+
// AABB-overlap window of ≈ 2 m (the sum of diameters along the
|
|
865
|
+
// sweep axis), reducing the coarse-step grid from a 30 m
|
|
866
|
+
// resolution (1000/32) to 6 cm (2/32).
|
|
867
|
+
let t_aabb_enter = -Infinity;
|
|
868
|
+
let t_aabb_exit = Infinity;
|
|
869
|
+
for (let ax = 0; ax < 3; ax++) {
|
|
870
|
+
const init_min = initial_aabb[ax];
|
|
871
|
+
const init_max = initial_aabb[ax + 3];
|
|
872
|
+
const body_min = target_world_aabb[ax];
|
|
873
|
+
const body_max = target_world_aabb[ax + 3];
|
|
874
|
+
const d_ax = ax === 0 ? dx : (ax === 1 ? dy : dz);
|
|
875
|
+
if (d_ax === 0) {
|
|
876
|
+
// Static along this axis: AABBs must overlap in their
|
|
877
|
+
// initial position or this candidate is unreachable.
|
|
878
|
+
if (init_max < body_min || init_min > body_max) return CAST_MISS;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
// swept_min(t) = init_min + d·t, swept_max(t) = init_max + d·t.
|
|
882
|
+
// Slab-enter: swept_max(t) = body_min → t = (body_min − init_max) / d
|
|
883
|
+
// Slab-exit: swept_min(t) = body_max → t = (body_max − init_min) / d
|
|
884
|
+
const t1 = (body_min - init_max) / d_ax;
|
|
885
|
+
const t2 = (body_max - init_min) / d_ax;
|
|
886
|
+
const lo = t1 < t2 ? t1 : t2;
|
|
887
|
+
const hi = t1 < t2 ? t2 : t1;
|
|
888
|
+
if (lo > t_aabb_enter) t_aabb_enter = lo;
|
|
889
|
+
if (hi < t_aabb_exit) t_aabb_exit = hi;
|
|
890
|
+
}
|
|
891
|
+
if (window_enter > t_aabb_enter) t_aabb_enter = window_enter;
|
|
892
|
+
if (window_exit < t_aabb_exit) t_aabb_exit = window_exit;
|
|
893
|
+
if (t_aabb_enter > t_aabb_exit) return CAST_MISS;
|
|
894
|
+
|
|
895
|
+
// Clamp to the relevant t-window: [0, t_limit]. Anything beyond it
|
|
896
|
+
// can't tighten the answer.
|
|
897
|
+
let t_start = t_aabb_enter > 0 ? t_aabb_enter : 0;
|
|
898
|
+
const t_end = t_aabb_exit < t_limit ? t_aabb_exit : t_limit;
|
|
899
|
+
if (t_start >= t_end) return CAST_MISS;
|
|
900
|
+
|
|
901
|
+
// ── Face contact: answered in closed form ──────────────────────
|
|
902
|
+
//
|
|
903
|
+
// A triangle's window opens the moment the shape reaches its plane, so
|
|
904
|
+
// nothing can touch the triangle sooner — and the point of the shape that
|
|
905
|
+
// reaches the plane first is known: its support toward the plane. If that
|
|
906
|
+
// point lands on the triangle, the shape met the triangle THERE, on its
|
|
907
|
+
// face: the time of impact is the window's opening, exact, and the contact
|
|
908
|
+
// normal is the face's (see `shape_cast`). A support and three cross
|
|
909
|
+
// products instead of an advancement, for every triangle under a body
|
|
910
|
+
// landing on a mesh floor. Otherwise the contact, if any, is with an edge
|
|
911
|
+
// or a corner, later. (The AABB slab can open a rounding error after the
|
|
912
|
+
// plane window does — that is the same instant.)
|
|
913
|
+
//
|
|
914
|
+
// This used to ask instead whether the shape overlapped the triangle a
|
|
915
|
+
// bisection tolerance, 1e-4 of the sweep, past the opening. A sphere's
|
|
916
|
+
// section through the plane by then reaches sideways by the square root
|
|
917
|
+
// of that depth times its diameter, so one reaching the plane just beyond
|
|
918
|
+
// the triangle's edge was taken to have struck the face, and reported the
|
|
919
|
+
// face's normal for the edge's: a 0.5 m sphere 0.15 m past a mesh cube's
|
|
920
|
+
// edge read 17.5° off on a 500 m cast.
|
|
921
|
+
if (window_enter >= 0 && t_start - window_enter <= stop_width) {
|
|
922
|
+
if (triangle_touch_inside(dx, dy, dz, window_enter)) {
|
|
923
|
+
cast_face = true;
|
|
924
|
+
cast_touch_t = t_start;
|
|
925
|
+
return t_start;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// Advance from a little short of the window: where the window opens on the
|
|
930
|
+
// AABB slab of an axis-aligned face, the shapes touch EXACTLY there, and an
|
|
931
|
+
// exact touch has no separating normal to advance along.
|
|
932
|
+
const t_from = t_start - 2 * ADVANCE_TARGET;
|
|
933
|
+
return advance_to_contact(ox, oy, oz, dx, dy, dz, t_from > 0 ? t_from : 0, t_end, stop_width);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* The edges of the triangle under test — bit `k` for edge `k`, vertex `k` to
|
|
938
|
+
* vertex `k + 1` — that a sweep NOT closing on its plane (see
|
|
939
|
+
* {@link triangle_edges_pending}) is run against: none of the face, which it
|
|
940
|
+
* cannot enter, and of the edges, only those it can meet edge-on.
|
|
941
|
+
*
|
|
942
|
+
* It meets an edge from beyond it, so its motion has to carry it back across
|
|
943
|
+
* the edge's line, against the edge's outward direction in the plane; the
|
|
944
|
+
* edges it runs along or away from are behind it.
|
|
945
|
+
*
|
|
946
|
+
* It meets one at all only by already reaching across the plane — by more than
|
|
947
|
+
* {@link CONTACT_EPSILON} at the nearest the sweep comes to it. Not closing,
|
|
948
|
+
* it never reaches further, so a shape that does not straddle the plane cannot
|
|
949
|
+
* meet the triangle, and one merely touching it can only graze it. Under CCD
|
|
950
|
+
* semantics it has to reach across by more than {@link PENETRATION_SLOP} as
|
|
951
|
+
* well, as a plane closed on by no more than the slop is not swept either (see
|
|
952
|
+
* {@link load_triangle}): a body resting in a floor reaches across it by just
|
|
953
|
+
* that much, and an edge it meets only with that much of itself is the
|
|
954
|
+
* solver's to resolve, not something to tunnel through. Swept, every edge the
|
|
955
|
+
* flags and the neighbour search cannot see as interior — a T-junction, tiles
|
|
956
|
+
* a micrometre out of level — stopped a ball rolling across it, every step it
|
|
957
|
+
* crossed.
|
|
958
|
+
*
|
|
959
|
+
* And only at the surface's own boundary: the rim of an open surface, or an
|
|
960
|
+
* edge three faces share. Every other edge lies between exactly two faces, and
|
|
961
|
+
* is met on one of them first. A FLAT edge lies inside the flat stretch the two
|
|
962
|
+
* make, whose own boundary the shape crosses first. A CONCAVE one has its
|
|
963
|
+
* neighbour rising toward the shape, a plane the sweep closes on, and that
|
|
964
|
+
* face's sweep covers the edge. A shape coming at a convex ridge from outside
|
|
965
|
+
* approaches along a normal between the two faces', so it closes on at least
|
|
966
|
+
* one of their planes too, and that face finds the ridge. What is left of a
|
|
967
|
+
* ridge for a sweep closing on neither face is a shape already lying across
|
|
968
|
+
* one of them — a CCD body resting the solver's slop deep in it, a mover flush
|
|
969
|
+
* on it — brushing the ridge with the part of it already in, or on, the
|
|
970
|
+
* surface: the touch it started with, carried along, not something in its way.
|
|
971
|
+
* Swept anyway, where a face meets the ridge a hair after the edge, the edge
|
|
972
|
+
* wins and hands back its slanted normal in place of the face's: a capsule
|
|
973
|
+
* walking edge-on into a 2 mm mesh slab read a normal 0.16° off the end face's,
|
|
974
|
+
* slid along it, and walked off round the slab.
|
|
975
|
+
*
|
|
976
|
+
* The edge flags cannot tell a rim from a ridge, so the boundary is found by
|
|
977
|
+
* looking for the neighbour: the other triangles under the sweep sharing both
|
|
978
|
+
* of an edge's vertices, bit for bit (both enumerators write a shared vertex
|
|
979
|
+
* identically). A mesh's flags are kept and cost a lookup, so they go first and
|
|
980
|
+
* spare a floor — all flat edges — the search, which walks an index of the
|
|
981
|
+
* buffer's edges. A heightmap's neighbours are its grid's, so it needs no search
|
|
982
|
+
* ({@link heightmap_unshared_edges}): its edges all have neighbours but at its
|
|
983
|
+
* border.
|
|
984
|
+
*
|
|
985
|
+
* @param {number} ox sweep origin
|
|
986
|
+
* @param {number} oy
|
|
987
|
+
* @param {number} oz
|
|
988
|
+
* @param {boolean} skip_initial_overlaps see {@link shape_cast}
|
|
989
|
+
* @returns {number}
|
|
990
|
+
*/
|
|
991
|
+
function triangle_edges_to_sweep(ox, oy, oz, skip_initial_overlaps) {
|
|
992
|
+
const v = triangle_local;
|
|
993
|
+
const ldx = local_sweep[3], ldy = local_sweep[4], ldz = local_sweep[5];
|
|
994
|
+
|
|
995
|
+
// the triangle's normal, either way up: the edges' outward directions follow its winding
|
|
996
|
+
const e1x = v[3] - v[0], e1y = v[4] - v[1], e1z = v[5] - v[2];
|
|
997
|
+
const e2x = v[6] - v[0], e2y = v[7] - v[1], e2z = v[8] - v[2];
|
|
998
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
999
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
1000
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
1001
|
+
|
|
1002
|
+
let edges = 0;
|
|
1003
|
+
for (let k = 0; k < 3; k++) {
|
|
1004
|
+
const a = 3 * k, b = 3 * ((k + 1) % 3);
|
|
1005
|
+
const ex = v[b] - v[a], ey = v[b + 1] - v[a + 1], ez = v[b + 2] - v[a + 2];
|
|
1006
|
+
// edge × normal points out of the triangle across the edge
|
|
1007
|
+
const ox_ = ey * nz - ez * ny;
|
|
1008
|
+
const oy_ = ez * nx - ex * nz;
|
|
1009
|
+
const oz_ = ex * ny - ey * nx;
|
|
1010
|
+
if (ldx * ox_ + ldy * oy_ + ldz * oz_ < 0) edges |= 1 << k;
|
|
1011
|
+
}
|
|
1012
|
+
if (edges === 0) return 0;
|
|
1013
|
+
|
|
1014
|
+
// A heightmap's neighbours are its grid's, found without a search.
|
|
1015
|
+
const heightmap = triangle_edge_shape.isHeightMapShape3D === true;
|
|
1016
|
+
if (heightmap) {
|
|
1017
|
+
edges &= heightmap_unshared_edges(triangle_edge_shape);
|
|
1018
|
+
if (edges === 0) return 0;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
if (triangle_edge_shape.isMeshShape3D === true) {
|
|
1022
|
+
const flags = triangle_edge_flags(triangle_edge_shape, triangle_buffer, triangle_offset);
|
|
1023
|
+
for (let k = 0; k < 3; k++) {
|
|
1024
|
+
if ((flags & ((TriangleEdgeFlags.FlatAB | TriangleEdgeFlags.ConcaveAB) << k)) !== 0) edges &= ~(1 << k);
|
|
1025
|
+
}
|
|
1026
|
+
if (edges === 0) return 0;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// straddling the plane?
|
|
1030
|
+
const tr = triangle_tr;
|
|
1031
|
+
v3_quaternion_apply(
|
|
1032
|
+
plane_normal, 0,
|
|
1033
|
+
triangle_plane_local[0], triangle_plane_local[1], triangle_plane_local[2],
|
|
1034
|
+
tr.rotation_x, tr.rotation_y, tr.rotation_z, tr.rotation_w
|
|
1035
|
+
);
|
|
1036
|
+
const wnx = plane_normal[0], wny = plane_normal[1], wnz = plane_normal[2];
|
|
1037
|
+
swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
|
|
1038
|
+
plane_normal_reversed[0] = -wnx;
|
|
1039
|
+
plane_normal_reversed[1] = -wny;
|
|
1040
|
+
plane_normal_reversed[2] = -wnz;
|
|
1041
|
+
swept_posed.support(support_point, 0, plane_normal_reversed, 0);
|
|
1042
|
+
const reach_near = (ox - support_point[0]) * wnx + (oy - support_point[1]) * wny + (oz - support_point[2]) * wnz;
|
|
1043
|
+
if (!(reach_near - triangle_edge_nearest > (skip_initial_overlaps ? PENETRATION_SLOP + CONTACT_EPSILON : CONTACT_EPSILON))) return 0;
|
|
1044
|
+
|
|
1045
|
+
if (heightmap) return edges;
|
|
1046
|
+
|
|
1047
|
+
// The faces across each edge: keep the edges with none, or more than one. A
|
|
1048
|
+
// face that only doubles this one — its back (the same three vertices, or
|
|
1049
|
+
// folded flat back over it across the edge), or a second copy of a face
|
|
1050
|
+
// already counted (the same far vertex) — is no neighbour: a double-sided
|
|
1051
|
+
// quad's rim is still a rim, and its diagonal is still between two faces.
|
|
1052
|
+
//
|
|
1053
|
+
// The candidates for an edge are the triangles with an edge of its hash
|
|
1054
|
+
// ({@link build_edge_index}), walked in buffer order: every triangle with
|
|
1055
|
+
// both of its vertices is among them.
|
|
1056
|
+
if (edge_index_generation !== buffer_generation) build_edge_index();
|
|
1057
|
+
|
|
1058
|
+
const buffer = triangle_buffer;
|
|
1059
|
+
const mask = edge_mask;
|
|
1060
|
+
const hv0 = vertex_hash(v[0], v[1], v[2]);
|
|
1061
|
+
const hv1 = vertex_hash(v[3], v[4], v[5]);
|
|
1062
|
+
const hv2 = vertex_hash(v[6], v[7], v[8]);
|
|
1063
|
+
const self = triangle_offset / TRIANGLE_FLOAT_STRIDE;
|
|
1064
|
+
|
|
1065
|
+
for (let k = 0; k < 3; k++) {
|
|
1066
|
+
if ((edges & (1 << k)) === 0) continue;
|
|
1067
|
+
|
|
1068
|
+
const key = edge_key(k === 0 ? hv0 : k === 1 ? hv1 : hv2, k === 0 ? hv1 : k === 1 ? hv2 : hv0);
|
|
1069
|
+
if (edge_seen_stamp === 0x7FFFFFFF) {
|
|
1070
|
+
edge_seen.fill(0);
|
|
1071
|
+
edge_seen_stamp = 0;
|
|
1072
|
+
}
|
|
1073
|
+
const stamp = ++edge_seen_stamp;
|
|
1074
|
+
let across_k = 0;
|
|
1075
|
+
const c = 3 * k;
|
|
1076
|
+
|
|
1077
|
+
for (let e = edge_heads[key & mask]; e !== -1; e = edge_next[e]) {
|
|
1078
|
+
if (edge_hash[e] !== key) continue;
|
|
1079
|
+
const t = edge_triangle[e];
|
|
1080
|
+
if (t === self || edge_seen[t] === stamp) continue;
|
|
1081
|
+
edge_seen[t] = stamp;
|
|
1082
|
+
|
|
1083
|
+
const o = t * TRIANGLE_FLOAT_STRIDE;
|
|
1084
|
+
|
|
1085
|
+
// which of this triangle's vertices that one has, and its vertex that is none of them
|
|
1086
|
+
let has = 0;
|
|
1087
|
+
let far = -1;
|
|
1088
|
+
for (let j = 0; j < 9; j += 3) {
|
|
1089
|
+
const x = buffer[o + j], y = buffer[o + j + 1], z = buffer[o + j + 2];
|
|
1090
|
+
if (x === v[0] && y === v[1] && z === v[2]) has |= 1;
|
|
1091
|
+
else if (x === v[3] && y === v[4] && z === v[5]) has |= 2;
|
|
1092
|
+
else if (x === v[6] && y === v[7] && z === v[8]) has |= 4;
|
|
1093
|
+
else far = o + j;
|
|
1094
|
+
}
|
|
1095
|
+
// across this edge, and not this very triangle again
|
|
1096
|
+
if ((has === 3 ? 0 : has === 6 ? 1 : has === 5 ? 2 : -1) !== k || far < 0) continue;
|
|
1097
|
+
|
|
1098
|
+
const fx = buffer[far], fy = buffer[far + 1], fz = buffer[far + 2];
|
|
1099
|
+
if (folds_back(k, fx, fy, fz)) continue;
|
|
1100
|
+
|
|
1101
|
+
if (across_k > 0 && across_far[c] === fx && across_far[c + 1] === fy && across_far[c + 2] === fz) continue;
|
|
1102
|
+
if (across_k === 0) {
|
|
1103
|
+
across_far[c] = fx; across_far[c + 1] = fy; across_far[c + 2] = fz;
|
|
1104
|
+
}
|
|
1105
|
+
across_k++;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (across_k === 1) edges &= ~(1 << k);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
return edges;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/** The far vertex of the first face found across each edge of the triangle under test. */
|
|
1115
|
+
const across_far = new Float64Array(9);
|
|
1116
|
+
|
|
1117
|
+
/**
|
|
1118
|
+
* Which edges of a heightmap's triangle under test have no neighbour in {@link triangle_buffer}: bit
|
|
1119
|
+
* `k` for edge `k`, as {@link triangle_edges_to_sweep} numbers them.
|
|
1120
|
+
*
|
|
1121
|
+
* A heightmap's adjacency is its grid's. The enumerator emits sub-cell `(i, j)` as triangle 0 `(A, D,
|
|
1122
|
+
* B)` and triangle 1 `(D, C, B)` (A, B, C, D its corners `(i, j)`, `(i + 1, j)`, `(i + 1, j + 1)`,
|
|
1123
|
+
* `(i, j + 1)`), every shared corner written identically, in feature-id order. So the face across each
|
|
1124
|
+
* edge is known from the triangle's own feature id: across the diagonal, the cell's other triangle;
|
|
1125
|
+
* across a side, the next cell's triangle on that side, or none at the grid's border. And whether the
|
|
1126
|
+
* buffer holds it is a binary search of the feature ids — what a search of the buffer for a triangle
|
|
1127
|
+
* with both of the edge's vertices finds, without the search. No face of a heightmap doubles another
|
|
1128
|
+
* or folds back over it.
|
|
1129
|
+
*
|
|
1130
|
+
* @param {import("../../../core/geom/3d/shape/HeightMapShape3D.js").HeightMapShape3D} shape
|
|
1131
|
+
* @returns {number}
|
|
1132
|
+
*/
|
|
1133
|
+
function heightmap_unshared_edges(shape) {
|
|
1134
|
+
const fid = triangle_buffer[triangle_offset + TRIANGLE_FEATURE_ID_OFFSET] - 1;
|
|
1135
|
+
const sampler = shape.sampler;
|
|
1136
|
+
const seg_u = (sampler.width - 1) * shape.tessellation;
|
|
1137
|
+
const seg_v = (sampler.height - 1) * shape.tessellation;
|
|
1138
|
+
|
|
1139
|
+
const cell = fid >> 1;
|
|
1140
|
+
const i = cell % seg_u;
|
|
1141
|
+
const j = (cell - i) / seg_u;
|
|
1142
|
+
|
|
1143
|
+
let unshared = 0;
|
|
1144
|
+
|
|
1145
|
+
if ((fid & 1) === 0) {
|
|
1146
|
+
// (A, D, B): A→D the side at u = i, D→B the diagonal, B→A the side at v = j
|
|
1147
|
+
if (!(i > 0 && buffer_holds_feature(cell - 1, 1))) unshared |= 1;
|
|
1148
|
+
if (!buffer_holds_feature(cell, 1)) unshared |= 2;
|
|
1149
|
+
if (!(j > 0 && buffer_holds_feature(cell - seg_u, 1))) unshared |= 4;
|
|
1150
|
+
} else {
|
|
1151
|
+
// (D, C, B): D→C the side at v = j + 1, C→B the side at u = i + 1, B→D the diagonal
|
|
1152
|
+
if (!(j < seg_v - 1 && buffer_holds_feature(cell + seg_u, 0))) unshared |= 1;
|
|
1153
|
+
if (!(i < seg_u - 1 && buffer_holds_feature(cell + 1, 0))) unshared |= 2;
|
|
1154
|
+
if (!buffer_holds_feature(cell, 0)) unshared |= 4;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return unshared;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Whether the first {@link triangle_count} triangles of {@link triangle_buffer}, a heightmap's in
|
|
1162
|
+
* feature-id order, include triangle `t` of sub-cell `cell`.
|
|
1163
|
+
*
|
|
1164
|
+
* @param {number} cell
|
|
1165
|
+
* @param {number} t 0 or 1
|
|
1166
|
+
* @returns {boolean}
|
|
1167
|
+
*/
|
|
1168
|
+
function buffer_holds_feature(cell, t) {
|
|
1169
|
+
const fid = cell * 2 + t + 1;
|
|
1170
|
+
let lo = 0, hi = triangle_count - 1;
|
|
1171
|
+
while (lo <= hi) {
|
|
1172
|
+
const mid = (lo + hi) >>> 1;
|
|
1173
|
+
const f = triangle_buffer[mid * TRIANGLE_FLOAT_STRIDE + TRIANGLE_FEATURE_ID_OFFSET];
|
|
1174
|
+
if (f < fid) lo = mid + 1;
|
|
1175
|
+
else if (f > fid) hi = mid - 1;
|
|
1176
|
+
else return true;
|
|
241
1177
|
}
|
|
242
1178
|
return false;
|
|
243
1179
|
}
|
|
244
1180
|
|
|
1181
|
+
/**
|
|
1182
|
+
* The edges of the triangles in {@link triangle_buffer}, hashed by their two vertices, for the
|
|
1183
|
+
* neighbour search in {@link triangle_edges_to_sweep}: a chain of the triangles having an edge of each
|
|
1184
|
+
* hash, in buffer order, so that a search walks only the triangles that may share the edge rather
|
|
1185
|
+
* than every triangle under the sweep — a search per triangle over all of them was quadratic, 10 s of
|
|
1186
|
+
* a 2.4 m slide over a 720,000-triangle heightmap. Built on the first search after the buffer is
|
|
1187
|
+
* refilled ({@link buffer_generation}).
|
|
1188
|
+
*/
|
|
1189
|
+
let edge_heads = new Int32Array(0);
|
|
1190
|
+
/** The buckets of {@link edge_heads} the last build used, less one: a power of two less one. */
|
|
1191
|
+
let edge_mask = 0;
|
|
1192
|
+
let edge_next = new Int32Array(0);
|
|
1193
|
+
let edge_hash = new Int32Array(0);
|
|
1194
|
+
let edge_triangle = new Int32Array(0);
|
|
1195
|
+
/** Per triangle, the search that last walked it, so a chain listing it twice is walked once. */
|
|
1196
|
+
let edge_seen = new Int32Array(0);
|
|
1197
|
+
let edge_seen_stamp = 0;
|
|
1198
|
+
/** The {@link buffer_generation} the index was built for. */
|
|
1199
|
+
let edge_index_generation = -1;
|
|
1200
|
+
/** Bumped by every enumeration into {@link triangle_buffer}. */
|
|
1201
|
+
let buffer_generation = 0;
|
|
1202
|
+
|
|
1203
|
+
const hash_f64 = new Float64Array(1);
|
|
1204
|
+
const hash_u32 = new Uint32Array(hash_f64.buffer);
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* A hash of a vertex that equal coordinates share, as `===` has them equal: `-0` with `0`.
|
|
1208
|
+
*
|
|
1209
|
+
* @param {number} x
|
|
1210
|
+
* @param {number} y
|
|
1211
|
+
* @param {number} z
|
|
1212
|
+
* @returns {number}
|
|
1213
|
+
*/
|
|
1214
|
+
function vertex_hash(x, y, z) {
|
|
1215
|
+
hash_f64[0] = x + 0;
|
|
1216
|
+
let h = Math.imul(hash_u32[0] ^ 0x811c9dc5, 0x01000193) ^ hash_u32[1];
|
|
1217
|
+
hash_f64[0] = y + 0;
|
|
1218
|
+
h = Math.imul(h ^ hash_u32[0], 0x01000193) ^ hash_u32[1];
|
|
1219
|
+
hash_f64[0] = z + 0;
|
|
1220
|
+
h = Math.imul(h ^ hash_u32[0], 0x01000193) ^ hash_u32[1];
|
|
1221
|
+
return lowbias32(h);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Index the first {@link triangle_count} triangles of {@link triangle_buffer} by their edges.
|
|
1226
|
+
*/
|
|
1227
|
+
function build_edge_index() {
|
|
1228
|
+
const count = triangle_count;
|
|
1229
|
+
const entries = count * 3;
|
|
1230
|
+
|
|
1231
|
+
let size = 16;
|
|
1232
|
+
while (size < 2 * entries) size *= 2;
|
|
1233
|
+
if (edge_heads.length < size) edge_heads = new Int32Array(size);
|
|
1234
|
+
if (edge_next.length < entries) {
|
|
1235
|
+
edge_next = new Int32Array(entries);
|
|
1236
|
+
edge_hash = new Int32Array(entries);
|
|
1237
|
+
edge_triangle = new Int32Array(entries);
|
|
1238
|
+
}
|
|
1239
|
+
if (edge_seen.length < count) {
|
|
1240
|
+
edge_seen = new Int32Array(Math.max(count, edge_seen.length * 2));
|
|
1241
|
+
edge_seen_stamp = 0;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
const mask = size - 1;
|
|
1245
|
+
edge_mask = mask;
|
|
1246
|
+
edge_heads.fill(-1, 0, size);
|
|
1247
|
+
|
|
1248
|
+
const buffer = triangle_buffer;
|
|
1249
|
+
let e = 0;
|
|
1250
|
+
// last to first, each pushed onto the front of its chain: the chains run in buffer order
|
|
1251
|
+
for (let t = count - 1; t >= 0; t--) {
|
|
1252
|
+
const o = t * TRIANGLE_FLOAT_STRIDE;
|
|
1253
|
+
const ha = vertex_hash(buffer[o], buffer[o + 1], buffer[o + 2]);
|
|
1254
|
+
const hb = vertex_hash(buffer[o + 3], buffer[o + 4], buffer[o + 5]);
|
|
1255
|
+
const hc = vertex_hash(buffer[o + 6], buffer[o + 7], buffer[o + 8]);
|
|
1256
|
+
|
|
1257
|
+
for (let k = 0; k < 3; k++) {
|
|
1258
|
+
const h = edge_key(k === 0 ? ha : k === 1 ? hb : hc, k === 0 ? hb : k === 1 ? hc : ha);
|
|
1259
|
+
const bucket = h & mask;
|
|
1260
|
+
edge_hash[e] = h;
|
|
1261
|
+
edge_triangle[e] = t;
|
|
1262
|
+
edge_next[e] = edge_heads[bucket];
|
|
1263
|
+
edge_heads[bucket] = e;
|
|
1264
|
+
e++;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
edge_index_generation = buffer_generation;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* The hash of an edge, whichever way round its vertices come.
|
|
1273
|
+
*
|
|
1274
|
+
* @param {number} ha
|
|
1275
|
+
* @param {number} hb
|
|
1276
|
+
* @returns {number}
|
|
1277
|
+
*/
|
|
1278
|
+
function edge_key(ha, hb) {
|
|
1279
|
+
return lowbias32((ha + hb) | 0) | 0;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* Whether a face across edge `k` of the triangle under test, whose vertex off
|
|
1284
|
+
* the edge is `(fx, fy, fz)`, is folded flat back over the triangle: in its
|
|
1285
|
+
* plane, on its side of the edge — a back face, however its quad was split.
|
|
1286
|
+
*
|
|
1287
|
+
* @param {number} k
|
|
1288
|
+
* @param {number} fx
|
|
1289
|
+
* @param {number} fy
|
|
1290
|
+
* @param {number} fz
|
|
1291
|
+
* @returns {boolean}
|
|
1292
|
+
*/
|
|
1293
|
+
function folds_back(k, fx, fy, fz) {
|
|
1294
|
+
const v = triangle_local;
|
|
1295
|
+
const a = 3 * k, b = 3 * ((k + 1) % 3), c = 3 * ((k + 2) % 3);
|
|
1296
|
+
const ex = v[b] - v[a], ey = v[b + 1] - v[a + 1], ez = v[b + 2] - v[a + 2];
|
|
1297
|
+
const cx = v[c] - v[a], cy = v[c + 1] - v[a + 1], cz = v[c + 2] - v[a + 2];
|
|
1298
|
+
const qx = fx - v[a], qy = fy - v[a + 1], qz = fz - v[a + 2];
|
|
1299
|
+
|
|
1300
|
+
// the triangle's normal, and the far vertex's height above its plane
|
|
1301
|
+
const nx = ey * cz - ez * cy, ny = ez * cx - ex * cz, nz = ex * cy - ey * cx;
|
|
1302
|
+
const height = nx * qx + ny * qy + nz * qz;
|
|
1303
|
+
const n_sqr = nx * nx + ny * ny + nz * nz;
|
|
1304
|
+
if (height * height > 1e-12 * n_sqr * (qx * qx + qy * qy + qz * qz)) return false;
|
|
1305
|
+
|
|
1306
|
+
// in the plane: on the triangle's side of the edge?
|
|
1307
|
+
const sx = ey * qz - ez * qy, sy = ez * qx - ex * qz, sz = ex * qy - ey * qx;
|
|
1308
|
+
return nx * sx + ny * sy + nz * sz > 0;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* Sweep against edges `edges` (bits, as {@link triangle_edges_to_sweep}) of the
|
|
1313
|
+
* triangle under test, each one a segment cast as a convex candidate of its
|
|
1314
|
+
* own.
|
|
1315
|
+
*
|
|
1316
|
+
* @param {number} ox
|
|
1317
|
+
* @param {number} oy
|
|
1318
|
+
* @param {number} oz
|
|
1319
|
+
* @param {number} dx
|
|
1320
|
+
* @param {number} dy
|
|
1321
|
+
* @param {number} dz
|
|
1322
|
+
* @param {number} t_limit
|
|
1323
|
+
* @param {number} stop_width
|
|
1324
|
+
* @param {boolean} skip_initial_overlaps
|
|
1325
|
+
* @param {number} edges
|
|
1326
|
+
* @returns {number} the nearest edge's time of impact, or {@link CAST_MISS};
|
|
1327
|
+
* {@link cast_has_normal} / {@link cast_normal} as {@link cast_candidate}
|
|
1328
|
+
*/
|
|
1329
|
+
function cast_triangle_edges(ox, oy, oz, dx, dy, dz, t_limit, stop_width, skip_initial_overlaps, edges) {
|
|
1330
|
+
const tr = triangle_tr;
|
|
1331
|
+
const qx = tr.rotation_x, qy = tr.rotation_y, qz = tr.rotation_z, qw = tr.rotation_w;
|
|
1332
|
+
const v = triangle_local;
|
|
1333
|
+
|
|
1334
|
+
let best = CAST_MISS;
|
|
1335
|
+
let best_contact = t_limit;
|
|
1336
|
+
let best_has_normal = false;
|
|
1337
|
+
/** Under CCD, whether the shape was found clear of the whole triangle at the start. */
|
|
1338
|
+
let clear_at_start = !skip_initial_overlaps;
|
|
1339
|
+
|
|
1340
|
+
for (let k = 0; k < 3; k++) {
|
|
1341
|
+
if ((edges & (1 << k)) === 0) continue;
|
|
1342
|
+
|
|
1343
|
+
const a = 3 * k;
|
|
1344
|
+
const b = 3 * ((k + 1) % 3);
|
|
1345
|
+
const mx = (v[a] + v[b]) * 0.5;
|
|
1346
|
+
const my = (v[a + 1] + v[b + 1]) * 0.5;
|
|
1347
|
+
const mz = (v[a + 2] + v[b + 2]) * 0.5;
|
|
1348
|
+
edge_vertices[0] = v[a] - mx; edge_vertices[1] = v[a + 1] - my; edge_vertices[2] = v[a + 2] - mz;
|
|
1349
|
+
edge_vertices[3] = v[b] - mx; edge_vertices[4] = v[b + 1] - my; edge_vertices[5] = v[b + 2] - mz;
|
|
1350
|
+
edge_vertices[6] = edge_vertices[3]; edge_vertices[7] = edge_vertices[4]; edge_vertices[8] = edge_vertices[5];
|
|
1351
|
+
|
|
1352
|
+
v3_quaternion_apply(anchor_world, 0, mx, my, mz, qx, qy, qz, qw);
|
|
1353
|
+
candidate_posed.setup_components(
|
|
1354
|
+
edge_shape,
|
|
1355
|
+
tr.translation_x + anchor_world[0], tr.translation_y + anchor_world[1], tr.translation_z + anchor_world[2],
|
|
1356
|
+
qx, qy, qz, qw
|
|
1357
|
+
);
|
|
1358
|
+
|
|
1359
|
+
// A segment is convex: cast as one, its normal probes read it, not the triangle.
|
|
1360
|
+
candidate_is_triangle = false;
|
|
1361
|
+
const t = cast_candidate(
|
|
1362
|
+
ox, oy, oz, dx, dy, dz, best_contact, stop_width, skip_initial_overlaps,
|
|
1363
|
+
-Infinity, Infinity
|
|
1364
|
+
);
|
|
1365
|
+
candidate_is_triangle = true;
|
|
1366
|
+
if (t === CAST_MISS || !(cast_touch_t < best_contact)) continue;
|
|
1367
|
+
|
|
1368
|
+
if (!clear_at_start) {
|
|
1369
|
+
// Under CCD a triangle the shape starts in is a resting contact to
|
|
1370
|
+
// step over, edges and all — a ball resting in an open floor by an
|
|
1371
|
+
// obtuse corner reaches past the line of the corner's edge beside
|
|
1372
|
+
// it, and can come onto the edge from outside.
|
|
1373
|
+
anchor_triangle(
|
|
1374
|
+
(v[0] + v[3] + v[6]) / 3, (v[1] + v[4] + v[7]) / 3, (v[2] + v[5] + v[8]) / 3
|
|
1375
|
+
);
|
|
1376
|
+
swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
|
|
1377
|
+
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
1378
|
+
best = CAST_MISS;
|
|
1379
|
+
best_has_normal = false;
|
|
1380
|
+
break;
|
|
1381
|
+
}
|
|
1382
|
+
clear_at_start = true;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
best = t === CAST_BLOCKED ? 0 : t;
|
|
1386
|
+
best_contact = cast_touch_t;
|
|
1387
|
+
best_has_normal = cast_has_normal;
|
|
1388
|
+
if (cast_has_normal) edge_normal.set(cast_normal);
|
|
1389
|
+
if (best === 0) break;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
cast_face = false;
|
|
1393
|
+
cast_has_normal = best_has_normal;
|
|
1394
|
+
if (best_has_normal) cast_normal.set(edge_normal);
|
|
1395
|
+
cast_touch_t = best_contact;
|
|
1396
|
+
return best;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Conservative advancement of `swept_posed` toward `candidate_posed` along the
|
|
1401
|
+
* sweep from `t_start`, after Box3D's `b3ShapeCast` (distance.c, MIT, Erin
|
|
1402
|
+
* Catto): the distance kernel gives a plane separating the two, and nothing can
|
|
1403
|
+
* touch before the sweep closes that plane's gap, so the shape steps across it
|
|
1404
|
+
* in one move, to {@link ADVANCE_TARGET} short of it, and asks again. A flat
|
|
1405
|
+
* approach lands in one step; no feature, however thin or oblique, can be
|
|
1406
|
+
* stepped over, because no step is ever longer than the gap to it.
|
|
1407
|
+
*
|
|
1408
|
+
* Arriving within the target is a TOUCH, not yet a hit — a sphere sliding
|
|
1409
|
+
* along a wall touches it everywhere and never enters it. So a touch is
|
|
1410
|
+
* followed one step further, to where it would be {@link ADVANCE_TARGET} deep
|
|
1411
|
+
* at its present rate of approach: if the shapes overlap there, the sweep
|
|
1412
|
+
* enters the candidate and the touch is the hit. If not, the advancement goes
|
|
1413
|
+
* on from there. It ends as soon as the sweep stops closing: the distance
|
|
1414
|
+
* along a translation is convex, so once it stops falling it never falls
|
|
1415
|
+
* again — a graze is a miss, as it was when only overlap counted.
|
|
1416
|
+
*
|
|
1417
|
+
* Box3D answers an advancement that runs out of iterations with a silent
|
|
1418
|
+
* miss. Here it falls back on the bracket search over what is left of the
|
|
1419
|
+
* window, and says so once per process.
|
|
1420
|
+
*
|
|
1421
|
+
* On a hit, {@link cast_normal} holds the separating direction at the touch.
|
|
1422
|
+
*
|
|
1423
|
+
* @param {number} ox
|
|
1424
|
+
* @param {number} oy
|
|
1425
|
+
* @param {number} oz
|
|
1426
|
+
* @param {number} dx unit sweep direction
|
|
1427
|
+
* @param {number} dy
|
|
1428
|
+
* @param {number} dz
|
|
1429
|
+
* @param {number} t_start nothing touches before this
|
|
1430
|
+
* @param {number} t_end nothing can start touching after this
|
|
1431
|
+
* @param {number} stop_width the bracket search's resolution
|
|
1432
|
+
* @returns {number} the time of impact, or {@link CAST_MISS}
|
|
1433
|
+
*/
|
|
1434
|
+
function advance_to_contact(ox, oy, oz, dx, dy, dz, t_start, t_end, stop_width) {
|
|
1435
|
+
distance_simplex.count = 0;
|
|
1436
|
+
|
|
1437
|
+
let t = t_start;
|
|
1438
|
+
swept_posed.px = ox + dx * t;
|
|
1439
|
+
swept_posed.py = oy + dy * t;
|
|
1440
|
+
swept_posed.pz = oz + dz * t;
|
|
1441
|
+
|
|
1442
|
+
/** A touch being followed: its time, or -1. */
|
|
1443
|
+
let t_touch = -1;
|
|
1444
|
+
/** When the contact behind that touch begins: the touch plus its gap over the closing speed. */
|
|
1445
|
+
let touch_contact = 0;
|
|
1446
|
+
/** The last time the shapes were measured apart. */
|
|
1447
|
+
let t_apart = t_start;
|
|
1448
|
+
|
|
1449
|
+
for (let iteration = 0; iteration < ADVANCE_MAX_ITERATIONS; iteration++) {
|
|
1450
|
+
let distance = gjk_distance(distance_result, distance_simplex, candidate_posed, swept_posed, ADVANCE_DISTANCE_TOLERANCE);
|
|
1451
|
+
if (distance > 0 && distance_result[9] <= ADVANCE_TARGET + ADVANCE_TOLERANCE
|
|
1452
|
+
&& distance - distance_result[9] > GJK_DISTANCE_RELATIVE_GAP * distance) {
|
|
1453
|
+
// A touch, or nearly, that the tolerance stopped short of exact:
|
|
1454
|
+
// its gap and normal are what is judged and reported, so the search
|
|
1455
|
+
// goes on from where it stopped to the kernel's own precision. (A
|
|
1456
|
+
// polytope pair ends exact on a repeated support either way.)
|
|
1457
|
+
distance = gjk_distance(distance_result, distance_simplex, candidate_posed, swept_posed, 0);
|
|
1458
|
+
}
|
|
1459
|
+
if (distance > 0 && !(distance_result[9] > 0)) {
|
|
1460
|
+
// The search ran out of iterations before any plane separated the
|
|
1461
|
+
// two, so `distance` is only how close it came. Ask again from
|
|
1462
|
+
// nothing: a simplex carried across steps can stall where a fresh
|
|
1463
|
+
// one does not (a 1,000 m sphere 1e-5 from a small one, 106 times
|
|
1464
|
+
// in 400 carried, 10 fresh).
|
|
1465
|
+
distance_simplex.count = 0;
|
|
1466
|
+
distance = gjk_distance(distance_result, distance_simplex, candidate_posed, swept_posed, 0);
|
|
1467
|
+
if (distance > 0 && !(distance_result[9] > 0)) {
|
|
1468
|
+
// Still nothing to step by, and no reason to call it a touch:
|
|
1469
|
+
// the bracket search settles it from the last pose known apart.
|
|
1470
|
+
return bracket_search(ox, oy, oz, dx, dy, dz, t_apart, t_end, stop_width);
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// In contact: the search ended on its own terms with no plane between
|
|
1475
|
+
// the two.
|
|
1476
|
+
if (distance === 0) {
|
|
1477
|
+
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
1478
|
+
// Overlap. Behind a touch, that is the hit: the shapes were
|
|
1479
|
+
// apart at the touch and are in contact one step on.
|
|
1480
|
+
if (t_touch >= 0) {
|
|
1481
|
+
cast_has_normal = true;
|
|
1482
|
+
cast_touch_t = touch_contact;
|
|
1483
|
+
return t_touch;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// Anywhere else the step that led here was supposed to be
|
|
1487
|
+
// safe, and only numerics put it inside. The bracket search
|
|
1488
|
+
// settles it from the last pose known apart.
|
|
1489
|
+
return bracket_search(ox, oy, oz, dx, dy, dz, t_apart, t_end, stop_width);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// Exactly touching — a shape flush with a face it slides along, or
|
|
1493
|
+
// a step that landed on the contact to the last bit. The distance
|
|
1494
|
+
// has no normal to give, so it is read by penetration, as a touch
|
|
1495
|
+
// at the start of the sweep is, and the rule is the same: only a
|
|
1496
|
+
// sweep driving into the touch enters it (see `cast_candidate`).
|
|
1497
|
+
const px = swept_posed.px, py = swept_posed.py, pz = swept_posed.pz;
|
|
1498
|
+
if (!recover_contact_normal(probe_normal, px, py, pz, dx, dy, dz)) {
|
|
1499
|
+
// No normal to judge by: stopping short is the safe failure.
|
|
1500
|
+
cast_touch_t = t_touch >= 0 ? touch_contact : t;
|
|
1501
|
+
return t_touch >= 0 ? t_touch : t;
|
|
1502
|
+
}
|
|
1503
|
+
if (dx * probe_normal[0] + dy * probe_normal[1] + dz * probe_normal[2] > -GRAZING_SINE_EPSILON) {
|
|
1504
|
+
return CAST_MISS;
|
|
1505
|
+
}
|
|
1506
|
+
if (t_touch < 0) {
|
|
1507
|
+
cast_normal[0] = probe_normal[0]; cast_normal[1] = probe_normal[1]; cast_normal[2] = probe_normal[2];
|
|
1508
|
+
}
|
|
1509
|
+
cast_has_normal = true;
|
|
1510
|
+
cast_touch_t = t_touch >= 0 ? touch_contact : t;
|
|
1511
|
+
return t_touch >= 0 ? t_touch : t;
|
|
1512
|
+
}
|
|
1513
|
+
t_apart = t;
|
|
1514
|
+
|
|
1515
|
+
const nx = distance_result[6], ny = distance_result[7], nz = distance_result[8];
|
|
1516
|
+
const gap = distance_result[9];
|
|
1517
|
+
|
|
1518
|
+
// Closing speed along the separating normal, per unit of sweep.
|
|
1519
|
+
const closing = -(dx * nx + dy * ny + dz * nz);
|
|
1520
|
+
if (!(closing > 0)) return CAST_MISS;
|
|
1521
|
+
|
|
1522
|
+
let t_next;
|
|
1523
|
+
if (gap <= ADVANCE_TARGET + ADVANCE_TOLERANCE) {
|
|
1524
|
+
t_touch = t;
|
|
1525
|
+
touch_contact = t + gap / closing;
|
|
1526
|
+
cast_normal[0] = nx; cast_normal[1] = ny; cast_normal[2] = nz;
|
|
1527
|
+
t_next = t + (gap + ADVANCE_TARGET) / closing;
|
|
1528
|
+
// Only a contact strictly before `t_end` counts, so that is as far
|
|
1529
|
+
// as it needs to be followed.
|
|
1530
|
+
if (t_next > t_end) t_next = t_end;
|
|
1531
|
+
if (!(t_next > t)) return CAST_MISS;
|
|
1532
|
+
} else {
|
|
1533
|
+
t_touch = -1;
|
|
1534
|
+
t_next = t + (gap - ADVANCE_TARGET) / closing;
|
|
1535
|
+
if (!(t_next < t_end)) return CAST_MISS;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
const step = t_next - t;
|
|
1539
|
+
swept_posed.px = ox + dx * t_next;
|
|
1540
|
+
swept_posed.py = oy + dy * t_next;
|
|
1541
|
+
swept_posed.pz = oz + dz * t_next;
|
|
1542
|
+
gjk_simplex_translate_b(distance_simplex, dx * step, dy * step, dz * step);
|
|
1543
|
+
t = t_next;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if (!advance_exhaustion_reported) {
|
|
1547
|
+
advance_exhaustion_reported = true;
|
|
1548
|
+
console.warn(
|
|
1549
|
+
`shape_cast: conservative advancement did not converge in ${ADVANCE_MAX_ITERATIONS} steps`
|
|
1550
|
+
+ ` (at t = ${t} of a window ending at ${t_end}); falling back on the bracket search.`
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
return bracket_search(ox, oy, oz, dx, dy, dz, t_apart, t_end, stop_width);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* The time of impact by sampling: a coarse scan of `[t_start, t_end]` for an
|
|
1558
|
+
* overlapping moment, then bisection down to `stop_width`. What every sweep
|
|
1559
|
+
* used before {@link advance_to_contact}, and what it falls back on; a feature
|
|
1560
|
+
* thinner than a sample's spacing is stepped over (see {@link COARSE_STEPS}).
|
|
1561
|
+
*
|
|
1562
|
+
* @param {number} ox
|
|
1563
|
+
* @param {number} oy
|
|
1564
|
+
* @param {number} oz
|
|
1565
|
+
* @param {number} dx
|
|
1566
|
+
* @param {number} dy
|
|
1567
|
+
* @param {number} dz
|
|
1568
|
+
* @param {number} t_start not overlapping here
|
|
1569
|
+
* @param {number} t_end
|
|
1570
|
+
* @param {number} stop_width
|
|
1571
|
+
* @returns {number} the just-SEPARATING side of the bisection, or {@link CAST_MISS}
|
|
1572
|
+
*/
|
|
1573
|
+
function bracket_search(ox, oy, oz, dx, dy, dz, t_start, t_end, stop_width) {
|
|
1574
|
+
cast_has_normal = false;
|
|
1575
|
+
|
|
1576
|
+
if (!(t_start < t_end)) return CAST_MISS;
|
|
1577
|
+
|
|
1578
|
+
// Coarse-search within the narrowed interval to find any t for
|
|
1579
|
+
// which the shapes overlap (their AABBs do by construction; the
|
|
1580
|
+
// shapes themselves may not, e.g. two spheres passing alongside).
|
|
1581
|
+
const step_dt = (t_end - t_start) / COARSE_STEPS;
|
|
1582
|
+
let t_prev = t_start;
|
|
1583
|
+
let t_hi = -1;
|
|
1584
|
+
for (let s = 1; s <= COARSE_STEPS; s++) {
|
|
1585
|
+
const t = t_start + s * step_dt;
|
|
1586
|
+
swept_posed.px = ox + dx * t;
|
|
1587
|
+
swept_posed.py = oy + dy * t;
|
|
1588
|
+
swept_posed.pz = oz + dz * t;
|
|
1589
|
+
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
1590
|
+
t_hi = t;
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
t_prev = t;
|
|
1594
|
+
}
|
|
1595
|
+
if (t_hi < 0) return CAST_MISS;
|
|
1596
|
+
|
|
1597
|
+
// Bisect [t_prev, t_hi]: invariant is `gjk(t_lo) === false` and
|
|
1598
|
+
// `gjk(t_hi) === true`.
|
|
1599
|
+
let t_lo = t_prev;
|
|
1600
|
+
for (let bi = 0; bi < MAX_BISECTION && (t_hi - t_lo) > stop_width; bi++) {
|
|
1601
|
+
const t_mid = (t_lo + t_hi) * 0.5;
|
|
1602
|
+
swept_posed.px = ox + dx * t_mid;
|
|
1603
|
+
swept_posed.py = oy + dy * t_mid;
|
|
1604
|
+
swept_posed.pz = oz + dz * t_mid;
|
|
1605
|
+
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
1606
|
+
t_hi = t_mid;
|
|
1607
|
+
} else {
|
|
1608
|
+
t_lo = t_mid;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// Use t_lo (the just-SEPARATING side of the bisection) rather
|
|
1613
|
+
// than t_hi (just-overlapping). With the fixed GJK that no
|
|
1614
|
+
// longer flags 5 mm-clear gaps as overlap, the bisection is
|
|
1615
|
+
// tight; reporting t_lo gives kinematic callers a conservative
|
|
1616
|
+
// TOI — the swept shape at the reported moment is provably NOT
|
|
1617
|
+
// overlapping the target. The normal-probe in `shape_cast` steps a
|
|
1618
|
+
// few mm past it to get a valid simplex for MPR.
|
|
1619
|
+
cast_touch_t = t_lo;
|
|
1620
|
+
return t_lo;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* The world box the swept shape covers over `[t0, t1]` of the sweep along unit
|
|
1625
|
+
* `(dx, dy, dz)`, from the shape's box at the origin, {@link initial_aabb};
|
|
1626
|
+
* written into {@link piece_aabb}.
|
|
1627
|
+
*
|
|
1628
|
+
* @param {number} dx
|
|
1629
|
+
* @param {number} dy
|
|
1630
|
+
* @param {number} dz
|
|
1631
|
+
* @param {number} t0
|
|
1632
|
+
* @param {number} t1
|
|
1633
|
+
* @returns {Float64Array} {@link piece_aabb}
|
|
1634
|
+
*/
|
|
1635
|
+
function sweep_piece_aabb(dx, dy, dz, t0, t1) {
|
|
1636
|
+
const sx0 = dx * t0, sx1 = dx * t1;
|
|
1637
|
+
const sy0 = dy * t0, sy1 = dy * t1;
|
|
1638
|
+
const sz0 = dz * t0, sz1 = dz * t1;
|
|
1639
|
+
piece_aabb[0] = initial_aabb[0] + (sx0 < sx1 ? sx0 : sx1);
|
|
1640
|
+
piece_aabb[1] = initial_aabb[1] + (sy0 < sy1 ? sy0 : sy1);
|
|
1641
|
+
piece_aabb[2] = initial_aabb[2] + (sz0 < sz1 ? sz0 : sz1);
|
|
1642
|
+
piece_aabb[3] = initial_aabb[3] + (sx0 > sx1 ? sx0 : sx1);
|
|
1643
|
+
piece_aabb[4] = initial_aabb[4] + (sy0 > sy1 ? sy0 : sy1);
|
|
1644
|
+
piece_aabb[5] = initial_aabb[5] + (sz0 > sz1 ? sz0 : sz1);
|
|
1645
|
+
return piece_aabb;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* Enumerate the triangles of concave `shape`, posed at `target_tr`, that may
|
|
1650
|
+
* overlap the world AABB `world_aabb` into {@link triangle_buffer}, in the
|
|
1651
|
+
* shape's own frame — the same decomposition the narrowphase and
|
|
1652
|
+
* `overlap_shape` use.
|
|
1653
|
+
*
|
|
1654
|
+
* The enumerator returns the TRUE count and drops what does not fit; a
|
|
1655
|
+
* dropped triangle is a hole the sweep would pass straight through, so the
|
|
1656
|
+
* buffer grows and the enumeration re-runs (deterministic → one resize) — up to
|
|
1657
|
+
* {@link MAX_TRIANGLES_PER_PAIR}, and no further. Past that, the count returned
|
|
1658
|
+
* is still the true one and only the first that many are in the buffer: the
|
|
1659
|
+
* caller walks the sweep in shorter pieces (see `shape_cast`).
|
|
1660
|
+
*
|
|
1661
|
+
* @param {AbstractShape3D} shape
|
|
1662
|
+
* @param {Transform64} target_tr
|
|
1663
|
+
* @param {Float64Array} world_aabb
|
|
1664
|
+
* @returns {number} the triangles overlapping the box, which may be more than
|
|
1665
|
+
* {@link MAX_TRIANGLES_PER_PAIR}
|
|
1666
|
+
*/
|
|
1667
|
+
function enumerate_triangles(shape, target_tr, world_aabb) {
|
|
1668
|
+
aabb3_transform_oriented_inverse(
|
|
1669
|
+
concave_query_aabb, 0,
|
|
1670
|
+
world_aabb,
|
|
1671
|
+
target_tr.translation_x, target_tr.translation_y, target_tr.translation_z,
|
|
1672
|
+
target_tr.rotation_x, target_tr.rotation_y, target_tr.rotation_z, target_tr.rotation_w
|
|
1673
|
+
);
|
|
1674
|
+
|
|
1675
|
+
buffer_generation++;
|
|
1676
|
+
|
|
1677
|
+
for (;;) {
|
|
1678
|
+
const count = decompose_to_triangles(
|
|
1679
|
+
triangle_buffer, 0, shape,
|
|
1680
|
+
concave_query_aabb[0], concave_query_aabb[1], concave_query_aabb[2],
|
|
1681
|
+
concave_query_aabb[3], concave_query_aabb[4], concave_query_aabb[5]
|
|
1682
|
+
);
|
|
1683
|
+
const capacity = triangle_buffer.length / TRIANGLE_FLOAT_STRIDE;
|
|
1684
|
+
if (count <= capacity || capacity >= MAX_TRIANGLES_PER_PAIR) return count;
|
|
1685
|
+
triangle_buffer = new Float64Array(
|
|
1686
|
+
Math.min(MAX_TRIANGLES_PER_PAIR, Math.max(count, capacity * 2)) * TRIANGLE_FLOAT_STRIDE
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* The count {@link enumerate_triangles} would return for the same box, for
|
|
1693
|
+
* sizing a piece of the walk. A heightmap's is counted in O(1)
|
|
1694
|
+
* ({@link heightmap_box_triangles}) and nothing is enumerated — the caller
|
|
1695
|
+
* enumerates the piece it settles on; a mesh's is enumerated, as its count can
|
|
1696
|
+
* only be had that way.
|
|
1697
|
+
*
|
|
1698
|
+
* @param {AbstractShape3D} shape
|
|
1699
|
+
* @param {Transform64} target_tr
|
|
1700
|
+
* @param {Float64Array} world_aabb
|
|
1701
|
+
* @returns {number}
|
|
1702
|
+
*/
|
|
1703
|
+
function count_triangles(shape, target_tr, world_aabb) {
|
|
1704
|
+
if (shape.isHeightMapShape3D !== true) {
|
|
1705
|
+
return enumerate_triangles(shape, target_tr, world_aabb);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
aabb3_transform_oriented_inverse(
|
|
1709
|
+
concave_query_aabb, 0,
|
|
1710
|
+
world_aabb,
|
|
1711
|
+
target_tr.translation_x, target_tr.translation_y, target_tr.translation_z,
|
|
1712
|
+
target_tr.rotation_x, target_tr.rotation_y, target_tr.rotation_z, target_tr.rotation_w
|
|
1713
|
+
);
|
|
1714
|
+
|
|
1715
|
+
return heightmap_box_triangles(
|
|
1716
|
+
shape,
|
|
1717
|
+
concave_query_aabb[0], concave_query_aabb[1], concave_query_aabb[2],
|
|
1718
|
+
concave_query_aabb[3], concave_query_aabb[4], concave_query_aabb[5]
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/**
|
|
1723
|
+
* Make the triangle at `offset` of `buffer` (in the frame of a collider posed
|
|
1724
|
+
* at `target_tr`) the one under test, posed as `candidate_posed` anchored at
|
|
1725
|
+
* its centroid.
|
|
1726
|
+
*
|
|
1727
|
+
* @param {Float64Array} buffer
|
|
1728
|
+
* @param {number} offset
|
|
1729
|
+
* @param {Transform64} target_tr
|
|
1730
|
+
*/
|
|
1731
|
+
function set_triangle(buffer, offset, target_tr) {
|
|
1732
|
+
for (let i = 0; i < 9; i++) triangle_local[i] = buffer[offset + i];
|
|
1733
|
+
triangle_tr = target_tr;
|
|
1734
|
+
candidate_is_triangle = true;
|
|
1735
|
+
|
|
1736
|
+
anchor_triangle(
|
|
1737
|
+
(triangle_local[0] + triangle_local[3] + triangle_local[6]) / 3,
|
|
1738
|
+
(triangle_local[1] + triangle_local[4] + triangle_local[7]) / 3,
|
|
1739
|
+
(triangle_local[2] + triangle_local[5] + triangle_local[8]) / 3
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Make the triangle at `offset` of `buffer` — vertices in the frame of a
|
|
1745
|
+
* concave collider posed at `target_tr` — the candidate under test, posed as
|
|
1746
|
+
* `candidate_posed` anchored at its centroid (see {@link triangle_vertices}),
|
|
1747
|
+
* and write the part of the sweep that can touch it into
|
|
1748
|
+
* {@link triangle_window_enter} / {@link triangle_window_exit}.
|
|
1749
|
+
*
|
|
1750
|
+
* A triangle is flat, and that is what the window is read from: the sweep can
|
|
1751
|
+
* touch the triangle only while the swept shape straddles its PLANE, an
|
|
1752
|
+
* interval known in closed form from the shape's reach along the normal. It
|
|
1753
|
+
* matters more than the saving. The coarse search samples 32 points across
|
|
1754
|
+
* whatever interval it is given, and the AABB slab interval of a large
|
|
1755
|
+
* oblique triangle is metres long while the shape crosses its plane in
|
|
1756
|
+
* centimetres — measured on a 40 m ramp at 30° pitch, 225 of 300 casts of a
|
|
1757
|
+
* 5 cm sphere stepped clean over it (as they do over a 1 mm box at the same
|
|
1758
|
+
* pose; a triangle is simply always that thin).
|
|
1759
|
+
*
|
|
1760
|
+
* A sweep that does not CLOSE on the plane gets an empty window: it is tested
|
|
1761
|
+
* for overlap at the start, and the face is never swept. Running parallel to
|
|
1762
|
+
* the plane, or leaving it, the shape cannot enter the face; at most it meets
|
|
1763
|
+
* the triangle's boundary, and only if it already reaches across the plane.
|
|
1764
|
+
* Most of that boundary is no boundary of the surface: a coplanar neighbour
|
|
1765
|
+
* (the next triangle of a floor) is the very surface the shape is sliding on,
|
|
1766
|
+
* and reporting the touch at its seam stops a sliding shape at every seam it
|
|
1767
|
+
* crosses and hands a kinematic caller a contact it rightly judges harmless
|
|
1768
|
+
* while the scan behind it is cut short. So only the edges a sweep can meet
|
|
1769
|
+
* edge-on are swept ({@link triangle_edges_to_sweep}): the surface's own
|
|
1770
|
+
* boundary. Skipping all of them, a quad approached exactly edge-on, or 1e-5
|
|
1771
|
+
* off it, was invisible to every cast.
|
|
1772
|
+
*
|
|
1773
|
+
* What "closing" means follows `skip_initial_overlaps`. Kinematic semantics
|
|
1774
|
+
* are exact: any approach beyond {@link GRAZING_SINE_EPSILON}. Under CCD
|
|
1775
|
+
* semantics the body is usually RESTING in the surface it slides on, already
|
|
1776
|
+
* {@link PENETRATION_SLOP} deep, and its net motion over a step drifts into
|
|
1777
|
+
* the plane by solver noise; a sweep that closes on a plane by no more than
|
|
1778
|
+
* that slop over its whole length, its centre staying on the side it started,
|
|
1779
|
+
* cannot carry the body through anything, and the discrete solver owns that
|
|
1780
|
+
* depth. Measured without it: a CCD sphere sliding at 5 m/s across a flat
|
|
1781
|
+
* heightmap was stopped at a seam often enough to lose 4.2 m of travel in one
|
|
1782
|
+
* second.
|
|
1783
|
+
*
|
|
1784
|
+
* @param {AbstractShape3D} shape the concave shape `buffer` was enumerated from
|
|
1785
|
+
* @param {Float64Array} buffer
|
|
1786
|
+
* @param {number} offset float-index of the triangle in `buffer`
|
|
1787
|
+
* @param {Transform64} target_tr
|
|
1788
|
+
* @param {number} lx sweep origin in the target's frame
|
|
1789
|
+
* @param {number} ly
|
|
1790
|
+
* @param {number} lz
|
|
1791
|
+
* @param {number} ldx unit sweep direction in the target's frame
|
|
1792
|
+
* @param {number} ldy
|
|
1793
|
+
* @param {number} ldz
|
|
1794
|
+
* @param {number} ox sweep origin in world space
|
|
1795
|
+
* @param {number} oy
|
|
1796
|
+
* @param {number} oz
|
|
1797
|
+
* @param {number} tMax sweep length
|
|
1798
|
+
* @param {boolean} skip_initial_overlaps see {@link shape_cast}
|
|
1799
|
+
*/
|
|
1800
|
+
function load_triangle(
|
|
1801
|
+
shape, buffer, offset, target_tr,
|
|
1802
|
+
lx, ly, lz, ldx, ldy, ldz,
|
|
1803
|
+
ox, oy, oz, tMax, skip_initial_overlaps
|
|
1804
|
+
) {
|
|
1805
|
+
set_triangle(buffer, offset, target_tr);
|
|
1806
|
+
|
|
1807
|
+
const ax = triangle_local[0], ay = triangle_local[1], az = triangle_local[2];
|
|
1808
|
+
const bx = triangle_local[3], by = triangle_local[4], bz = triangle_local[5];
|
|
1809
|
+
const cx = triangle_local[6], cy = triangle_local[7], cz = triangle_local[8];
|
|
1810
|
+
const mx = (ax + bx + cx) / 3;
|
|
1811
|
+
const my = (ay + by + cy) / 3;
|
|
1812
|
+
const mz = (az + bz + cz) / 3;
|
|
1813
|
+
|
|
1814
|
+
// Empty until shown otherwise: tested at the start only.
|
|
1815
|
+
triangle_window_enter = Infinity;
|
|
1816
|
+
triangle_window_exit = -Infinity;
|
|
1817
|
+
triangle_start_depth = Infinity;
|
|
1818
|
+
triangle_centre_crossing = Infinity;
|
|
1819
|
+
triangle_edges_pending = false;
|
|
1820
|
+
|
|
1821
|
+
const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
|
|
1822
|
+
const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
|
|
1823
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
1824
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
1825
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
1826
|
+
const n_len = Math.sqrt(nx * nx + ny * ny + nz * nz);
|
|
1827
|
+
// A degenerate (zero-area) triangle has no plane to enter and no
|
|
1828
|
+
// surface of its own; its neighbours carry the geometry.
|
|
1829
|
+
if (!(n_len > 0)) return;
|
|
1830
|
+
const n_inv = 1 / n_len;
|
|
1831
|
+
|
|
1832
|
+
// Orient the unit normal toward the side the sweep starts on; a start IN
|
|
1833
|
+
// the plane has no side, so the normal faces the sweep.
|
|
1834
|
+
const side = ((lx - mx) * nx + (ly - my) * ny + (lz - mz) * nz) * n_inv;
|
|
1835
|
+
const rate = (ldx * nx + ldy * ny + ldz * nz) * n_inv;
|
|
1836
|
+
const sign = side > 0 ? 1 : (side < 0 ? -1 : (rate > 0 ? -1 : 1));
|
|
1837
|
+
const closing = -rate * sign;
|
|
1838
|
+
const distance = side * sign;
|
|
1839
|
+
|
|
1840
|
+
// The CCD slop: a sweep closing on the plane by no more than the solver's
|
|
1841
|
+
// penetration slop is the solver's — unless its centre ends on the far
|
|
1842
|
+
// side, which a body thinner than the slop does while staying inside it.
|
|
1843
|
+
// The discrete solver pushes such a body on through: a 2 mm plate or a
|
|
1844
|
+
// 4 mm sphere approaching a mesh floor at under 5 mm a step passed it in
|
|
1845
|
+
// 23 and 15 of 30 cases.
|
|
1846
|
+
const sweeps_plane = closing > GRAZING_SINE_EPSILON
|
|
1847
|
+
&& !(skip_initial_overlaps && !(closing * tMax > PENETRATION_SLOP) && distance - closing * tMax > 0);
|
|
1848
|
+
|
|
1849
|
+
const s = sign * n_inv;
|
|
1850
|
+
|
|
1851
|
+
if (!sweeps_plane) {
|
|
1852
|
+
// Not closing on the plane: only the edges are left to meet, and only
|
|
1853
|
+
// by a shape already reaching across the plane. Which of them, and
|
|
1854
|
+
// whether it does, is worked out only when asked
|
|
1855
|
+
// ({@link triangle_edges_to_sweep}).
|
|
1856
|
+
triangle_edges_pending = true;
|
|
1857
|
+
triangle_edge_shape = shape;
|
|
1858
|
+
triangle_edge_nearest = distance - (closing > 0 ? closing * tMax : 0);
|
|
1859
|
+
triangle_plane_local[0] = nx * s;
|
|
1860
|
+
triangle_plane_local[1] = ny * s;
|
|
1861
|
+
triangle_plane_local[2] = nz * s;
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
// The swept shape's reach toward the plane and away from it, from its
|
|
1866
|
+
// supports along the (world) normal at the sweep origin.
|
|
1867
|
+
v3_quaternion_apply(
|
|
1868
|
+
plane_normal, 0,
|
|
1869
|
+
nx * s, ny * s, nz * s,
|
|
1870
|
+
target_tr.rotation_x, target_tr.rotation_y, target_tr.rotation_z, target_tr.rotation_w
|
|
1871
|
+
);
|
|
1872
|
+
const wnx = plane_normal[0], wny = plane_normal[1], wnz = plane_normal[2];
|
|
1873
|
+
|
|
1874
|
+
swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
|
|
1875
|
+
plane_normal_reversed[0] = -wnx;
|
|
1876
|
+
plane_normal_reversed[1] = -wny;
|
|
1877
|
+
plane_normal_reversed[2] = -wnz;
|
|
1878
|
+
swept_posed.support(support_point, 0, plane_normal_reversed, 0);
|
|
1879
|
+
const reach_near = (ox - support_point[0]) * wnx + (oy - support_point[1]) * wny + (oz - support_point[2]) * wnz;
|
|
1880
|
+
// the point that reaches the plane first, as the sweep starts
|
|
1881
|
+
triangle_touch_origin[0] = support_point[0];
|
|
1882
|
+
triangle_touch_origin[1] = support_point[1];
|
|
1883
|
+
triangle_touch_origin[2] = support_point[2];
|
|
1884
|
+
swept_posed.support(support_point, 0, plane_normal, 0);
|
|
1885
|
+
const reach_far = (support_point[0] - ox) * wnx + (support_point[1] - oy) * wny + (support_point[2] - oz) * wnz;
|
|
1886
|
+
|
|
1887
|
+
triangle_window_enter = (distance - reach_near) / closing;
|
|
1888
|
+
triangle_window_exit = (distance + reach_far) / closing;
|
|
1889
|
+
triangle_start_depth = reach_near - distance;
|
|
1890
|
+
|
|
1891
|
+
// Where the centre reaches the plane, and whether that is within the
|
|
1892
|
+
// triangle's edges (each edge's cross product agrees with the normal).
|
|
1893
|
+
if (distance >= 0) {
|
|
1894
|
+
const t_cross = distance / closing;
|
|
1895
|
+
const px = lx + ldx * t_cross, py = ly + ldy * t_cross, pz = lz + ldz * t_cross;
|
|
1896
|
+
if (edge_holds(ax, ay, az, bx, by, bz, px, py, pz, nx, ny, nz)
|
|
1897
|
+
&& edge_holds(bx, by, bz, cx, cy, cz, px, py, pz, nx, ny, nz)
|
|
1898
|
+
&& edge_holds(cx, cy, cz, ax, ay, az, px, py, pz, nx, ny, nz)) {
|
|
1899
|
+
triangle_centre_crossing = t_cross;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* Whether point `p`, in a triangle's plane, lies on the inner side of (or on)
|
|
1906
|
+
* the triangle's edge from `a` to `b`, the triangle's normal being `n` (from
|
|
1907
|
+
* its winding, either way up).
|
|
1908
|
+
*/
|
|
1909
|
+
function edge_holds(ax, ay, az, bx, by, bz, px, py, pz, nx, ny, nz) {
|
|
1910
|
+
const ex = bx - ax, ey = by - ay, ez = bz - az;
|
|
1911
|
+
const qx = px - ax, qy = py - ay, qz = pz - az;
|
|
1912
|
+
return nx * (ey * qz - ez * qy) + ny * (ez * qx - ex * qz) + nz * (ex * qy - ey * qx) >= 0;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
245
1915
|
/**
|
|
246
1916
|
* Sweep a convex shape along a ray and find the first body it would
|
|
247
1917
|
* hit. Used by character controllers (sweep a capsule along intended
|
|
@@ -255,35 +1925,46 @@ function recover_contact_normal(out, cx, cy, cz, dx, dy, dz, target_tr) {
|
|
|
255
1925
|
* stretched along `ray.direction * ray.tMax`.
|
|
256
1926
|
* 2. Query both broadphase BVHs (static + dynamic) for leaves whose
|
|
257
1927
|
* AABB overlaps the swept volume.
|
|
258
|
-
* 3. For each candidate,
|
|
259
|
-
*
|
|
260
|
-
*
|
|
1928
|
+
* 3. For each candidate, advance the swept shape toward the candidate's
|
|
1929
|
+
* collider by conservative advancement on the GJK distance (see
|
|
1930
|
+
* `advance_to_contact`) for the smallest `t` at which it touches and
|
|
1931
|
+
* goes on into it, within [0, best_t). A concave collider (mesh,
|
|
1932
|
+
* heightmap) is a surface, not the solid its hull encloses: it is
|
|
1933
|
+
* swept as the set of its triangles under the swept AABB, each one a
|
|
1934
|
+
* convex candidate under the same rules.
|
|
261
1935
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* being checked at its full [0, tMax] interval.
|
|
1936
|
+
* Searching only [0, best_t) (rather than always the full [0, tMax]) is the
|
|
1937
|
+
* early-termination optimisation: once we have a hit at some t, no later
|
|
1938
|
+
* candidate can produce a smaller TOI by being checked over the rest.
|
|
266
1939
|
*
|
|
267
1940
|
* Output on hit:
|
|
268
1941
|
* - `result.t` — sweep distance to impact (in the same units as
|
|
269
1942
|
* `ray.direction`'s magnitude; for a unit-direction ray, this is
|
|
270
|
-
* metres).
|
|
1943
|
+
* metres). The swept shape there is still apart from what it struck
|
|
1944
|
+
* — by about {@link ADVANCE_TARGET}, or within the bracket search's
|
|
1945
|
+
* resolution when that found it — so a caller can place a body there.
|
|
271
1946
|
* - `result.position` — `ray.origin + t * ray.direction`, i.e. the
|
|
272
1947
|
* centre of the swept shape at the moment of first contact. NOT
|
|
273
|
-
* a point on the target's surface
|
|
274
|
-
* refinement which the broadphase-only architecture doesn't have
|
|
275
|
-
* wired up yet.
|
|
1948
|
+
* a point on the target's surface.
|
|
276
1949
|
* - `result.normal` — target surface's outward normal at the kiss
|
|
277
|
-
* point (unit length)
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* toward the target's centre
|
|
281
|
-
* the last-resort fallback if
|
|
282
|
-
* contact-normal
|
|
1950
|
+
* point (unit length): the separating direction advancement stopped
|
|
1951
|
+
* on, or a triangle face's own normal. A cast blocked where it starts
|
|
1952
|
+
* reads it off by MPR, and a pair exactly tangent there carries no MTV
|
|
1953
|
+
* to read, so a second probe nudged toward the target's centre
|
|
1954
|
+
* supplies one; `-ray.direction` remains the last-resort fallback if
|
|
1955
|
+
* both degenerate. See the contact-normal block near the end of the
|
|
1956
|
+
* function.
|
|
283
1957
|
* - `result.entity` / `result.body_id` — the hit body.
|
|
1958
|
+
* - `result.collider_entity` — the entity owning the struck collider (a
|
|
1959
|
+
* compound body's child's own); `result.triangle` — the struck triangle of
|
|
1960
|
+
* a mesh or heightmap collider, `-1` for any other.
|
|
284
1961
|
*
|
|
285
1962
|
* Output on miss: untouched; same convention as `raycast`.
|
|
286
1963
|
*
|
|
1964
|
+
* The filter may run a raycast or an overlap of its own, but not another cast:
|
|
1965
|
+
* a cast keeps its working state in module scratch, and one started from its
|
|
1966
|
+
* filter is refused by an assert.
|
|
1967
|
+
*
|
|
287
1968
|
* @param {PhysicsSystem} system
|
|
288
1969
|
* @param {Ray3|{origin_x:number,origin_y:number,origin_z:number,direction_x:number,direction_y:number,direction_z:number,tMax:number}} ray
|
|
289
1970
|
* origin + unit direction + `tMax`. Only the named accessors are read, so a
|
|
@@ -293,30 +1974,61 @@ function recover_contact_normal(out, cx, cy, cz, dx, dy, dz, target_tr) {
|
|
|
293
1974
|
* @param {ArrayLike<number>} rotation the orientation the shape is held at for
|
|
294
1975
|
* the whole sweep, read BY INDEX as `[x, y, z, w]` and taken to be a unit
|
|
295
1976
|
* quaternion (it is neither normalised nor validated here — a non-unit one
|
|
296
|
-
* silently returns wrong answers). A
|
|
297
|
-
*
|
|
1977
|
+
* silently returns wrong answers). A retained `Float64Array` (what the CCD
|
|
1978
|
+
* pass hands in: the body's orientation copied out of its Transform64, whose
|
|
1979
|
+
* `rotation` accessor allocates a view per read), a `Quaternion`
|
|
298
1980
|
* (`Float64Array`-backed) and a plain `[x, y, z, w]` array all satisfy that;
|
|
299
1981
|
* an `{x, y, z, w}` object does NOT — its components read as `undefined`,
|
|
300
1982
|
* the swept AABB comes out NaN, and every cast then misses silently
|
|
301
1983
|
* @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
|
|
302
1984
|
* @param {(entity:number, collider:Collider, body_id:number)=>boolean} [filter]
|
|
303
|
-
* mandatory in contract; defaults to {@link returnTrue}.
|
|
304
|
-
* candidate body's entity,
|
|
305
|
-
* distinguishes bodies when colliders live on
|
|
1985
|
+
* mandatory in contract; defaults to {@link returnTrue}. Called once per
|
|
1986
|
+
* collider of each candidate body, with the body's entity, that collider,
|
|
1987
|
+
* and the packed body id (the id distinguishes bodies when colliders live on
|
|
1988
|
+
* child entities)
|
|
306
1989
|
* @param {boolean} [skip_initial_overlaps=false] how a candidate ALREADY
|
|
307
1990
|
* overlapping the swept shape at `t = 0` is treated. `false` (kinematic
|
|
308
1991
|
* "can I move?" semantics): targets are solid, so the cast is blocked where
|
|
309
|
-
* it stands — report a hit at `t = 0`. The one exception is a
|
|
1992
|
+
* it stands — report a hit at `t = 0`. The one exception is a target
|
|
310
1993
|
* the shape merely TOUCHES (no depth beyond {@link CONTACT_EPSILON}): a
|
|
311
1994
|
* tangency blocks only a sweep driving into it, and otherwise steps aside so
|
|
312
1995
|
* the scan can reach real blockers. `true` (CCD semantics): such a candidate
|
|
313
1996
|
* is a resting / sliding contact the discrete solver already owns, NOT a
|
|
314
1997
|
* tunnelling threat — skip it and keep scanning the remaining candidates for
|
|
315
1998
|
* real blockers along the sweep. Either way, one contact at the start of the
|
|
316
|
-
* sweep must never blind the cast to every other obstacle.
|
|
1999
|
+
* sweep must never blind the cast to every other obstacle. For a concave
|
|
2000
|
+
* target all of this is decided per TRIANGLE: a shape touching or resting
|
|
2001
|
+
* in one triangle of a mesh is still stopped by another one ahead of it.
|
|
317
2002
|
* @returns {boolean}
|
|
318
2003
|
*/
|
|
319
2004
|
export function shape_cast(system, ray, shape, rotation, result, filter = returnTrue, skip_initial_overlaps = false) {
|
|
2005
|
+
assert.ok(!shape_cast_running, NESTED_SHAPE_CAST);
|
|
2006
|
+
|
|
2007
|
+
shape_cast_running = true;
|
|
2008
|
+
try {
|
|
2009
|
+
return shape_cast_nearest(system, ray, shape, rotation, result, filter, skip_initial_overlaps);
|
|
2010
|
+
} finally {
|
|
2011
|
+
// also on the way out of a throw — a filter's own error, or the assert
|
|
2012
|
+
// above in a cast the filter started — so the next cast is not refused
|
|
2013
|
+
shape_cast_running = false;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
const NONFINITE_DIRECTION = 'shape_cast: ray direction must be a unit vector, and this one has a component that is not finite';
|
|
2018
|
+
|
|
2019
|
+
/**
|
|
2020
|
+
* {@link shape_cast}, unguarded.
|
|
2021
|
+
*
|
|
2022
|
+
* @param {PhysicsSystem} system
|
|
2023
|
+
* @param {{origin_x:number,origin_y:number,origin_z:number,direction_x:number,direction_y:number,direction_z:number,tMax:number}} ray
|
|
2024
|
+
* @param {AbstractShape3D} shape
|
|
2025
|
+
* @param {ArrayLike<number>} rotation
|
|
2026
|
+
* @param {PhysicsSurfacePoint} result
|
|
2027
|
+
* @param {(entity:number, collider:Collider, body_id:number)=>boolean} filter
|
|
2028
|
+
* @param {boolean} skip_initial_overlaps
|
|
2029
|
+
* @returns {boolean}
|
|
2030
|
+
*/
|
|
2031
|
+
function shape_cast_nearest(system, ray, shape, rotation, result, filter, skip_initial_overlaps) {
|
|
320
2032
|
const ox = ray.origin_x;
|
|
321
2033
|
const oy = ray.origin_y;
|
|
322
2034
|
const oz = ray.origin_z;
|
|
@@ -331,6 +2043,13 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
331
2043
|
assert.ok(Number.isFinite(tMax) && tMax > 0,
|
|
332
2044
|
`shape_cast: ray.tMax must be a positive finite sweep length, got ${tMax}`);
|
|
333
2045
|
if (!(tMax > 0) || !Number.isFinite(tMax)) return false;
|
|
2046
|
+
// Nor a direction with a component that is not finite: there is no unit
|
|
2047
|
+
// length to sweep by, and the swept AABB is unbounded — over a heightmap
|
|
2048
|
+
// too big for one enumeration, the piece walk shortened an infinite piece
|
|
2049
|
+
// forever. The same as the reach: loud in dev, a miss in prod.
|
|
2050
|
+
const direction_finite = Number.isFinite(dx) && Number.isFinite(dy) && Number.isFinite(dz);
|
|
2051
|
+
assert.ok(direction_finite, NONFINITE_DIRECTION);
|
|
2052
|
+
if (!direction_finite) return false;
|
|
334
2053
|
|
|
335
2054
|
const rx = rotation[0], ry = rotation[1], rz = rotation[2], rw = rotation[3];
|
|
336
2055
|
|
|
@@ -373,24 +2092,58 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
373
2092
|
}
|
|
374
2093
|
if (n_total === 0) return false;
|
|
375
2094
|
|
|
376
|
-
// ── 3. Narrowphase: per-candidate
|
|
2095
|
+
// ── 3. Narrowphase: per-candidate advancement ──────────────────
|
|
377
2096
|
//
|
|
378
2097
|
// Re-bind the swept shape's PosedShape3D once for shape + rotation;
|
|
379
|
-
// we update `px/py/pz` per
|
|
380
|
-
//
|
|
2098
|
+
// we update `px/py/pz` per sample pose without rerunning setup
|
|
2099
|
+
// (px/py/pz are public fields by contract).
|
|
381
2100
|
swept_posed.shape = shape;
|
|
382
2101
|
swept_posed.qx = rx; swept_posed.qy = ry; swept_posed.qz = rz; swept_posed.qw = rw;
|
|
383
2102
|
|
|
384
2103
|
let best_t = tMax;
|
|
2104
|
+
/** When the winner's contact begins, which candidates are ranked by ({@link cast_touch_t}). */
|
|
2105
|
+
let best_contact = tMax;
|
|
2106
|
+
/** Whether the winner is a triangle face contact, which wins a tie ({@link SIMULTANEOUS}). */
|
|
2107
|
+
let best_is_face = false;
|
|
385
2108
|
let best_body_id = -1;
|
|
386
2109
|
let best_entity = -1;
|
|
387
|
-
/**
|
|
2110
|
+
/** The struck collider's own entity, and the struck triangle of a concave one (else -1). */
|
|
2111
|
+
let best_collider_entity = -1;
|
|
2112
|
+
let best_triangle = -1;
|
|
2113
|
+
/**
|
|
2114
|
+
* Winning convex collider, for the normal probe — null when the winner is
|
|
2115
|
+
* a triangle of a concave collider, kept in {@link best_triangle_local}.
|
|
2116
|
+
*/
|
|
388
2117
|
let best_collider = null;
|
|
2118
|
+
/** The transform the winner was posed at (a triangle's: its collider's). */
|
|
389
2119
|
let best_tr = null;
|
|
2120
|
+
/** Whether the winner came with its contact normal, in {@link best_normal}. */
|
|
2121
|
+
let best_has_normal = false;
|
|
2122
|
+
|
|
2123
|
+
const stop_width = TOI_TOLERANCE * tMax;
|
|
2124
|
+
|
|
2125
|
+
// Fresh stamp for this query; wrap back to a cleared table before the
|
|
2126
|
+
// counter could collide with a stamp left behind by an older query.
|
|
2127
|
+
seen_stamp++;
|
|
2128
|
+
if (seen_stamp >= 0x7FFFFFFF) {
|
|
2129
|
+
scratch_seen.fill(0);
|
|
2130
|
+
seen_stamp = 1;
|
|
2131
|
+
}
|
|
390
2132
|
|
|
391
2133
|
candidates: for (let i = 0; i < n_total; i++) {
|
|
392
2134
|
const body_id = scratch_candidates[i];
|
|
393
2135
|
const body_idx = body_id_index(body_id);
|
|
2136
|
+
|
|
2137
|
+
if (body_idx >= scratch_seen.length) {
|
|
2138
|
+
// Preserve the stamps already written this query.
|
|
2139
|
+
const grown = new Int32Array(Math.max(body_idx + 1, scratch_seen.length * 2));
|
|
2140
|
+
grown.set(scratch_seen);
|
|
2141
|
+
scratch_seen = grown;
|
|
2142
|
+
}
|
|
2143
|
+
// A second leaf of a body already tested: every collider of it was.
|
|
2144
|
+
if (scratch_seen[body_idx] === seen_stamp) continue;
|
|
2145
|
+
scratch_seen[body_idx] = seen_stamp;
|
|
2146
|
+
|
|
394
2147
|
const entity = system.entityOf(body_id);
|
|
395
2148
|
if (entity < 0) continue;
|
|
396
2149
|
|
|
@@ -405,193 +2158,216 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
405
2158
|
if (!filter(entity, collider, body_id)) continue;
|
|
406
2159
|
|
|
407
2160
|
const target_tr = colliders[ci].transform;
|
|
408
|
-
|
|
2161
|
+
|
|
2162
|
+
if (collider.shape.is_convex !== false) {
|
|
2163
|
+
candidate_is_triangle = false;
|
|
2164
|
+
candidate_posed.setup_components(
|
|
409
2165
|
collider.shape,
|
|
410
2166
|
target_tr.translation_x, target_tr.translation_y, target_tr.translation_z,
|
|
411
2167
|
target_tr.rotation_x, target_tr.rotation_y, target_tr.rotation_z, target_tr.rotation_w
|
|
412
2168
|
);
|
|
413
2169
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// genuinely inside one is blocked where it stands, `t = 0`, whatever
|
|
421
|
-
// direction it is trying to sweep. Nothing can beat that, so stop
|
|
422
|
-
// scanning. Getting out is depenetration's job, not the sweep's.
|
|
423
|
-
//
|
|
424
|
-
// Exact TANGENCY is the exception, and it needs one. A zero-depth
|
|
425
|
-
// touch is not "inside" anything — the shape is resting against a
|
|
426
|
-
// face, or flush with a brush seam, and is free to slide along it or
|
|
427
|
-
// leave. It also survives depenetration, which has no depth to push
|
|
428
|
-
// out of, so it persists frame after frame.
|
|
429
|
-
//
|
|
430
|
-
// Reporting it as a `t = 0` hit ends the scan, and that is the whole
|
|
431
|
-
// problem: the caller is handed a contact it correctly judges harmless
|
|
432
|
-
// for this direction and concludes the sweep is clear, while the body
|
|
433
|
-
// it was actually about to hit was never tested. A character flush
|
|
434
|
-
// against a wall falls through the floor that way. So a tangency
|
|
435
|
-
// blocks only when the sweep drives INTO it, and otherwise steps aside
|
|
436
|
-
// and lets the scan continue.
|
|
437
|
-
//
|
|
438
|
-
// MPR's depth at the START pose is what separates the two: positive
|
|
439
|
-
// means genuine overlap, none means tangency. Tangency is also exactly
|
|
440
|
-
// where the normal is hardest to recover, hence the second probe; if
|
|
441
|
-
// even that degenerates there is no normal to judge with and the
|
|
442
|
-
// contact blocks, stopping short being the safe failure.
|
|
443
|
-
swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
|
|
444
|
-
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
445
|
-
if (skip_initial_overlaps) continue;
|
|
446
|
-
|
|
447
|
-
// The tangency exception reads MPR's depth and normal, both of
|
|
448
|
-
// which assume a convex target. This query has never supported
|
|
449
|
-
// concave ones (`overlap_shape` decomposes them per-triangle;
|
|
450
|
-
// nothing here does), so rather than extend a convex-only
|
|
451
|
-
// inference to geometry the module cannot see properly, leave
|
|
452
|
-
// those on the unconditional "solid, blocked at t = 0" path.
|
|
453
|
-
const convex_target = collider.shape.is_convex !== false;
|
|
454
|
-
if (convex_target && !probe_contact_normal(probe_normal, ox, oy, oz, target_tr)) {
|
|
455
|
-
const known = recover_contact_normal(
|
|
456
|
-
probe_normal, ox, oy, oz, dx, dy, dz, target_tr,
|
|
457
|
-
);
|
|
458
|
-
if (known) {
|
|
459
|
-
// Both vectors are unit, so this is the sine of the angle
|
|
460
|
-
// between the sweep and the contact plane. Zero means
|
|
461
|
-
// exactly parallel — sliding along the face — and positive
|
|
462
|
-
// means leaving it; neither blocks. The tolerance matters
|
|
463
|
-
// because the parallel case sits right on the sign change,
|
|
464
|
-
// and an MPR-recovered normal carries ~1e-6 of angular
|
|
465
|
-
// noise: without it a sweep ALONG a face flips to
|
|
466
|
-
// "head-on" on solver noise alone.
|
|
467
|
-
const into = dx * probe_normal[0] + dy * probe_normal[1] + dz * probe_normal[2];
|
|
468
|
-
if (into > -GRAZING_SINE_EPSILON) continue;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
2170
|
+
const t = cast_candidate(
|
|
2171
|
+
ox, oy, oz, dx, dy, dz, best_contact, stop_width, skip_initial_overlaps,
|
|
2172
|
+
-Infinity, Infinity
|
|
2173
|
+
);
|
|
2174
|
+
if (t === CAST_MISS) continue;
|
|
2175
|
+
if (t !== CAST_BLOCKED && !(cast_touch_t < (best_is_face ? best_contact - SIMULTANEOUS : best_contact))) continue;
|
|
471
2176
|
|
|
472
|
-
|
|
2177
|
+
best_contact = cast_touch_t;
|
|
2178
|
+
best_is_face = false;
|
|
473
2179
|
best_body_id = body_id;
|
|
474
2180
|
best_entity = entity;
|
|
2181
|
+
best_collider_entity = colliders[ci].entity;
|
|
2182
|
+
best_triangle = -1;
|
|
475
2183
|
best_collider = collider;
|
|
476
2184
|
best_tr = target_tr;
|
|
477
|
-
|
|
2185
|
+
best_has_normal = cast_has_normal;
|
|
2186
|
+
if (cast_has_normal) best_normal.set(cast_normal);
|
|
2187
|
+
if (t === CAST_BLOCKED) {
|
|
2188
|
+
best_t = 0;
|
|
2189
|
+
break candidates;
|
|
2190
|
+
}
|
|
2191
|
+
best_t = t;
|
|
2192
|
+
continue;
|
|
478
2193
|
}
|
|
479
2194
|
|
|
480
|
-
// ──
|
|
2195
|
+
// ── Concave collider: sweep its triangles ──────────────────
|
|
481
2196
|
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
2197
|
+
// A mesh or a heightmap is a SURFACE. Its convex hull — what the
|
|
2198
|
+
// whole-shape GJK above would test — reports hits in the empty
|
|
2199
|
+
// space between parts of one mesh and blocks a shape standing
|
|
2200
|
+
// anywhere inside it, and a heightmap has no support function to
|
|
2201
|
+
// build a hull from at all. So it is swept as the triangles under
|
|
2202
|
+
// the swept AABB, enumerated in its own frame by the same
|
|
2203
|
+
// decomposition the narrowphase and `overlap_shape` use, each one a
|
|
2204
|
+
// candidate in its own right.
|
|
489
2205
|
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
2206
|
+
// At most MAX_TRIANGLES_PER_PAIR of them at a time: a sweep whose box
|
|
2207
|
+
// takes in more is walked in pieces, in sweep order, each tested
|
|
2208
|
+
// only for contacts that begin within it — a later contact on one
|
|
2209
|
+
// of its triangles is the next piece's to find, with the triangles
|
|
2210
|
+
// around it — until one is hit.
|
|
2211
|
+
//
|
|
2212
|
+
// A mesh or heightmap a rigid TransformedShape3D wraps is that
|
|
2213
|
+
// surface at the composed pose, as the narrowphase collides it. A
|
|
2214
|
+
// wrapper that scales is not unwrapped, and has no enumerator, here
|
|
2215
|
+
// as there.
|
|
2216
|
+
let concave = collider.shape;
|
|
2217
|
+
let concave_tr = target_tr;
|
|
2218
|
+
while (concave.isTransformedShape3D === true && rigid_subject_pose(
|
|
2219
|
+
subject_pose, concave,
|
|
2220
|
+
concave_tr.translation_x, concave_tr.translation_y, concave_tr.translation_z,
|
|
2221
|
+
concave_tr.rotation_x, concave_tr.rotation_y, concave_tr.rotation_z, concave_tr.rotation_w
|
|
2222
|
+
)) {
|
|
2223
|
+
concave = concave.subject;
|
|
2224
|
+
concave_tr = subject_pose;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
// The sweep in the surface's frame, for the per-triangle plane
|
|
2228
|
+
// test in `load_triangle`.
|
|
2229
|
+
const qx = concave_tr.rotation_x, qy = concave_tr.rotation_y, qz = concave_tr.rotation_z, qw = concave_tr.rotation_w;
|
|
2230
|
+
v3_quaternion_apply_inverse(
|
|
2231
|
+
local_sweep, 0,
|
|
2232
|
+
ox - concave_tr.translation_x, oy - concave_tr.translation_y, oz - concave_tr.translation_z,
|
|
2233
|
+
qx, qy, qz, qw
|
|
502
2234
|
);
|
|
2235
|
+
v3_quaternion_apply_inverse(local_sweep, 3, dx, dy, dz, qx, qy, qz, qw);
|
|
2236
|
+
const lx = local_sweep[0], ly = local_sweep[1], lz = local_sweep[2];
|
|
2237
|
+
const ldx = local_sweep[3], ldy = local_sweep[4], ldz = local_sweep[5];
|
|
503
2238
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
2239
|
+
// The walk ends. Every piece is at least `min_piece` long, but the
|
|
2240
|
+
// last: one that reaches the end of the sweep, or one that cannot
|
|
2241
|
+
// be made to fit even that short — the shape's own box holds more
|
|
2242
|
+
// than the budget — which takes the rest of the sweep with it,
|
|
2243
|
+
// tested as far as the budget goes. So there are at most
|
|
2244
|
+
// 1 / MIN_PIECE_FRACTION + 1 pieces, and every shortening of one
|
|
2245
|
+
// takes at least a tenth off it until it is `min_piece` long.
|
|
2246
|
+
// Offered ever-shorter pieces instead, a sphere whose own box held
|
|
2247
|
+
// 0.81 of the budget walked a Zeno walk that never reached the end
|
|
2248
|
+
// of a 2 m slide.
|
|
2249
|
+
const min_piece = MIN_PIECE_FRACTION * tMax;
|
|
2250
|
+
let piece_start = 0;
|
|
2251
|
+
let piece_end = best_contact;
|
|
2252
|
+
let last_piece = false;
|
|
2253
|
+
while (piece_start < best_contact) {
|
|
2254
|
+
let tri_count = count_triangles(concave, concave_tr, sweep_piece_aabb(dx, dy, dz, piece_start, piece_end));
|
|
2255
|
+
while (tri_count > MAX_TRIANGLES_PER_PAIR && !last_piece) {
|
|
2256
|
+
const length = piece_end - piece_start;
|
|
2257
|
+
if (length > min_piece) {
|
|
2258
|
+
// the box's triangles grow with its area, about the square of its length
|
|
2259
|
+
const shorter = length * Math.sqrt(MAX_TRIANGLES_PER_PAIR / tri_count) * 0.9;
|
|
2260
|
+
piece_end = piece_start + (shorter > min_piece ? shorter : min_piece);
|
|
2261
|
+
} else {
|
|
2262
|
+
last_piece = true;
|
|
2263
|
+
piece_end = best_contact;
|
|
519
2264
|
}
|
|
520
|
-
|
|
2265
|
+
tri_count = count_triangles(concave, concave_tr, sweep_piece_aabb(dx, dy, dz, piece_start, piece_end));
|
|
521
2266
|
}
|
|
522
|
-
//
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const t1 = (body_min - init_max) / d_ax;
|
|
526
|
-
const t2 = (body_max - init_min) / d_ax;
|
|
527
|
-
const lo = t1 < t2 ? t1 : t2;
|
|
528
|
-
const hi = t1 < t2 ? t2 : t1;
|
|
529
|
-
if (lo > t_aabb_enter) t_aabb_enter = lo;
|
|
530
|
-
if (hi < t_aabb_exit) t_aabb_exit = hi;
|
|
531
|
-
}
|
|
532
|
-
if (skip_candidate) continue;
|
|
533
|
-
if (t_aabb_enter > t_aabb_exit) continue;
|
|
534
|
-
|
|
535
|
-
// Clamp to the relevant t-window: [0, best_t]. Anything beyond
|
|
536
|
-
// best_t can't tighten the answer.
|
|
537
|
-
const t_start = t_aabb_enter > 0 ? t_aabb_enter : 0;
|
|
538
|
-
const t_end = t_aabb_exit < best_t ? t_aabb_exit : best_t;
|
|
539
|
-
if (t_start >= t_end) continue;
|
|
540
|
-
|
|
541
|
-
// Coarse-search within the narrowed interval to find any t for
|
|
542
|
-
// which the shapes overlap (their AABBs do by construction; the
|
|
543
|
-
// shapes themselves may not, e.g. two spheres passing alongside).
|
|
544
|
-
const step_dt = (t_end - t_start) / COARSE_STEPS;
|
|
545
|
-
let t_prev = t_start;
|
|
546
|
-
let t_hi = -1;
|
|
547
|
-
for (let s = 1; s <= COARSE_STEPS; s++) {
|
|
548
|
-
const t = t_start + s * step_dt;
|
|
549
|
-
swept_posed.px = ox + dx * t;
|
|
550
|
-
swept_posed.py = oy + dy * t;
|
|
551
|
-
swept_posed.pz = oz + dz * t;
|
|
552
|
-
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
553
|
-
t_hi = t;
|
|
554
|
-
break;
|
|
2267
|
+
// A heightmap's piece was only counted: enumerate the one settled on, once.
|
|
2268
|
+
if (concave.isHeightMapShape3D === true) {
|
|
2269
|
+
tri_count = enumerate_triangles(concave, concave_tr, piece_aabb);
|
|
555
2270
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
swept_posed.px = ox + dx * t_mid;
|
|
567
|
-
swept_posed.py = oy + dy * t_mid;
|
|
568
|
-
swept_posed.pz = oz + dz * t_mid;
|
|
569
|
-
if (gjk(simplex_buf, swept_posed, candidate_posed)) {
|
|
570
|
-
t_hi = t_mid;
|
|
571
|
-
} else {
|
|
572
|
-
t_lo = t_mid;
|
|
2271
|
+
if (tri_count > MAX_TRIANGLES_PER_PAIR) {
|
|
2272
|
+
if (!triangle_overflow_reported) {
|
|
2273
|
+
triangle_overflow_reported = true;
|
|
2274
|
+
console.warn(
|
|
2275
|
+
`shape_cast: the sweep's box overlaps ${tri_count} triangles of a`
|
|
2276
|
+
+ ` ${concave.constructor.name} over a stretch too short to split;`
|
|
2277
|
+
+ ` it is tested against ${MAX_TRIANGLES_PER_PAIR} and not the rest.`
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
2280
|
+
tri_count = MAX_TRIANGLES_PER_PAIR;
|
|
573
2281
|
}
|
|
574
|
-
}
|
|
575
2282
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
2283
|
+
triangle_count = tri_count;
|
|
2284
|
+
for (let k = 0; k < tri_count; k++) {
|
|
2285
|
+
triangle_offset = k * TRIANGLE_FLOAT_STRIDE;
|
|
2286
|
+
load_triangle(
|
|
2287
|
+
concave, triangle_buffer, triangle_offset, concave_tr,
|
|
2288
|
+
lx, ly, lz, ldx, ldy, ldz,
|
|
2289
|
+
ox, oy, oz, tMax, skip_initial_overlaps
|
|
2290
|
+
);
|
|
2291
|
+
|
|
2292
|
+
// a face may still win a tie with a contact of another kind
|
|
2293
|
+
let reach = best_is_face ? best_contact : best_contact + SIMULTANEOUS;
|
|
2294
|
+
if (reach > tMax) reach = tMax;
|
|
2295
|
+
const limit = reach < piece_end ? reach : piece_end;
|
|
2296
|
+
const t = cast_candidate(
|
|
2297
|
+
ox, oy, oz, dx, dy, dz, limit, stop_width, skip_initial_overlaps,
|
|
2298
|
+
triangle_window_enter, triangle_window_exit
|
|
2299
|
+
);
|
|
2300
|
+
if (t === CAST_MISS) continue;
|
|
2301
|
+
const beats = t === CAST_BLOCKED || (cast_face
|
|
2302
|
+
? cast_touch_t < limit
|
|
2303
|
+
: cast_touch_t < (best_is_face ? best_contact - SIMULTANEOUS : best_contact) && cast_touch_t < piece_end);
|
|
2304
|
+
if (!beats) continue;
|
|
2305
|
+
|
|
2306
|
+
best_contact = cast_touch_t;
|
|
2307
|
+
best_is_face = cast_face;
|
|
2308
|
+
best_body_id = body_id;
|
|
2309
|
+
best_entity = entity;
|
|
2310
|
+
best_collider_entity = colliders[ci].entity;
|
|
2311
|
+
// the enumerators' feature id is the triangle's index plus one
|
|
2312
|
+
best_triangle = triangle_buffer[triangle_offset + TRIANGLE_FEATURE_ID_OFFSET] - 1;
|
|
2313
|
+
best_collider = null;
|
|
2314
|
+
if (concave_tr === subject_pose) {
|
|
2315
|
+
best_subject_pose.copy(subject_pose);
|
|
2316
|
+
best_tr = best_subject_pose;
|
|
2317
|
+
} else {
|
|
2318
|
+
best_tr = concave_tr;
|
|
2319
|
+
}
|
|
2320
|
+
best_triangle_local.set(triangle_local);
|
|
2321
|
+
if (cast_face) {
|
|
2322
|
+
best_has_normal = true;
|
|
2323
|
+
best_normal.set(plane_normal);
|
|
2324
|
+
} else {
|
|
2325
|
+
best_has_normal = cast_has_normal;
|
|
2326
|
+
if (cast_has_normal) best_normal.set(cast_normal);
|
|
2327
|
+
}
|
|
2328
|
+
if (t === CAST_BLOCKED) {
|
|
2329
|
+
best_t = 0;
|
|
2330
|
+
break candidates;
|
|
2331
|
+
}
|
|
2332
|
+
best_t = t;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
// A hit in this piece is nearer than anything a later one holds.
|
|
2336
|
+
if (best_contact < piece_end || last_piece) break;
|
|
2337
|
+
|
|
2338
|
+
// Offer the next piece the length this one's triangles say fills
|
|
2339
|
+
// the budget — never less than this one's — not the rest of the
|
|
2340
|
+
// sweep: enumerating the rest, over-full, only to learn that it
|
|
2341
|
+
// was, took a third of a 2.6 m sweep's time over a
|
|
2342
|
+
// 720,000-triangle floor.
|
|
2343
|
+
const piece_length = piece_end - piece_start;
|
|
2344
|
+
const fill = Math.sqrt(MAX_TRIANGLES_PER_PAIR / (tri_count > 0 ? tri_count : 1)) * 0.9;
|
|
2345
|
+
piece_start = piece_end;
|
|
2346
|
+
piece_end = piece_start + (fill > 1 ? piece_length * fill : piece_length);
|
|
2347
|
+
if (!(piece_end < best_contact)) piece_end = best_contact;
|
|
589
2348
|
}
|
|
590
2349
|
}
|
|
591
2350
|
}
|
|
592
2351
|
|
|
593
2352
|
if (best_body_id === -1) return false;
|
|
594
2353
|
|
|
2354
|
+
// What was struck — a convex collider, or the one triangle of a concave
|
|
2355
|
+
// one — posed for {@link shape_cast_struck_support}.
|
|
2356
|
+
if (best_collider !== null) {
|
|
2357
|
+
struck_posed.setup_components(
|
|
2358
|
+
best_collider.shape,
|
|
2359
|
+
best_tr.translation_x, best_tr.translation_y, best_tr.translation_z,
|
|
2360
|
+
best_tr.rotation_x, best_tr.rotation_y, best_tr.rotation_z, best_tr.rotation_w
|
|
2361
|
+
);
|
|
2362
|
+
} else {
|
|
2363
|
+
struck_triangle_vertices.set(best_triangle_local);
|
|
2364
|
+
struck_posed.setup_components(
|
|
2365
|
+
struck_triangle_shape,
|
|
2366
|
+
best_tr.translation_x, best_tr.translation_y, best_tr.translation_z,
|
|
2367
|
+
best_tr.rotation_x, best_tr.rotation_y, best_tr.rotation_z, best_tr.rotation_w
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
595
2371
|
const rp = result.position;
|
|
596
2372
|
const rn = result.normal;
|
|
597
2373
|
|
|
@@ -603,20 +2379,26 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
603
2379
|
rp[1] = swept_y;
|
|
604
2380
|
rp[2] = swept_z;
|
|
605
2381
|
|
|
606
|
-
// ── Contact
|
|
2382
|
+
// ── Contact normal ─────────────────────────────────────────────
|
|
607
2383
|
//
|
|
608
|
-
//
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
//
|
|
614
|
-
//
|
|
615
|
-
//
|
|
616
|
-
//
|
|
2384
|
+
// A hit found by advancement comes with its normal: the direction
|
|
2385
|
+
// separating the two at the reported pose, from the closest points the
|
|
2386
|
+
// distance kernel stopped on — exact for any pair of shapes, edge and
|
|
2387
|
+
// corner contacts included. A triangle FACE contact comes with the face's.
|
|
2388
|
+
// Read by penetration instead, off the one triangle that won, it leans
|
|
2389
|
+
// toward that triangle's edge when the contact sits near the seam of a
|
|
2390
|
+
// face split into triangles — a capsule striking a cube face across its
|
|
2391
|
+
// diagonal read 5.7°, where a convex box reads its face exactly.
|
|
2392
|
+
//
|
|
2393
|
+
// The rest — a hit blocked at the start, or one the bracket search found
|
|
2394
|
+
// — is read off by MPR. EPA on smooth-vs-smooth supports at this overlap
|
|
2395
|
+
// can't tighten before its iteration cap and returns a direction off by
|
|
2396
|
+
// ~30° from truth. MPR is the better tool here: it converges in 5-15
|
|
2397
|
+
// iterations on smooth surfaces, same MTV output convention as EPA
|
|
2398
|
+
// (direction = A's interior into B, magnitude = depth).
|
|
617
2399
|
//
|
|
618
2400
|
// The probe pose is `NORMAL_PROBE_OFFSET` past `best_t` along the sweep
|
|
619
|
-
// (a few mm into the target) —
|
|
2401
|
+
// (a few mm into the target) — the search stops on the just-SEPARATING
|
|
620
2402
|
// side, so there is no MTV to read exactly at `best_t`. The reported
|
|
621
2403
|
// `result.t` stays at `best_t`; only the normal probe moves.
|
|
622
2404
|
// `recover_contact_normal` handles the grazing case, where advancing
|
|
@@ -625,17 +2407,32 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
625
2407
|
const contact_y = oy + dy * best_t;
|
|
626
2408
|
const contact_z = oz + dz * best_t;
|
|
627
2409
|
let normal_x = -dx, normal_y = -dy, normal_z = -dz;
|
|
2410
|
+
result.collider_entity = best_collider_entity;
|
|
2411
|
+
result.triangle = best_triangle;
|
|
2412
|
+
if (best_has_normal) {
|
|
2413
|
+
rn[0] = best_normal[0]; rn[1] = best_normal[1]; rn[2] = best_normal[2];
|
|
2414
|
+
result.t = best_t;
|
|
2415
|
+
result.entity = best_entity;
|
|
2416
|
+
result.body_id = best_body_id;
|
|
2417
|
+
return true;
|
|
2418
|
+
}
|
|
628
2419
|
if (best_collider !== null) {
|
|
2420
|
+
candidate_is_triangle = false;
|
|
629
2421
|
candidate_posed.setup_components(
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
2422
|
+
best_collider.shape,
|
|
2423
|
+
best_tr.translation_x, best_tr.translation_y, best_tr.translation_z,
|
|
2424
|
+
best_tr.rotation_x, best_tr.rotation_y, best_tr.rotation_z, best_tr.rotation_w
|
|
2425
|
+
);
|
|
2426
|
+
} else {
|
|
2427
|
+
// The probes re-anchor the triangle themselves.
|
|
2428
|
+
triangle_local.set(best_triangle_local);
|
|
2429
|
+
triangle_tr = best_tr;
|
|
2430
|
+
candidate_is_triangle = true;
|
|
2431
|
+
}
|
|
2432
|
+
if (recover_contact_normal(probe_normal, contact_x, contact_y, contact_z, dx, dy, dz)) {
|
|
2433
|
+
normal_x = probe_normal[0];
|
|
2434
|
+
normal_y = probe_normal[1];
|
|
2435
|
+
normal_z = probe_normal[2];
|
|
639
2436
|
}
|
|
640
2437
|
|
|
641
2438
|
rn[0] = normal_x; rn[1] = normal_y; rn[2] = normal_z;
|
|
@@ -644,3 +2441,22 @@ export function shape_cast(system, ray, shape, rotation, result, filter = return
|
|
|
644
2441
|
result.body_id = best_body_id;
|
|
645
2442
|
return true;
|
|
646
2443
|
}
|
|
2444
|
+
|
|
2445
|
+
/**
|
|
2446
|
+
* Support point, in world space, of what the last successful {@link shape_cast}
|
|
2447
|
+
* struck — the convex collider, or for a concave collider the one triangle the
|
|
2448
|
+
* hit was on — along the world direction in `direction[direction_offset .. +2]`, under
|
|
2449
|
+
* {@link AbstractShape3D#support}'s contract.
|
|
2450
|
+
*
|
|
2451
|
+
* For a caller that needs the struck surface's own geometry at the contact
|
|
2452
|
+
* (the CCD pass places its impulse where the two facing features overlap).
|
|
2453
|
+
* Valid until the next cast; meaningless before any cast has hit.
|
|
2454
|
+
*
|
|
2455
|
+
* @param {Float64Array} out receives the point
|
|
2456
|
+
* @param {number} out_offset
|
|
2457
|
+
* @param {Float64Array|number[]} direction
|
|
2458
|
+
* @param {number} direction_offset
|
|
2459
|
+
*/
|
|
2460
|
+
export function shape_cast_struck_support(out, out_offset, direction, direction_offset) {
|
|
2461
|
+
struck_posed.support(out, out_offset, direction, direction_offset);
|
|
2462
|
+
}
|