@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.
Files changed (172) hide show
  1. package/package.json +1 -1
  2. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts +3 -3
  3. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts.map +1 -1
  4. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js +4 -4
  5. package/src/{engine/physics/broadphase/aabb_transform_oriented.d.ts → core/geom/3d/aabb/aabb3_transform_oriented.d.ts} +2 -2
  6. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -0
  7. package/src/{engine/physics/broadphase/aabb_transform_oriented.js → core/geom/3d/aabb/aabb3_transform_oriented.js} +1 -1
  8. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +54 -0
  9. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -0
  10. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -0
  11. package/src/core/geom/3d/shape/AbstractShape3D.d.ts +24 -2
  12. package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
  13. package/src/core/geom/3d/shape/AbstractShape3D.js +24 -1
  14. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +148 -0
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -0
  16. package/src/core/geom/3d/shape/HeightMapShape3D.js +451 -0
  17. package/src/core/geom/3d/shape/MeshShape3D.d.ts +210 -0
  18. package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -0
  19. package/src/core/geom/3d/shape/MeshShape3D.js +593 -0
  20. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  21. package/src/core/geom/3d/shape/TransformedShape3D.js +46 -2
  22. package/src/core/geom/3d/shape/Triangle3D.d.ts +95 -0
  23. package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -0
  24. package/src/core/geom/3d/shape/Triangle3D.js +318 -0
  25. package/src/core/geom/3d/shape/UnionShape3D.js +13 -0
  26. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +30 -0
  27. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +64 -0
  29. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +9 -11
  30. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts +28 -0
  31. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map +1 -0
  32. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -0
  33. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
  34. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +40 -18
  35. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +9 -5
  36. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -1
  37. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +38 -10
  38. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +14 -5
  39. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -1
  40. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +47 -5
  41. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +19 -0
  42. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
  43. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +75 -13
  44. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +2 -2
  45. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +1 -1
  46. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +1 -1
  47. package/src/core/geom/vec3/v3_dot_array_array.d.ts +3 -3
  48. package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
  49. package/src/core/geom/vec3/v3_dot_array_array.js +2 -2
  50. package/src/core/geom/vec3/v3_negate_array.d.ts +3 -3
  51. package/src/core/geom/vec3/v3_negate_array.d.ts.map +1 -1
  52. package/src/core/geom/vec3/v3_negate_array.js +2 -2
  53. package/src/core/geom/vec3/v3_quat3_apply.d.ts +29 -0
  54. package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +1 -0
  55. package/src/core/geom/vec3/v3_quat3_apply.js +39 -0
  56. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +30 -0
  57. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +1 -0
  58. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +41 -0
  59. package/src/core/geom/vec3/v3_triple_cross_product.d.ts +32 -0
  60. package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +1 -0
  61. package/src/core/geom/vec3/v3_triple_cross_product.js +45 -0
  62. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +16 -3
  63. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  64. package/src/engine/control/first-person/FirstPersonPlayerController.js +211 -211
  65. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +72 -8
  66. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  67. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +37 -5
  68. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +101 -3
  69. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  70. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1789 -1416
  71. package/src/engine/control/first-person/TODO.md +173 -127
  72. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
  73. package/src/engine/control/first-person/abilities/Slide.js +9 -1
  74. package/src/engine/control/first-person/prototype_first_person_controller.js +88 -2
  75. package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -1
  76. package/src/engine/control/first-person/test/buildTestPlayer.js +9 -1
  77. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts +42 -0
  78. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts.map +1 -0
  79. package/src/engine/graphics/geometry/CapsuleGeometry.js +171 -0
  80. package/src/engine/physics/BULLET_REVIEW.md +945 -0
  81. package/src/engine/physics/CANNON_REVIEW.md +1300 -0
  82. package/src/engine/physics/JOLT_REVIEW.md +913 -0
  83. package/src/engine/physics/PLAN.md +461 -236
  84. package/src/engine/physics/RAPIER_REVIEW.md +934 -0
  85. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -0
  86. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +2 -2
  87. package/src/engine/physics/contact/ManifoldStore.d.ts +83 -10
  88. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  89. package/src/engine/physics/contact/ManifoldStore.js +608 -499
  90. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +2 -2
  91. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -1
  92. package/src/engine/physics/ecs/PhysicsSystem.d.ts +128 -20
  93. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  94. package/src/engine/physics/ecs/PhysicsSystem.js +1301 -1159
  95. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  96. package/src/engine/physics/fluid/FluidSimulator.js +2 -1
  97. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +28 -6
  98. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  99. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +39 -17
  100. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +6 -6
  101. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
  102. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +68 -22
  103. package/src/engine/physics/gjk/gjk.d.ts +28 -2
  104. package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
  105. package/src/engine/physics/gjk/gjk.js +421 -378
  106. package/src/engine/physics/gjk/minkowski_support.d.ts +37 -0
  107. package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -0
  108. package/src/engine/physics/gjk/minkowski_support.js +75 -0
  109. package/src/engine/physics/gjk/mpr.d.ts +56 -0
  110. package/src/engine/physics/gjk/mpr.d.ts.map +1 -0
  111. package/src/engine/physics/gjk/mpr.js +344 -0
  112. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +20 -5
  113. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  114. package/src/engine/physics/inertia/world_inverse_inertia.js +36 -38
  115. package/src/engine/physics/integration/integrate_position.d.ts +25 -7
  116. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
  117. package/src/engine/physics/integration/integrate_position.js +43 -12
  118. package/src/engine/physics/integration/integrate_velocity.d.ts +30 -0
  119. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  120. package/src/engine/physics/integration/integrate_velocity.js +82 -1
  121. package/src/engine/physics/narrowphase/PosedShape.d.ts +0 -8
  122. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -1
  123. package/src/engine/physics/narrowphase/PosedShape.js +28 -30
  124. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  125. package/src/engine/physics/narrowphase/box_box_manifold.js +113 -17
  126. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +30 -0
  127. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -0
  128. package/src/engine/physics/narrowphase/box_triangle_contact.js +811 -0
  129. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  130. package/src/engine/physics/narrowphase/capsule_contacts.js +10 -56
  131. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +71 -0
  132. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -0
  133. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +375 -0
  134. package/src/engine/physics/narrowphase/compute_penetration.d.ts +91 -0
  135. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -0
  136. package/src/engine/physics/narrowphase/compute_penetration.js +396 -0
  137. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts +35 -0
  138. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +1 -0
  139. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.js +80 -0
  140. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +31 -0
  141. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -0
  142. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -0
  143. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +42 -0
  144. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -0
  145. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +204 -0
  146. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +42 -0
  147. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -0
  148. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +94 -0
  149. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +37 -0
  150. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -0
  151. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -0
  152. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +8 -2
  153. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  154. package/src/engine/physics/narrowphase/narrowphase_step.js +1422 -382
  155. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  156. package/src/engine/physics/narrowphase/sphere_box_contact.js +16 -23
  157. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +48 -0
  158. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -0
  159. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +143 -0
  160. package/src/engine/physics/queries/overlap_shape.d.ts +51 -0
  161. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -0
  162. package/src/engine/physics/queries/overlap_shape.js +183 -0
  163. package/src/engine/physics/queries/shape_cast.d.ts +56 -0
  164. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -0
  165. package/src/engine/physics/queries/shape_cast.js +387 -0
  166. package/src/engine/physics/solver/solve_contacts.d.ts +116 -30
  167. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  168. package/src/engine/physics/solver/solve_contacts.js +641 -223
  169. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +0 -1
  170. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +0 -20
  171. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +0 -1
  172. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +0 -83
@@ -1 +1 @@
1
- {"version":3,"file":"FluidSimulator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/fluid/FluidSimulator.js"],"names":[],"mappings":";;;;;;;;;;;;;;;6BAyBU,MAAM;;;;;AAOhB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;;;;;;;;;GASG;AACH,wCAFU,MAAM,CAE2B;AAE3C;IAEI;;;OAGG;IACH,yBAFU,MAAM,CAEY;IAE5B;;;;OAIG;IACH,+BAFU,MAAM,CAEkB;IAElC;;;;;OAKG;IACH,uBAFU,MAAM,CAEU;IAE1B;;OAEG;IACH,6BAFU,MAAM,CAEgB;IAEhC;;;;;;;;;;;;;;;OAeG;IACH,iBAFU,MAAM,CAEqB;IAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,0BAFU,OAAO,CAEe;IAEhC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,0BAFU,MAAM,CAEgB;IA+EhC;;;;;;;;;;;;OAYG;IACH,iCALW,MAAM,SACN,MAAM,SACN,MAAM,GACL,MAAM,CAUjB;IAED;;;;;;OAMG;IACH,iCAkDC;IAqBD;;;;;;;;;;;;;OAaG;IACH,oCAVW,MAAM,aAEN,uBAAuB,iBACvB,YAAY,GAAC,MAAM,EAAE,QAyF/B;;CACJ"}
1
+ {"version":3,"file":"FluidSimulator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/fluid/FluidSimulator.js"],"names":[],"mappings":";;;;;;;;;;;;;;;6BAyBU,MAAM;;;;;AAOhB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;;;;;;;;;GASG;AACH,wCAFU,MAAM,CAE2B;AAE3C;IAEI;;;OAGG;IACH,yBAFU,MAAM,CAEY;IAE5B;;;;OAIG;IACH,+BAFU,MAAM,CAEkB;IAElC;;;;;OAKG;IACH,uBAFU,MAAM,CAEU;IAE1B;;OAEG;IACH,6BAFU,MAAM,CAEgB;IAEhC;;;;;;;;;;;;;;;OAeG;IACH,iBAFU,MAAM,CAEqB;IAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,0BAFU,OAAO,CAEe;IAEhC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,0BAFU,MAAM,CAEgB;IA+EhC;;;;;;;;;;;;OAYG;IACH,iCALW,MAAM,SACN,MAAM,SACN,MAAM,GACL,MAAM,CAUjB;IAED;;;;;;OAMG;IACH,iCAmDC;IAqBD;;;;;;;;;;;;;OAaG;IACH,oCAVW,MAAM,aAEN,uBAAuB,iBACvB,YAAY,GAAC,MAAM,EAAE,QAyF/B;;CACJ"}
@@ -332,7 +332,8 @@ export class FluidSimulator {
332
332
  field.velocity_x, field.velocity_y, field.velocity_z,
333
333
  field.pressure,
334
334
  res[0], res[1], res[2],
335
- solid
335
+ solid,
336
+ field.solid_neighbour_mask
336
337
  );
337
338
  }
338
339
 
@@ -13,14 +13,36 @@
13
13
  * pressure (consistent with the Neumann condition used in the solve), which keeps the
14
14
  * flow tangent to the boundary.
15
15
  *
16
- * @param {Float32Array} vel_x Mutated in place.
17
- * @param {Float32Array} vel_y Mutated in place.
18
- * @param {Float32Array} vel_z Mutated in place.
19
- * @param {Float32Array} pressure From {@link v3_grid_solve_pressure}.
16
+ * Which neighbours count as fluid is read straight from `neighbour_mask`, the same
17
+ * pre-baked per-cell bitmask {@link v3_grid_solve_pressure} consumes (populated by
18
+ * {@link FluidField.recomputeSolidNeighbourMask}). A set bit means "that neighbour is
19
+ * fluid (in-bounds AND non-solid)", so a clear bit reflects the cell's own pressure
20
+ * folding the boundary check and the solid-neighbour check into one register-resident
21
+ * bit-test per face. Encoding:
22
+ *
23
+ * bit 0 (= 1) : -x neighbour is fluid
24
+ * bit 1 (= 2) : +x neighbour is fluid
25
+ * bit 2 (= 4) : -y neighbour is fluid
26
+ * bit 3 (= 8) : +y neighbour is fluid
27
+ * bit 4 (= 16) : -z neighbour is fluid
28
+ * bit 5 (= 32) : +z neighbour is fluid
29
+ *
30
+ * Unlike the solve, the mask can't drive the self-cell branch: both a solid cell and
31
+ * an isolated fluid cell (no fluid neighbours) encode as `mask = 0`, yet they need
32
+ * opposite handling — the solid must be zeroed for no-slip, while the isolated fluid's
33
+ * gradient already nets to zero (every face reflects its own pressure) and must be
34
+ * left alone. `solid` is what tells them apart, so it stays.
35
+ *
36
+ * @param {Float32Array} vel_x Mutated in place.
37
+ * @param {Float32Array} vel_y Mutated in place.
38
+ * @param {Float32Array} vel_z Mutated in place.
39
+ * @param {Float32Array} pressure From {@link v3_grid_solve_pressure}.
20
40
  * @param {number} res_x
21
41
  * @param {number} res_y
22
42
  * @param {number} res_z
23
- * @param {Uint8Array} solid Required (zero-filled for a wall-free domain).
43
+ * @param {Uint8Array} solid Required (zero-filled for a wall-free domain).
44
+ * @param {Uint8Array} neighbour_mask Length ≥ res_x*res_y*res_z. Same buffer the
45
+ * pressure solve uses; MUST be recomputed whenever `solid` changes.
24
46
  */
25
- export function v3_grid_subtract_pressure_gradient(vel_x: Float32Array, vel_y: Float32Array, vel_z: Float32Array, pressure: Float32Array, res_x: number, res_y: number, res_z: number, solid: Uint8Array): void;
47
+ export function v3_grid_subtract_pressure_gradient(vel_x: Float32Array, vel_y: Float32Array, vel_z: Float32Array, pressure: Float32Array, res_x: number, res_y: number, res_z: number, solid: Uint8Array, neighbour_mask: Uint8Array): void;
26
48
  //# sourceMappingURL=v3_grid_subtract_pressure_gradient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"v3_grid_subtract_pressure_gradient.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,0DATW,YAAY,SACZ,YAAY,SACZ,YAAY,YACZ,YAAY,SACZ,MAAM,SACN,MAAM,SACN,MAAM,SACN,UAAU,QA6CpB"}
1
+ {"version":3,"file":"v3_grid_subtract_pressure_gradient.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,0DAXW,YAAY,SACZ,YAAY,SACZ,YAAY,YACZ,YAAY,SACZ,MAAM,SACN,MAAM,SACN,MAAM,SACN,UAAU,kBACV,UAAU,QA8CpB"}
@@ -15,26 +15,46 @@ import { assert } from "../../../../core/assert.js";
15
15
  * pressure (consistent with the Neumann condition used in the solve), which keeps the
16
16
  * flow tangent to the boundary.
17
17
  *
18
- * @param {Float32Array} vel_x Mutated in place.
19
- * @param {Float32Array} vel_y Mutated in place.
20
- * @param {Float32Array} vel_z Mutated in place.
21
- * @param {Float32Array} pressure From {@link v3_grid_solve_pressure}.
18
+ * Which neighbours count as fluid is read straight from `neighbour_mask`, the same
19
+ * pre-baked per-cell bitmask {@link v3_grid_solve_pressure} consumes (populated by
20
+ * {@link FluidField.recomputeSolidNeighbourMask}). A set bit means "that neighbour is
21
+ * fluid (in-bounds AND non-solid)", so a clear bit reflects the cell's own pressure
22
+ * folding the boundary check and the solid-neighbour check into one register-resident
23
+ * bit-test per face. Encoding:
24
+ *
25
+ * bit 0 (= 1) : -x neighbour is fluid
26
+ * bit 1 (= 2) : +x neighbour is fluid
27
+ * bit 2 (= 4) : -y neighbour is fluid
28
+ * bit 3 (= 8) : +y neighbour is fluid
29
+ * bit 4 (= 16) : -z neighbour is fluid
30
+ * bit 5 (= 32) : +z neighbour is fluid
31
+ *
32
+ * Unlike the solve, the mask can't drive the self-cell branch: both a solid cell and
33
+ * an isolated fluid cell (no fluid neighbours) encode as `mask = 0`, yet they need
34
+ * opposite handling — the solid must be zeroed for no-slip, while the isolated fluid's
35
+ * gradient already nets to zero (every face reflects its own pressure) and must be
36
+ * left alone. `solid` is what tells them apart, so it stays.
37
+ *
38
+ * @param {Float32Array} vel_x Mutated in place.
39
+ * @param {Float32Array} vel_y Mutated in place.
40
+ * @param {Float32Array} vel_z Mutated in place.
41
+ * @param {Float32Array} pressure From {@link v3_grid_solve_pressure}.
22
42
  * @param {number} res_x
23
43
  * @param {number} res_y
24
44
  * @param {number} res_z
25
- * @param {Uint8Array} solid Required (zero-filled for a wall-free domain).
45
+ * @param {Uint8Array} solid Required (zero-filled for a wall-free domain).
46
+ * @param {Uint8Array} neighbour_mask Length ≥ res_x*res_y*res_z. Same buffer the
47
+ * pressure solve uses; MUST be recomputed whenever `solid` changes.
26
48
  */
27
- export function v3_grid_subtract_pressure_gradient(vel_x, vel_y, vel_z, pressure, res_x, res_y, res_z, solid) {
49
+ export function v3_grid_subtract_pressure_gradient(vel_x, vel_y, vel_z, pressure, res_x, res_y, res_z, solid, neighbour_mask) {
28
50
  const cell_count = res_x * res_y * res_z;
29
51
  assert.greaterThanOrEqual(vel_x.length, cell_count, "vel_x covers grid");
30
52
  assert.greaterThanOrEqual(vel_y.length, cell_count, "vel_y covers grid");
31
53
  assert.greaterThanOrEqual(vel_z.length, cell_count, "vel_z covers grid");
32
54
  assert.greaterThanOrEqual(pressure.length, cell_count, "pressure covers grid");
55
+ assert.greaterThanOrEqual(neighbour_mask.length, cell_count, "neighbour_mask covers grid");
33
56
 
34
57
  const slice_size = res_x * res_y;
35
- const last_x = res_x - 1;
36
- const last_y = res_y - 1;
37
- const last_z = res_z - 1;
38
58
 
39
59
  for (let z = 0; z < res_z; z++) {
40
60
  const z_off = z * slice_size;
@@ -52,14 +72,16 @@ export function v3_grid_subtract_pressure_gradient(vel_x, vel_y, vel_z, pressure
52
72
  continue;
53
73
  }
54
74
 
55
- // Reflect pressure across a solid neighbour: that face contributes 0
56
- // to the gradient, consistent with ∂p/∂n = 0 at the wall.
57
- const p_xm = (x > 0 && solid[c - 1] === 0) ? pressure[c - 1] : pressure[c];
58
- const p_xp = (x < last_x && solid[c + 1] === 0) ? pressure[c + 1] : pressure[c];
59
- const p_ym = (y > 0 && solid[c - res_x] === 0) ? pressure[c - res_x] : pressure[c];
60
- const p_yp = (y < last_y && solid[c + res_x] === 0) ? pressure[c + res_x] : pressure[c];
61
- const p_zm = (z > 0 && solid[c - slice_size] === 0) ? pressure[c - slice_size] : pressure[c];
62
- const p_zp = (z < last_z && solid[c + slice_size] === 0) ? pressure[c + slice_size] : pressure[c];
75
+ // A clear bit means the neighbour is out-of-bounds or solid; reflect
76
+ // the cell's own pressure so that face contributes 0 to the gradient,
77
+ // consistent with ∂p/∂n = 0 at the wall.
78
+ const mask = neighbour_mask[c];
79
+ const p_xm = (mask & 1) ? pressure[c - 1] : pressure[c];
80
+ const p_xp = (mask & 2) ? pressure[c + 1] : pressure[c];
81
+ const p_ym = (mask & 4) ? pressure[c - res_x] : pressure[c];
82
+ const p_yp = (mask & 8) ? pressure[c + res_x] : pressure[c];
83
+ const p_zm = (mask & 16) ? pressure[c - slice_size] : pressure[c];
84
+ const p_zp = (mask & 32) ? pressure[c + slice_size] : pressure[c];
63
85
 
64
86
  vel_x[c] -= 0.5 * (p_xp - p_xm);
65
87
  vel_y[c] -= 0.5 * (p_yp - p_ym);
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * TODO: needs to be tested thoroughly, intended to be working with GJK
3
- * @param {number[]} result
3
+ * @param {number[]|Float64Array} result
4
4
  * @param {number} result_offset
5
- * @param {number[]} a
6
- * @param {number[]} b
7
- * @param {number[]} c
8
- * @param {number[]} d
5
+ * @param {number[]|Float64Array} a
6
+ * @param {number[]|Float64Array} b
7
+ * @param {number[]|Float64Array} c
8
+ * @param {number[]|Float64Array} d
9
9
  * @param {AbstractShape3D} coll1
10
10
  * @param {AbstractShape3D} coll2
11
11
  */
12
- export function expanding_polytope_algorithm(result: number[], result_offset: number, a: number[], b: number[], c: number[], d: number[], coll1: AbstractShape3D, coll2: AbstractShape3D): void;
12
+ export function expanding_polytope_algorithm(result: number[] | Float64Array, result_offset: number, a: number[] | Float64Array, b: number[] | Float64Array, c: number[] | Float64Array, d: number[] | Float64Array, coll1: AbstractShape3D, coll2: AbstractShape3D): void;
13
13
  //# sourceMappingURL=expanding_polytope_algorithm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expanding_polytope_algorithm.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/gjk/expanding_polytope_algorithm.js"],"names":[],"mappings":"AAgEA;;;;;;;;;;GAUG;AACH,qDATW,MAAM,EAAE,iBACR,MAAM,KACN,MAAM,EAAE,KACR,MAAM,EAAE,KACR,MAAM,EAAE,KACR,MAAM,EAAE,wDA8PlB"}
1
+ {"version":3,"file":"expanding_polytope_algorithm.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/gjk/expanding_polytope_algorithm.js"],"names":[],"mappings":"AAqGA;;;;;;;;;;GAUG;AACH,qDATW,MAAM,EAAE,GAAC,YAAY,iBACrB,MAAM,KACN,MAAM,EAAE,GAAC,YAAY,KACrB,MAAM,EAAE,GAAC,YAAY,KACrB,MAAM,EAAE,GAAC,YAAY,KACrB,MAAM,EAAE,GAAC,YAAY,wDAuQ/B"}
@@ -1,4 +1,3 @@
1
- import { assert } from "../../../core/assert.js";
2
1
  import { array_copy } from "../../../core/collection/array/array_copy.js";
3
2
  import { array_swap } from "../../../core/collection/array/array_swap.js";
4
3
  import { v3_compute_triangle_normal } from "../../../core/geom/3d/triangle/v3_compute_triangle_normal.js";
@@ -7,7 +6,30 @@ import { v3_dot_array_array } from "../../../core/geom/vec3/v3_dot_array_array.j
7
6
 
8
7
  import { v3_negate_array } from "../../../core/geom/vec3/v3_negate_array.js";
9
8
 
10
- const EPA_TOLERANCE = 0.0001;
9
+ /**
10
+ * Convergence tolerance — relative to the current closest-face distance,
11
+ * floored at an absolute epsilon to prevent zero-distance loops.
12
+ *
13
+ * Why relative, not absolute (P2.2). An absolute `EPA_TOLERANCE = 1e-4`
14
+ * works for mid-scale contacts (a few millimetres deep on metre-sized
15
+ * bodies) but degrades for shallow contacts: when the closest-face
16
+ * distance is ~1e-5 m (sub-mm overlaps that the speculative-margin path
17
+ * handles), `1e-4` is *larger than the depth itself*, so EPA terminates
18
+ * with whatever intermediate face it happens to have, producing a noisy
19
+ * normal direction. Jolt's `EPSILON_REL_DIST_SQ` and similar
20
+ * formulations scale tolerance with the current distance.
21
+ *
22
+ * Note: only the TOLERANCE was made relative as part of P2.2. The
23
+ * convergence-path RESULT magnitude is intentionally left as
24
+ * `dot_p_search_dir` (the new support point's projection) — switching
25
+ * to `min_dist` was tried and caused energy injection in the closed-
26
+ * form-dispatch paths that share the EPA depth metric (e.g.
27
+ * sphere-vs-sphere stack regressions). See REVIEW_001_ACTION_PLAN.md.
28
+ *
29
+ * @type {number}
30
+ */
31
+ const EPA_TOLERANCE_REL = 1e-4;
32
+ const EPA_TOLERANCE_ABS = 1e-6;
11
33
  const EPA_MAX_NUM_FACES = 64;
12
34
  const EPA_MAX_NUM_LOOSE_EDGES = 32;
13
35
  const EPA_MAX_NUM_ITERATIONS = 64;
@@ -16,16 +38,31 @@ const FACE_ELEMENT_COUNT = 3 * 4;
16
38
 
17
39
  const EDGE_ELEMENT_COUNT = 2 * 3;
18
40
 
19
- //Array of faces, each with 3 verts and a normal
20
- const faces = new Float32Array(EPA_MAX_NUM_FACES * FACE_ELEMENT_COUNT);
41
+ /**
42
+ * Polytope face buffer. Float64 throughout — EPA's expand-and-recompute
43
+ * step iterates up to {@link EPA_MAX_NUM_ITERATIONS} times, each
44
+ * iteration rebuilds face normals via cross products, and tests them
45
+ * against accumulated support points; the per-iteration error in
46
+ * Float32 compounds and noticeably slows convergence on shapes with
47
+ * many similar-magnitude faces (anything with subtle curvature). The
48
+ * memory footprint of the upgrade is the buffer's size doubling — a
49
+ * few KB at most.
50
+ *
51
+ * Layout per face: 3 vec3 vertices + 1 vec3 normal = 12 floats.
52
+ * @type {Float64Array}
53
+ */
54
+ const faces = new Float64Array(EPA_MAX_NUM_FACES * FACE_ELEMENT_COUNT);
21
55
 
22
56
  /**
23
- * keep track of edges we need to fix after removing faces
24
- * @type {Float32Array}
57
+ * Edges we need to fix after removing faces. Same Float64 motivation
58
+ * as {@link faces} — endpoints are vertex coords pulled out of `faces`,
59
+ * and any precision loss here propagates back into the next face when
60
+ * the polytope is rebuilt.
61
+ * @type {Float64Array}
25
62
  */
26
- const loose_edges = new Float32Array(EPA_MAX_NUM_LOOSE_EDGES * EDGE_ELEMENT_COUNT);
63
+ const loose_edges = new Float64Array(EPA_MAX_NUM_LOOSE_EDGES * EDGE_ELEMENT_COUNT);
27
64
 
28
- const scratch_v3 = new Float32Array(3);
65
+ const scratch_v3 = new Float64Array(3);
29
66
 
30
67
  /**
31
68
  *
@@ -39,7 +76,7 @@ function write_v3(target, target_index, v) {
39
76
 
40
77
  /**
41
78
  *
42
- * @param {number[]|Float32Array} faces
79
+ * @param {number[]|Float64Array} faces
43
80
  * @param {number} index
44
81
  * @param {number[]} a
45
82
  * @param {number[]} b
@@ -64,12 +101,12 @@ function write_face(faces, index, a, b, c) {
64
101
 
65
102
  /**
66
103
  * TODO: needs to be tested thoroughly, intended to be working with GJK
67
- * @param {number[]} result
104
+ * @param {number[]|Float64Array} result
68
105
  * @param {number} result_offset
69
- * @param {number[]} a
70
- * @param {number[]} b
71
- * @param {number[]} c
72
- * @param {number[]} d
106
+ * @param {number[]|Float64Array} a
107
+ * @param {number[]|Float64Array} b
108
+ * @param {number[]|Float64Array} c
109
+ * @param {number[]|Float64Array} d
73
110
  * @param {AbstractShape3D} coll1
74
111
  * @param {AbstractShape3D} coll2
75
112
  */
@@ -117,10 +154,6 @@ export function expanding_polytope_algorithm(
117
154
  const search_dir_y = faces[closest_face_normal_offset + 1];
118
155
  const search_dir_z = faces[closest_face_normal_offset + 2];
119
156
 
120
- if (search_dir_x === 0 && search_dir_y === 0 && search_dir_z === 0) {
121
- debugger;
122
- }
123
-
124
157
  // build new support point to expand polytope
125
158
 
126
159
  coll2.support(scratch_v3, 0, search_dir_x, search_dir_y, search_dir_z);
@@ -141,7 +174,14 @@ export function expanding_polytope_algorithm(
141
174
 
142
175
  const dot_p_search_dir = v3_dot(p_x, p_y, p_z, search_dir_x, search_dir_y, search_dir_z);
143
176
 
144
- if (dot_p_search_dir - min_dist < EPA_TOLERANCE) {
177
+ // Adaptive convergence (P2.2). Terminate when the new support
178
+ // point's projection onto the current search direction is
179
+ // within a RELATIVE tolerance of the current closest-face
180
+ // distance — scales with depth instead of the fixed absolute
181
+ // EPA_TOLERANCE = 1e-4 that was too coarse for sub-mm contacts.
182
+ const min_dist_abs = min_dist < 0 ? -min_dist : min_dist;
183
+ const tol_floor = min_dist_abs > EPA_TOLERANCE_ABS ? min_dist_abs : EPA_TOLERANCE_ABS;
184
+ if (dot_p_search_dir - min_dist < EPA_TOLERANCE_REL * tol_floor) {
145
185
  //Convergence (new point is not significantly further from origin)
146
186
 
147
187
  result[result_offset] = search_dir_x * dot_p_search_dir;
@@ -311,9 +351,15 @@ export function expanding_polytope_algorithm(
311
351
  }
312
352
  }
313
353
 
314
- console.warn("EPA did not converge");
315
-
316
- //Return most recent closest point
354
+ // Iteration cap reached without convergence. Return the
355
+ // closest-face approximation rather than warning — this is the
356
+ // expected outcome on smooth / high-complexity shapes (a torus knot
357
+ // collider produces it dozens of times per frame while the player
358
+ // is in contact). The narrowphase consumer treats any depth that
359
+ // isn't strictly positive + finite as a miss, so a degenerate
360
+ // closest-face result is filtered upstream. PLAN.md already lists
361
+ // EPA-on-smooth-shapes as a known limitation; the actionable fix
362
+ // is MPR / hierarchical support, not console spam.
317
363
  const closest_face_offset = closest_face * FACE_ELEMENT_COUNT;
318
364
  const closest_face_normal_offset = closest_face_offset + 3 * 3;
319
365
 
@@ -7,10 +7,36 @@
7
7
  *
8
8
  * Adapted from https://github.com/kevinmoran/GJK/blob/master/GJK.h
9
9
  *
10
- * @param {number[]|Float32Array} simplex Working buffer for simplex vertices (4 vec3s). Must have length >= 12.
10
+ * @param {number[]|Float64Array} simplex Working buffer for simplex vertices (4 vec3s). Must have length >= 12.
11
11
  * @param {AbstractShape3D} shape_a
12
12
  * @param {AbstractShape3D} shape_b
13
13
  * @returns {boolean} true if the shapes intersect
14
14
  */
15
- export function gjk(simplex: number[] | Float32Array, shape_a: AbstractShape3D, shape_b: AbstractShape3D): boolean;
15
+ export function gjk(simplex: number[] | Float64Array, shape_a: AbstractShape3D, shape_b: AbstractShape3D): boolean;
16
+ /**
17
+ * Separating-axis-cached variant of {@link gjk}. The 3 floats at
18
+ * `axis_buffer[axis_offset..+2]` are used as the initial search
19
+ * direction (seed) AND are overwritten with the final search direction
20
+ * on exit. The narrowphase keeps a per-manifold-slot cache of these
21
+ * three floats so quiescent contacts converge in 1–2 iterations next
22
+ * frame instead of ~6–10 from a cold `(1, 0, 0)` start (Bullet's
23
+ * `m_cachedSeparatingAxis` and Jolt's `ioV` use the same pattern).
24
+ *
25
+ * The same primitive doubles as a separating-axis cache for the
26
+ * "no-overlap" path: when GJK returns false, the final direction is
27
+ * roughly the separating axis, and next frame's first iteration
28
+ * detects separation immediately.
29
+ *
30
+ * Writeback is automatic — `gjk_core` mutates a `subarray` view of
31
+ * `axis_buffer`, so on return `axis_buffer[axis_offset..+2]` holds the
32
+ * final direction. No try/finally needed.
33
+ *
34
+ * @param {number[]|Float64Array} simplex
35
+ * @param {AbstractShape3D} shape_a
36
+ * @param {AbstractShape3D} shape_b
37
+ * @param {Float64Array} axis_buffer
38
+ * @param {number} axis_offset
39
+ * @returns {boolean}
40
+ */
41
+ export function gjk_with_axis(simplex: number[] | Float64Array, shape_a: AbstractShape3D, shape_b: AbstractShape3D, axis_buffer: Float64Array, axis_offset: number): boolean;
16
42
  //# sourceMappingURL=gjk.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gjk.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/gjk/gjk.js"],"names":[],"mappings":"AAmDA;;;;;;;;;;;;;GAaG;AACH,6BALW,MAAM,EAAE,GAAC,YAAY,uDAGnB,OAAO,CAkGnB"}
1
+ {"version":3,"file":"gjk.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/gjk/gjk.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;GAaG;AACH,6BALW,MAAM,EAAE,GAAC,YAAY,uDAGnB,OAAO,CAWnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,uCAPW,MAAM,EAAE,GAAC,YAAY,mEAGrB,YAAY,eACZ,MAAM,GACJ,OAAO,CAqBnB"}