@woosh/meep-engine 2.139.0 → 2.140.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/package.json +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts +3 -3
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js +4 -4
- package/src/{engine/physics/broadphase/aabb_transform_oriented.d.ts → core/geom/3d/aabb/aabb3_transform_oriented.d.ts} +2 -2
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -0
- package/src/{engine/physics/broadphase/aabb_transform_oriented.js → core/geom/3d/aabb/aabb3_transform_oriented.js} +1 -1
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +54 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -0
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts +24 -2
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/AbstractShape3D.js +24 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +148 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.js +451 -0
- package/src/core/geom/3d/shape/MeshShape3D.d.ts +210 -0
- package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/MeshShape3D.js +593 -0
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +46 -2
- package/src/core/geom/3d/shape/Triangle3D.d.ts +95 -0
- package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/Triangle3D.js +318 -0
- package/src/core/geom/3d/shape/UnionShape3D.js +13 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +30 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +1 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +64 -0
- package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +9 -11
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts +28 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +40 -18
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +9 -5
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +38 -10
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +14 -5
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +47 -5
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +19 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +75 -13
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +2 -2
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +1 -1
- package/src/core/geom/vec3/v3_dot_array_array.d.ts +3 -3
- package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_dot_array_array.js +2 -2
- package/src/core/geom/vec3/v3_negate_array.d.ts +3 -3
- package/src/core/geom/vec3/v3_negate_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_negate_array.js +2 -2
- package/src/core/geom/vec3/v3_quat3_apply.d.ts +29 -0
- package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_quat3_apply.js +39 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +30 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.js +41 -0
- package/src/core/geom/vec3/v3_triple_cross_product.d.ts +32 -0
- package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_triple_cross_product.js +45 -0
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +16 -3
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerController.js +211 -211
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +72 -8
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +37 -5
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +101 -3
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1789 -1416
- package/src/engine/control/first-person/TODO.md +173 -127
- package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Slide.js +9 -1
- package/src/engine/control/first-person/prototype_first_person_controller.js +88 -2
- package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -1
- package/src/engine/control/first-person/test/buildTestPlayer.js +9 -1
- package/src/engine/graphics/geometry/CapsuleGeometry.d.ts +42 -0
- package/src/engine/graphics/geometry/CapsuleGeometry.d.ts.map +1 -0
- package/src/engine/graphics/geometry/CapsuleGeometry.js +171 -0
- package/src/engine/physics/BULLET_REVIEW.md +945 -0
- package/src/engine/physics/CANNON_REVIEW.md +1300 -0
- package/src/engine/physics/JOLT_REVIEW.md +913 -0
- package/src/engine/physics/PLAN.md +461 -236
- package/src/engine/physics/RAPIER_REVIEW.md +934 -0
- package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +2 -2
- package/src/engine/physics/contact/ManifoldStore.d.ts +83 -10
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
- package/src/engine/physics/contact/ManifoldStore.js +608 -499
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +2 -2
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +128 -20
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +1301 -1159
- package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidSimulator.js +2 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +28 -6
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +39 -17
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +6 -6
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
- package/src/engine/physics/gjk/expanding_polytope_algorithm.js +68 -22
- package/src/engine/physics/gjk/gjk.d.ts +28 -2
- package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
- package/src/engine/physics/gjk/gjk.js +421 -378
- package/src/engine/physics/gjk/minkowski_support.d.ts +37 -0
- package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -0
- package/src/engine/physics/gjk/minkowski_support.js +75 -0
- package/src/engine/physics/gjk/mpr.d.ts +56 -0
- package/src/engine/physics/gjk/mpr.d.ts.map +1 -0
- package/src/engine/physics/gjk/mpr.js +344 -0
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +20 -5
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +36 -38
- package/src/engine/physics/integration/integrate_position.d.ts +25 -7
- package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_position.js +43 -12
- package/src/engine/physics/integration/integrate_velocity.d.ts +30 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +82 -1
- package/src/engine/physics/narrowphase/PosedShape.d.ts +0 -8
- package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/PosedShape.js +28 -30
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +113 -17
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +30 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.js +811 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_contacts.js +10 -56
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +71 -0
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/capsule_triangle_contact.js +375 -0
- package/src/engine/physics/narrowphase/compute_penetration.d.ts +91 -0
- package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/compute_penetration.js +396 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts +35 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.js +80 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +31 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +42 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +204 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +42 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +94 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +37 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts +8 -2
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +1422 -382
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_box_contact.js +16 -23
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +48 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.js +143 -0
- package/src/engine/physics/queries/overlap_shape.d.ts +51 -0
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -0
- package/src/engine/physics/queries/overlap_shape.js +183 -0
- package/src/engine/physics/queries/shape_cast.d.ts +56 -0
- package/src/engine/physics/queries/shape_cast.d.ts.map +1 -0
- package/src/engine/physics/queries/shape_cast.js +387 -0
- package/src/engine/physics/solver/solve_contacts.d.ts +116 -30
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +641 -223
- package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +0 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +0 -20
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +0 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +0 -83
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sphere_box_contact.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/narrowphase/sphere_box_contact.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sphere_box_contact.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/narrowphase/sphere_box_contact.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wCAjBW,MAAM,EAAE,GAAC,YAAY,MACrB,MAAM,MACN,MAAM,MACN,MAAM,UACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,OAAO,CA8EnB"}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { v3_quat3_apply } from "../../../core/geom/vec3/v3_quat3_apply.js";
|
|
2
|
+
import { v3_quat3_apply_inverse } from "../../../core/geom/vec3/v3_quat3_apply_inverse.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Scratch for the world→box-local rotation of the sphere centre at the
|
|
6
|
+
* top of {@link sphere_box_contact}. 3 floats; allocation-free.
|
|
7
|
+
* @type {Float64Array}
|
|
8
|
+
*/
|
|
9
|
+
const scratch_local = new Float64Array(3);
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Closed-form contact generation for a unit sphere vs. an oriented box.
|
|
3
13
|
*
|
|
@@ -43,18 +53,10 @@ export function sphere_box_contact(
|
|
|
43
53
|
) {
|
|
44
54
|
// Step 1: bring the sphere centre into box-local space via the conjugate
|
|
45
55
|
// quaternion. v_local = q* · (s - b) · q
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
const tx0 = bqw * dx + cy * dz - cz * dy;
|
|
51
|
-
const ty0 = bqw * dy + cz * dx - cx * dz;
|
|
52
|
-
const tz0 = bqw * dz + cx * dy - cy * dx;
|
|
53
|
-
const tw0 = -cx * dx - cy * dy - cz * dz;
|
|
54
|
-
// Then multiply by c* = (qx,qy,qz,qw) (the original quaternion):
|
|
55
|
-
const lx = tx0 * bqw + tw0 * bqx + ty0 * bqz - tz0 * bqy;
|
|
56
|
-
const ly = ty0 * bqw + tw0 * bqy + tz0 * bqx - tx0 * bqz;
|
|
57
|
-
const lz = tz0 * bqw + tw0 * bqz + tx0 * bqy - ty0 * bqx;
|
|
56
|
+
v3_quat3_apply_inverse(scratch_local, 0, sx - bx, sy - by, sz - bz, bqx, bqy, bqz, bqw);
|
|
57
|
+
const lx = scratch_local[0];
|
|
58
|
+
const ly = scratch_local[1];
|
|
59
|
+
const lz = scratch_local[2];
|
|
58
60
|
|
|
59
61
|
// Step 2: closest point on the box to the sphere centre, in body frame.
|
|
60
62
|
const clx = lx < -hx ? -hx : (lx > hx ? hx : lx);
|
|
@@ -100,18 +102,9 @@ export function sphere_box_contact(
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
// Step 3: rotate normal and surface point back to world. v_world = q · v · q*
|
|
103
|
-
function rotate_to_world(out_arr, off, vx, vy, vz) {
|
|
104
|
-
const ix = bqw * vx + bqy * vz - bqz * vy;
|
|
105
|
-
const iy = bqw * vy + bqz * vx - bqx * vz;
|
|
106
|
-
const iz = bqw * vz + bqx * vy - bqy * vx;
|
|
107
|
-
const iw = -bqx * vx - bqy * vy - bqz * vz;
|
|
108
|
-
out_arr[off] = ix * bqw + iw * (-bqx) + iy * (-bqz) - iz * (-bqy);
|
|
109
|
-
out_arr[off + 1] = iy * bqw + iw * (-bqy) + iz * (-bqx) - ix * (-bqz);
|
|
110
|
-
out_arr[off + 2] = iz * bqw + iw * (-bqz) + ix * (-bqy) - iy * (-bqx);
|
|
111
|
-
}
|
|
112
105
|
|
|
113
106
|
// World normal (box → sphere).
|
|
114
|
-
|
|
107
|
+
v3_quat3_apply(out, 0, nlx, nly, nlz, bqx, bqy, bqz, bqw);
|
|
115
108
|
const nx = out[0], ny = out[1], nz = out[2];
|
|
116
109
|
out[3] = radius - dist;
|
|
117
110
|
|
|
@@ -121,7 +114,7 @@ export function sphere_box_contact(
|
|
|
121
114
|
out[6] = sz - nz * radius;
|
|
122
115
|
|
|
123
116
|
// World contact on box: rotate the local-space clamped point to world, plus box centre.
|
|
124
|
-
|
|
117
|
+
v3_quat3_apply(out, 7, clx, cly, clz, bqx, bqy, bqz, bqw);
|
|
125
118
|
out[7] += bx;
|
|
126
119
|
out[8] += by;
|
|
127
120
|
out[9] += bz;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed-form contact generation for a sphere vs. a triangle.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm: find the closest point on the triangle to the sphere centre
|
|
5
|
+
* via Ericson barycentric voronoi-region projection, then compare the
|
|
6
|
+
* distance to the sphere radius. The result is closed-form, exact for
|
|
7
|
+
* the geometric primitives involved, and avoids the precision wall that
|
|
8
|
+
* GJK+EPA hits on {@link Triangle3D} — whose support function is
|
|
9
|
+
* degenerate along the face normal (all 3 vertices project to the same
|
|
10
|
+
* value) and produces noisy depths at small penetrations.
|
|
11
|
+
*
|
|
12
|
+
* Sphere-vs-triangle is the building block for sphere-vs-concave
|
|
13
|
+
* (mesh, heightmap) narrowphase: the concave dispatch in
|
|
14
|
+
* {@link narrowphase_step} decomposes the concave shape into world-space
|
|
15
|
+
* triangles and runs this function per triangle.
|
|
16
|
+
*
|
|
17
|
+
* Output convention (mirrors {@link sphere_box_contact} and
|
|
18
|
+
* {@link sphere_sphere_contact}): the normal in `out[0..2]` points
|
|
19
|
+
* from the triangle's surface toward the sphere centre — i.e. the
|
|
20
|
+
* direction the sphere should be pushed to separate; `out[3]` is the
|
|
21
|
+
* positive penetration depth; `out[4..6]` is the world contact on
|
|
22
|
+
* the sphere's surface; `out[7..9]` is the world contact on the
|
|
23
|
+
* triangle's surface (the closest point).
|
|
24
|
+
*
|
|
25
|
+
* Singular case: when the sphere centre lies exactly on the triangle's
|
|
26
|
+
* plane (distance == 0), the normal direction is geometrically undefined.
|
|
27
|
+
* We fall back to the triangle's face normal (CCW winding), which is the
|
|
28
|
+
* direction the surrounding solid is "outward" from for closed meshes
|
|
29
|
+
* and heightmaps.
|
|
30
|
+
*
|
|
31
|
+
* @param {number[]|Float64Array} out length >= 10
|
|
32
|
+
* @param {number} sx sphere centre x (world)
|
|
33
|
+
* @param {number} sy
|
|
34
|
+
* @param {number} sz
|
|
35
|
+
* @param {number} radius
|
|
36
|
+
* @param {number} ax triangle vertex A x (world)
|
|
37
|
+
* @param {number} ay
|
|
38
|
+
* @param {number} az
|
|
39
|
+
* @param {number} bx triangle vertex B x (world)
|
|
40
|
+
* @param {number} by
|
|
41
|
+
* @param {number} bz
|
|
42
|
+
* @param {number} cx triangle vertex C x (world)
|
|
43
|
+
* @param {number} cy
|
|
44
|
+
* @param {number} cz
|
|
45
|
+
* @returns {boolean} true if sphere overlaps the triangle
|
|
46
|
+
*/
|
|
47
|
+
export function sphere_triangle_contact(out: number[] | Float64Array, sx: number, sy: number, sz: number, radius: number, ax: number, ay: number, az: number, bx: number, by: number, bz: number, cx: number, cy: number, cz: number): boolean;
|
|
48
|
+
//# sourceMappingURL=sphere_triangle_contact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sphere_triangle_contact.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/narrowphase/sphere_triangle_contact.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,6CAhBW,MAAM,EAAE,GAAC,YAAY,MACrB,MAAM,MACN,MAAM,MACN,MAAM,UACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,OAAO,CAwFnB"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { computeTriangleClosestPointToPointBarycentric } from "../../../core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Closest-point on triangle, written into the first two floats of `out`
|
|
5
|
+
* as `(alpha_A, alpha_B)` — `alpha_C = 1 - alpha_A - alpha_B`. Reused
|
|
6
|
+
* across the {@link sphere_triangle_contact} body to avoid allocation.
|
|
7
|
+
* @type {Float64Array}
|
|
8
|
+
*/
|
|
9
|
+
const scratch_bary = new Float64Array(2);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Closed-form contact generation for a sphere vs. a triangle.
|
|
13
|
+
*
|
|
14
|
+
* Algorithm: find the closest point on the triangle to the sphere centre
|
|
15
|
+
* via Ericson barycentric voronoi-region projection, then compare the
|
|
16
|
+
* distance to the sphere radius. The result is closed-form, exact for
|
|
17
|
+
* the geometric primitives involved, and avoids the precision wall that
|
|
18
|
+
* GJK+EPA hits on {@link Triangle3D} — whose support function is
|
|
19
|
+
* degenerate along the face normal (all 3 vertices project to the same
|
|
20
|
+
* value) and produces noisy depths at small penetrations.
|
|
21
|
+
*
|
|
22
|
+
* Sphere-vs-triangle is the building block for sphere-vs-concave
|
|
23
|
+
* (mesh, heightmap) narrowphase: the concave dispatch in
|
|
24
|
+
* {@link narrowphase_step} decomposes the concave shape into world-space
|
|
25
|
+
* triangles and runs this function per triangle.
|
|
26
|
+
*
|
|
27
|
+
* Output convention (mirrors {@link sphere_box_contact} and
|
|
28
|
+
* {@link sphere_sphere_contact}): the normal in `out[0..2]` points
|
|
29
|
+
* from the triangle's surface toward the sphere centre — i.e. the
|
|
30
|
+
* direction the sphere should be pushed to separate; `out[3]` is the
|
|
31
|
+
* positive penetration depth; `out[4..6]` is the world contact on
|
|
32
|
+
* the sphere's surface; `out[7..9]` is the world contact on the
|
|
33
|
+
* triangle's surface (the closest point).
|
|
34
|
+
*
|
|
35
|
+
* Singular case: when the sphere centre lies exactly on the triangle's
|
|
36
|
+
* plane (distance == 0), the normal direction is geometrically undefined.
|
|
37
|
+
* We fall back to the triangle's face normal (CCW winding), which is the
|
|
38
|
+
* direction the surrounding solid is "outward" from for closed meshes
|
|
39
|
+
* and heightmaps.
|
|
40
|
+
*
|
|
41
|
+
* @param {number[]|Float64Array} out length >= 10
|
|
42
|
+
* @param {number} sx sphere centre x (world)
|
|
43
|
+
* @param {number} sy
|
|
44
|
+
* @param {number} sz
|
|
45
|
+
* @param {number} radius
|
|
46
|
+
* @param {number} ax triangle vertex A x (world)
|
|
47
|
+
* @param {number} ay
|
|
48
|
+
* @param {number} az
|
|
49
|
+
* @param {number} bx triangle vertex B x (world)
|
|
50
|
+
* @param {number} by
|
|
51
|
+
* @param {number} bz
|
|
52
|
+
* @param {number} cx triangle vertex C x (world)
|
|
53
|
+
* @param {number} cy
|
|
54
|
+
* @param {number} cz
|
|
55
|
+
* @returns {boolean} true if sphere overlaps the triangle
|
|
56
|
+
*/
|
|
57
|
+
export function sphere_triangle_contact(
|
|
58
|
+
out,
|
|
59
|
+
sx, sy, sz, radius,
|
|
60
|
+
ax, ay, az,
|
|
61
|
+
bx, by, bz,
|
|
62
|
+
cx, cy, cz
|
|
63
|
+
) {
|
|
64
|
+
// Degenerate-triangle guard. For zero-area triangles (colinear or
|
|
65
|
+
// duplicate vertices) the closest-point algorithm still returns
|
|
66
|
+
// a point on the degenerate "line" but the surrounding geometry
|
|
67
|
+
// has no meaningful face — emitting a contact would mislead the
|
|
68
|
+
// solver. Catch this upfront via the face-normal cross product;
|
|
69
|
+
// the same magnitude is reused for the dist=0 fallback below.
|
|
70
|
+
//
|
|
71
|
+
// Cost: 9 flops + 1 sqrt. Negligible vs. the rest of the function
|
|
72
|
+
// and saves the caller from having to pre-filter its input.
|
|
73
|
+
const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
|
|
74
|
+
const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
|
|
75
|
+
const fnx = e1y * e2z - e1z * e2y;
|
|
76
|
+
const fny = e1z * e2x - e1x * e2z;
|
|
77
|
+
const fnz = e1x * e2y - e1y * e2x;
|
|
78
|
+
const fn_mag_sqr = fnx * fnx + fny * fny + fnz * fnz;
|
|
79
|
+
if (fn_mag_sqr === 0) return false;
|
|
80
|
+
|
|
81
|
+
// Closest-point on triangle to sphere centre — barycentric output.
|
|
82
|
+
computeTriangleClosestPointToPointBarycentric(
|
|
83
|
+
scratch_bary, 0,
|
|
84
|
+
sx, sy, sz,
|
|
85
|
+
ax, ay, az,
|
|
86
|
+
bx, by, bz,
|
|
87
|
+
cx, cy, cz
|
|
88
|
+
);
|
|
89
|
+
const alpha_a = scratch_bary[0];
|
|
90
|
+
const alpha_b = scratch_bary[1];
|
|
91
|
+
const alpha_c = 1 - alpha_a - alpha_b;
|
|
92
|
+
|
|
93
|
+
// Reconstruct the closest world-space point.
|
|
94
|
+
const px = alpha_a * ax + alpha_b * bx + alpha_c * cx;
|
|
95
|
+
const py = alpha_a * ay + alpha_b * by + alpha_c * cy;
|
|
96
|
+
const pz = alpha_a * az + alpha_b * bz + alpha_c * cz;
|
|
97
|
+
|
|
98
|
+
// Vector from closest point to sphere centre.
|
|
99
|
+
const dx = sx - px;
|
|
100
|
+
const dy = sy - py;
|
|
101
|
+
const dz = sz - pz;
|
|
102
|
+
const dist_sqr = dx * dx + dy * dy + dz * dz;
|
|
103
|
+
|
|
104
|
+
if (dist_sqr >= radius * radius) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const dist = Math.sqrt(dist_sqr);
|
|
109
|
+
let nx, ny, nz;
|
|
110
|
+
if (dist > 0) {
|
|
111
|
+
const inv = 1 / dist;
|
|
112
|
+
nx = dx * inv;
|
|
113
|
+
ny = dy * inv;
|
|
114
|
+
nz = dz * inv;
|
|
115
|
+
} else {
|
|
116
|
+
// Sphere centre lies on the triangle's surface — direction is
|
|
117
|
+
// undefined. Fall back to the triangle's face normal (CCW
|
|
118
|
+
// winding: (B - A) × (C - A)), which is the outward direction
|
|
119
|
+
// for closed meshes and heightmaps. The cross product was
|
|
120
|
+
// already computed for the degeneracy guard at the top of
|
|
121
|
+
// the function; reuse fn_mag_sqr.
|
|
122
|
+
const fn_mag = Math.sqrt(fn_mag_sqr);
|
|
123
|
+
const inv_fn = 1 / fn_mag;
|
|
124
|
+
nx = fnx * inv_fn;
|
|
125
|
+
ny = fny * inv_fn;
|
|
126
|
+
nz = fnz * inv_fn;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
out[0] = nx;
|
|
130
|
+
out[1] = ny;
|
|
131
|
+
out[2] = nz;
|
|
132
|
+
out[3] = radius - dist;
|
|
133
|
+
// Sphere surface point: centre minus normal*radius (the point on
|
|
134
|
+
// the sphere nearest the triangle).
|
|
135
|
+
out[4] = sx - nx * radius;
|
|
136
|
+
out[5] = sy - ny * radius;
|
|
137
|
+
out[6] = sz - nz * radius;
|
|
138
|
+
// Triangle surface point: the closest point we already computed.
|
|
139
|
+
out[7] = px;
|
|
140
|
+
out[8] = py;
|
|
141
|
+
out[9] = pz;
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test what bodies overlap a convex shape placed at a given pose. Each
|
|
3
|
+
* overlapping body's `body_id` is written to `output` starting at
|
|
4
|
+
* `output_offset`; the function returns the number of body ids written.
|
|
5
|
+
*
|
|
6
|
+
* Use case: speculative physics queries for kinematic / character
|
|
7
|
+
* controllers. An external system can ask "would my body collide with
|
|
8
|
+
* anything if I moved it here?" without committing a tick of
|
|
9
|
+
* simulation. The output is a flat list of body ids so the caller can
|
|
10
|
+
* decide what to do per hit (skip, push, slide, etc.).
|
|
11
|
+
*
|
|
12
|
+
* The pipeline mirrors the narrowphase pair test:
|
|
13
|
+
* 1. Build the query shape's world AABB.
|
|
14
|
+
* 2. Pull candidates from both broadphase trees that overlap that AABB.
|
|
15
|
+
* 3. For each candidate, run GJK in world frame. Convex candidates
|
|
16
|
+
* go through one GJK call; concave candidates (heightmap / mesh)
|
|
17
|
+
* go through the per-triangle decomposition path.
|
|
18
|
+
* 4. Apply the optional `filter` callback (same signature as in
|
|
19
|
+
* raycast / shapeCast) before the GJK test — early-out on bodies
|
|
20
|
+
* the caller already wants to skip (themselves, allies, etc.).
|
|
21
|
+
*
|
|
22
|
+
* The query shape must be convex (`is_convex === true`). Concave shapes
|
|
23
|
+
* are typically static terrain and not used as kinematic query
|
|
24
|
+
* probes; rejecting them avoids the M×N triangle-pair cost.
|
|
25
|
+
*
|
|
26
|
+
* @param {PhysicsSystem} system
|
|
27
|
+
* @param {AbstractShape3D} shape query shape, convex; expressed in
|
|
28
|
+
* its own local frame
|
|
29
|
+
* @param {{x:number,y:number,z:number}} position world position of the
|
|
30
|
+
* query shape
|
|
31
|
+
* @param {{x:number,y:number,z:number,w:number}} rotation world rotation
|
|
32
|
+
* of the query shape (unit quaternion)
|
|
33
|
+
* @param {Uint32Array|number[]} output buffer to write body_ids into.
|
|
34
|
+
* Caller is responsible for sizing it; ids past its end are dropped.
|
|
35
|
+
* @param {number} output_offset float-index in output to start writing at
|
|
36
|
+
* @param {(entity:number, collider:Collider)=>boolean} [filter]
|
|
37
|
+
* defaults to {@link returnTrue} (accept every candidate)
|
|
38
|
+
* @returns {number} number of overlapping bodies written
|
|
39
|
+
* @throws {Error} if `shape.is_convex === false`
|
|
40
|
+
*/
|
|
41
|
+
export function overlap_shape(system: PhysicsSystem, shape: AbstractShape3D, position: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
z: number;
|
|
45
|
+
}, rotation: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
z: number;
|
|
49
|
+
w: number;
|
|
50
|
+
}, output: Uint32Array | number[], output_offset: number, filter?: (entity: number, collider: Collider) => boolean): number;
|
|
51
|
+
//# sourceMappingURL=overlap_shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlap_shape.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/queries/overlap_shape.js"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,uFAZW;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,YAE5B;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,UAErC,WAAW,GAAC,MAAM,EAAE,iBAEpB,MAAM,oBACE,MAAM,yBAAsB,OAAO,GAEzC,MAAM,CAqGlB"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { bvh_query_user_data_overlaps_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
|
|
2
|
+
import { returnTrue } from "../../../core/function/returnTrue.js";
|
|
3
|
+
import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
|
|
4
|
+
import { Triangle3D } from "../../../core/geom/3d/shape/Triangle3D.js";
|
|
5
|
+
import { body_id_index } from "../body/BodyStorage.js";
|
|
6
|
+
import { gjk } from "../gjk/gjk.js";
|
|
7
|
+
import { aabb_world_to_local } from "../narrowphase/decomposition/aabb_world_to_local.js";
|
|
8
|
+
import { decompose_to_triangles } from "../narrowphase/decomposition/decompose_to_triangles.js";
|
|
9
|
+
import { TRIANGLE_FLOAT_STRIDE } from "../narrowphase/decomposition/triangle_buffer_layout.js";
|
|
10
|
+
import { PosedShape } from "../narrowphase/PosedShape.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Scratch state — module-scoped to avoid per-query allocation. Safe
|
|
14
|
+
* because PhysicsSystem queries run on the main thread, sequentially.
|
|
15
|
+
*/
|
|
16
|
+
const local_aabb = new Float64Array(6);
|
|
17
|
+
const world_aabb = new Float64Array(6);
|
|
18
|
+
const concave_query_aabb = new Float64Array(6);
|
|
19
|
+
const simplex_buf = new Float64Array(12);
|
|
20
|
+
|
|
21
|
+
const query_posed = new PosedShape();
|
|
22
|
+
const candidate_posed = new PosedShape();
|
|
23
|
+
const triangle_shape = new Triangle3D();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Maximum triangles a concave candidate can emit per overlap pair.
|
|
27
|
+
* Same rationale as the narrowphase's `MAX_TRIANGLES_PER_PAIR`: the
|
|
28
|
+
* broadphase has already bounded the query AABB to the query shape's
|
|
29
|
+
* envelope, so a single candidate typically yields tens of triangles.
|
|
30
|
+
* Excess triangles are dropped by the enumerator's bounds check —
|
|
31
|
+
* worst case is a missed overlap on a far edge of the candidate's
|
|
32
|
+
* geometry, recovered next query.
|
|
33
|
+
* @type {number}
|
|
34
|
+
*/
|
|
35
|
+
const MAX_TRIANGLES_PER_PAIR = 1024;
|
|
36
|
+
|
|
37
|
+
const triangle_buffer = new Float64Array(MAX_TRIANGLES_PER_PAIR * TRIANGLE_FLOAT_STRIDE);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Broadphase candidate buffer. Grows by doubling on overflow.
|
|
41
|
+
* @type {Uint32Array}
|
|
42
|
+
*/
|
|
43
|
+
let scratch_candidates = new Uint32Array(64);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Test what bodies overlap a convex shape placed at a given pose. Each
|
|
47
|
+
* overlapping body's `body_id` is written to `output` starting at
|
|
48
|
+
* `output_offset`; the function returns the number of body ids written.
|
|
49
|
+
*
|
|
50
|
+
* Use case: speculative physics queries for kinematic / character
|
|
51
|
+
* controllers. An external system can ask "would my body collide with
|
|
52
|
+
* anything if I moved it here?" without committing a tick of
|
|
53
|
+
* simulation. The output is a flat list of body ids so the caller can
|
|
54
|
+
* decide what to do per hit (skip, push, slide, etc.).
|
|
55
|
+
*
|
|
56
|
+
* The pipeline mirrors the narrowphase pair test:
|
|
57
|
+
* 1. Build the query shape's world AABB.
|
|
58
|
+
* 2. Pull candidates from both broadphase trees that overlap that AABB.
|
|
59
|
+
* 3. For each candidate, run GJK in world frame. Convex candidates
|
|
60
|
+
* go through one GJK call; concave candidates (heightmap / mesh)
|
|
61
|
+
* go through the per-triangle decomposition path.
|
|
62
|
+
* 4. Apply the optional `filter` callback (same signature as in
|
|
63
|
+
* raycast / shapeCast) before the GJK test — early-out on bodies
|
|
64
|
+
* the caller already wants to skip (themselves, allies, etc.).
|
|
65
|
+
*
|
|
66
|
+
* The query shape must be convex (`is_convex === true`). Concave shapes
|
|
67
|
+
* are typically static terrain and not used as kinematic query
|
|
68
|
+
* probes; rejecting them avoids the M×N triangle-pair cost.
|
|
69
|
+
*
|
|
70
|
+
* @param {PhysicsSystem} system
|
|
71
|
+
* @param {AbstractShape3D} shape query shape, convex; expressed in
|
|
72
|
+
* its own local frame
|
|
73
|
+
* @param {{x:number,y:number,z:number}} position world position of the
|
|
74
|
+
* query shape
|
|
75
|
+
* @param {{x:number,y:number,z:number,w:number}} rotation world rotation
|
|
76
|
+
* of the query shape (unit quaternion)
|
|
77
|
+
* @param {Uint32Array|number[]} output buffer to write body_ids into.
|
|
78
|
+
* Caller is responsible for sizing it; ids past its end are dropped.
|
|
79
|
+
* @param {number} output_offset float-index in output to start writing at
|
|
80
|
+
* @param {(entity:number, collider:Collider)=>boolean} [filter]
|
|
81
|
+
* defaults to {@link returnTrue} (accept every candidate)
|
|
82
|
+
* @returns {number} number of overlapping bodies written
|
|
83
|
+
* @throws {Error} if `shape.is_convex === false`
|
|
84
|
+
*/
|
|
85
|
+
export function overlap_shape(system, shape, position, rotation, output, output_offset, filter = returnTrue) {
|
|
86
|
+
if (shape.is_convex === false) {
|
|
87
|
+
throw new Error(`overlap_shape: query shape must be convex; received \`${shape.constructor.name}\` (is_convex=false)`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── 1. Query shape's world AABB ─────────────────────────────────
|
|
91
|
+
shape.compute_bounding_box(local_aabb);
|
|
92
|
+
aabb3_transform_oriented(
|
|
93
|
+
world_aabb, 0,
|
|
94
|
+
local_aabb[0], local_aabb[1], local_aabb[2],
|
|
95
|
+
local_aabb[3], local_aabb[4], local_aabb[5],
|
|
96
|
+
position.x, position.y, position.z,
|
|
97
|
+
rotation.x, rotation.y, rotation.z, rotation.w
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// ── 2. Gather broadphase candidates ─────────────────────────────
|
|
101
|
+
const n_static = bvh_query_user_data_overlaps_aabb(
|
|
102
|
+
scratch_candidates, 0, system.staticBvh, world_aabb
|
|
103
|
+
);
|
|
104
|
+
const n_dynamic = bvh_query_user_data_overlaps_aabb(
|
|
105
|
+
scratch_candidates, n_static, system.dynamicBvh, world_aabb
|
|
106
|
+
);
|
|
107
|
+
const n_total = n_static + n_dynamic;
|
|
108
|
+
if (n_total === 0) return 0;
|
|
109
|
+
|
|
110
|
+
// ── 3. Set up query PosedShape (constant across candidates) ─────
|
|
111
|
+
query_posed.setup(shape, position, rotation);
|
|
112
|
+
|
|
113
|
+
// ── 4. Per-candidate narrowphase ────────────────────────────────
|
|
114
|
+
const output_capacity = output.length - output_offset;
|
|
115
|
+
let count = 0;
|
|
116
|
+
let cursor = output_offset;
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < n_total; i++) {
|
|
119
|
+
if (count >= output_capacity) break;
|
|
120
|
+
|
|
121
|
+
const body_id = scratch_candidates[i];
|
|
122
|
+
const body_idx = body_id_index(body_id);
|
|
123
|
+
|
|
124
|
+
const entity = system.entityOf(body_id);
|
|
125
|
+
if (entity < 0) continue;
|
|
126
|
+
|
|
127
|
+
const collider = system.__primary_collider(body_idx);
|
|
128
|
+
if (collider === null) continue;
|
|
129
|
+
if (!filter(entity, collider)) continue;
|
|
130
|
+
|
|
131
|
+
const candidate_tr = system.__transforms[body_idx];
|
|
132
|
+
|
|
133
|
+
let overlaps = false;
|
|
134
|
+
|
|
135
|
+
if (collider.shape.is_convex !== false) {
|
|
136
|
+
candidate_posed.setup(collider.shape, candidate_tr.position, candidate_tr.rotation);
|
|
137
|
+
overlaps = gjk(simplex_buf, query_posed, candidate_posed);
|
|
138
|
+
} else {
|
|
139
|
+
// Concave candidate: project the query's world AABB into
|
|
140
|
+
// the candidate's body-local frame, decompose to triangles,
|
|
141
|
+
// run per-triangle GJK until one overlap is found.
|
|
142
|
+
aabb_world_to_local(
|
|
143
|
+
concave_query_aabb, 0,
|
|
144
|
+
world_aabb,
|
|
145
|
+
candidate_tr.position.x, candidate_tr.position.y, candidate_tr.position.z,
|
|
146
|
+
candidate_tr.rotation.x, candidate_tr.rotation.y, candidate_tr.rotation.z, candidate_tr.rotation.w
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const tri_count = decompose_to_triangles(
|
|
150
|
+
triangle_buffer, 0, collider.shape,
|
|
151
|
+
concave_query_aabb[0], concave_query_aabb[1], concave_query_aabb[2],
|
|
152
|
+
concave_query_aabb[3], concave_query_aabb[4], concave_query_aabb[5]
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Re-pose candidate as the concave body, rebinding the
|
|
156
|
+
// flyweight triangle per iteration.
|
|
157
|
+
candidate_posed.shape = triangle_shape;
|
|
158
|
+
candidate_posed.px = candidate_tr.position.x;
|
|
159
|
+
candidate_posed.py = candidate_tr.position.y;
|
|
160
|
+
candidate_posed.pz = candidate_tr.position.z;
|
|
161
|
+
candidate_posed.qx = candidate_tr.rotation.x;
|
|
162
|
+
candidate_posed.qy = candidate_tr.rotation.y;
|
|
163
|
+
candidate_posed.qz = candidate_tr.rotation.z;
|
|
164
|
+
candidate_posed.qw = candidate_tr.rotation.w;
|
|
165
|
+
|
|
166
|
+
for (let t = 0; t < tri_count; t++) {
|
|
167
|
+
triangle_shape.bind(triangle_buffer, t * TRIANGLE_FLOAT_STRIDE);
|
|
168
|
+
if (gjk(simplex_buf, query_posed, candidate_posed)) {
|
|
169
|
+
overlaps = true;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (overlaps) {
|
|
176
|
+
output[cursor] = body_id;
|
|
177
|
+
cursor++;
|
|
178
|
+
count++;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return count;
|
|
183
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sweep a convex shape along a ray and find the first body it would
|
|
3
|
+
* hit. Used by character controllers (sweep a capsule along intended
|
|
4
|
+
* movement to find blockers), high-speed projectile movement (avoid
|
|
5
|
+
* tunnelling without paying for full per-body CCD), and any kinematic
|
|
6
|
+
* "where would this body end up if I tried to move it?" query.
|
|
7
|
+
*
|
|
8
|
+
* Pipeline:
|
|
9
|
+
* 1. Build the swept AABB: the shape's local-frame AABB rotated
|
|
10
|
+
* into world by `rotation`, translated to `ray.origin`, then
|
|
11
|
+
* stretched along `ray.direction * ray.tMax`.
|
|
12
|
+
* 2. Query both broadphase BVHs (static + dynamic) for leaves whose
|
|
13
|
+
* AABB overlaps the swept volume.
|
|
14
|
+
* 3. For each candidate, bisect the [0, best_t] interval for the
|
|
15
|
+
* smallest `t` at which the swept shape overlaps the candidate's
|
|
16
|
+
* collider. GJK on each midpoint.
|
|
17
|
+
*
|
|
18
|
+
* Picking `best_t` (rather than always running the full [0, tMax]
|
|
19
|
+
* bisection) is the early-termination optimisation: once we have a
|
|
20
|
+
* hit at some t, no later candidate can produce a smaller TOI by
|
|
21
|
+
* being checked at its full [0, tMax] interval.
|
|
22
|
+
*
|
|
23
|
+
* Output on hit:
|
|
24
|
+
* - `result.t` — sweep distance to impact (in the same units as
|
|
25
|
+
* `ray.direction`'s magnitude; for a unit-direction ray, this is
|
|
26
|
+
* metres).
|
|
27
|
+
* - `result.position` — `ray.origin + t * ray.direction`, i.e. the
|
|
28
|
+
* centre of the swept shape at the moment of first contact. NOT
|
|
29
|
+
* a point on the target's surface; that would need narrowphase
|
|
30
|
+
* refinement which the broadphase-only architecture doesn't have
|
|
31
|
+
* wired up yet.
|
|
32
|
+
* - `result.normal` — target surface's outward normal at the kiss
|
|
33
|
+
* point (unit length), computed by running GJK + EPA against the
|
|
34
|
+
* just-overlapping configuration at the TOI. Falls back to
|
|
35
|
+
* `-ray.direction` on the rare case EPA degenerates (NaN / zero
|
|
36
|
+
* depth) — see comment near the EPA call.
|
|
37
|
+
* - `result.entity` / `result.body_id` — the hit body.
|
|
38
|
+
*
|
|
39
|
+
* Output on miss: untouched; same convention as `raycast`.
|
|
40
|
+
*
|
|
41
|
+
* @param {PhysicsSystem} system
|
|
42
|
+
* @param {Ray3} ray origin + unit direction + `tMax`
|
|
43
|
+
* @param {AbstractShape3D} shape shape being swept, in its local frame
|
|
44
|
+
* @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
|
|
45
|
+
* @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
|
|
46
|
+
* @param {(entity:number, collider:Collider)=>boolean} [filter] mandatory in
|
|
47
|
+
* contract; defaults to {@link returnTrue}
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
export function shape_cast(system: PhysicsSystem, ray: Ray3, shape: AbstractShape3D, rotation: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
z: number;
|
|
54
|
+
w: number;
|
|
55
|
+
}, result: PhysicsSurfacePoint, filter?: (entity: number, collider: Collider) => boolean): boolean;
|
|
56
|
+
//# sourceMappingURL=shape_cast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape_cast.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/queries/shape_cast.js"],"names":[],"mappings":"AAwEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,+FANW;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,iDAE7B,MAAM,yBAAsB,OAAO,GAEzC,OAAO,CA2QnB"}
|