@woosh/meep-engine 3.37.0 → 3.38.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 (106) hide show
  1. package/package.json +1 -1
  2. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  3. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +2 -0
  4. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts +11 -0
  5. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts.map +1 -0
  6. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.js +10 -0
  7. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  8. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +16 -0
  9. package/src/engine/graphics/ecs/water/Water.d.ts +30 -0
  10. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  11. package/src/engine/graphics/ecs/water/Water.js +125 -104
  12. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  13. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +13 -1
  14. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts +6 -0
  15. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts.map +1 -0
  16. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.js +18 -0
  17. package/src/engine/graphics3/WaterSystem.d.ts +22 -6
  18. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  19. package/src/engine/graphics3/WaterSystem.js +314 -293
  20. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +13 -14
  21. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  22. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +137 -36
  23. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +30 -0
  24. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
  25. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +33 -0
  26. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +2 -1
  27. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +10 -1
  28. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  29. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +36 -14
  30. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +15 -2
  31. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  32. package/src/engine/physics/cloth/ecs/ClothInstance.js +17 -2
  33. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  34. package/src/engine/physics/cloth/ecs/ClothWorld.js +19 -6
  35. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +18 -20
  36. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  37. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +139 -89
  38. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  39. package/src/engine/physics/ecs/PhysicsSystem.js +32 -16
  40. package/src/shade/playground/water_refraction/README.md +149 -0
  41. package/src/shade/playground/water_refraction/index.html +42 -0
  42. package/src/shade/playground/water_refraction/main.d.ts +2 -0
  43. package/src/shade/playground/water_refraction/main.d.ts.map +1 -0
  44. package/src/shade/playground/water_refraction/main.js +201 -0
  45. package/src/shade/playground/water_refraction/world.d.ts +37 -0
  46. package/src/shade/playground/water_refraction/world.d.ts.map +1 -0
  47. package/src/shade/playground/water_refraction/world.js +137 -0
  48. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  49. package/src/shade/renderer/Renderer.js +4 -0
  50. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts +2 -3
  51. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  52. package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
  53. package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts +8 -0
  54. package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts.map +1 -0
  55. package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts +0 -6
  56. package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts.map +1 -1
  57. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +1 -1
  58. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -1
  59. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +17 -0
  60. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  61. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +7 -0
  62. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts +4 -0
  63. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts.map +1 -0
  64. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.js +11 -0
  65. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts +4 -0
  66. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts.map +1 -0
  67. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.js +19 -0
  68. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts.map +1 -1
  69. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +5 -3
  70. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts +4 -0
  71. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts.map +1 -0
  72. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.js +8 -0
  73. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +1 -1
  74. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  75. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +21 -2
  76. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -1
  77. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +4 -8
  78. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
  79. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts +12 -0
  80. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts.map +1 -0
  81. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts +12 -0
  82. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts.map +1 -0
  83. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts +12 -0
  84. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts.map +1 -0
  85. package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.d.ts → chunk_plane_ray_raycast.d.ts} +2 -2
  86. package/src/shade/renderer/shader/chunk/geometry/plane/chunk_plane_ray_raycast.d.ts.map +1 -0
  87. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts +4 -0
  88. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts.map +1 -0
  89. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.js +101 -0
  90. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +62 -29
  91. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  92. package/src/shade/renderer/water/GPUWaterRenderer.js +235 -147
  93. package/src/shade/renderer/water/chunk_water_transport.d.ts +5 -0
  94. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -0
  95. package/src/shade/renderer/water/chunk_water_transport.js +94 -0
  96. package/src/shade/renderer/water/shader_water.d.ts +9 -26
  97. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  98. package/src/shade/renderer/water/shader_water.js +384 -246
  99. package/src/shade/renderer/water/shader_water_avboit.d.ts +12 -0
  100. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -0
  101. package/src/shade/renderer/water/shader_water_avboit.js +258 -0
  102. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  103. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +13 -0
  104. package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts +0 -29
  105. package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts.map +0 -1
  106. package/src/shade/renderer/shader/chunk/geometry/plane/plane_ray_raycast.d.ts.map +0 -1
@@ -443,8 +443,8 @@ export class ClothInstance {
443
443
  * The index handles this cloth last **stepped against**, in the order the
444
444
  * broadphase returned them, and how many of them are meaningful.
445
445
  *
446
- * §7 P5's wake test compares each overlapping collider's previous pose with
447
- * its current one, and `ClothColliderSystem#link` *places* a new collider —
446
+ * §7 P5's wake test compares each overlapping collider's revision with the
447
+ * last simulated step, and `ClothColliderSystem#link` *places* a new collider —
448
448
  * previous equals current — so a collider spawned around a sleeping cloth
449
449
  * is one that has not moved and never woke it. The set is the other half of
450
450
  * that question: a handle appearing or leaving is a change to the world the
@@ -456,6 +456,19 @@ export class ClothInstance {
456
456
  * @type {number}
457
457
  */
458
458
  collider_key_count: number;
459
+ /**
460
+ * Revision of each collider at the last simulated gather. Unlike comparing
461
+ * swept poses, this also detects a placement or a changed surface.
462
+ * @type {Uint32Array}
463
+ */
464
+ collider_revisions: Uint32Array;
465
+ /**
466
+ * Revisions captured alongside the current solver table. The remember
467
+ * operation copies this snapshot, so index edits after gathering still
468
+ * wake the cloth and the public two-argument remember API needs no index.
469
+ * @type {Uint32Array}
470
+ */
471
+ gathered_collider_revisions: Uint32Array;
459
472
  /**
460
473
  * The broadphase margin the last gather used, metres. The wake test has to
461
474
  * query with the same one, or it compares a set built under one reach with
@@ -1 +1 @@
1
- {"version":3,"file":"ClothInstance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothInstance.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ClothInstance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothInstance.js"],"names":[],"mappings":"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"}
@@ -498,8 +498,8 @@ export class ClothInstance {
498
498
  * The index handles this cloth last **stepped against**, in the order the
499
499
  * broadphase returned them, and how many of them are meaningful.
500
500
  *
501
- * §7 P5's wake test compares each overlapping collider's previous pose with
502
- * its current one, and `ClothColliderSystem#link` *places* a new collider —
501
+ * §7 P5's wake test compares each overlapping collider's revision with the
502
+ * last simulated step, and `ClothColliderSystem#link` *places* a new collider —
503
503
  * previous equals current — so a collider spawned around a sleeping cloth
504
504
  * is one that has not moved and never woke it. The set is the other half of
505
505
  * that question: a handle appearing or leaving is a change to the world the
@@ -513,6 +513,21 @@ export class ClothInstance {
513
513
  */
514
514
  collider_key_count = 0;
515
515
 
516
+ /**
517
+ * Revision of each collider at the last simulated gather. Unlike comparing
518
+ * swept poses, this also detects a placement or a changed surface.
519
+ * @type {Uint32Array}
520
+ */
521
+ collider_revisions = new Uint32Array(CLOTH_COLLIDER_SLOTS);
522
+
523
+ /**
524
+ * Revisions captured alongside the current solver table. The remember
525
+ * operation copies this snapshot, so index edits after gathering still
526
+ * wake the cloth and the public two-argument remember API needs no index.
527
+ * @type {Uint32Array}
528
+ */
529
+ gathered_collider_revisions = new Uint32Array(CLOTH_COLLIDER_SLOTS);
530
+
516
531
  /**
517
532
  * The broadphase margin the last gather used, metres. The wake test has to
518
533
  * query with the same one, or it compares a set built under one reach with
@@ -1 +1 @@
1
- {"version":3,"file":"ClothWorld.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothWorld.js"],"names":[],"mappings":"AA2DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH;IAEI;;;OAGG;IACH,SAFU,YAAY,CAEoB;IAE1C;;;;;;;;;;;;OAYG;IACH,WAFU,aAAa,EAAE,CAEV;IAEf;;;;;;;;;;;;;;;OAeG;IACH,QAFU;QAAC,WAAW,SAAW,MAAM,KAAG,CAAC,iBAAe,IAAI,CAAC,CAAA;KAAC,GAAC,IAAI,CAEvD;IAEd;;OAEG;IACH,eAFU,gBAAc,IAAI,CAEP;IAErB;;OAEG;IACH,aAFU,yBAAyB,GAAC,IAAI,CAErB;IAEnB;;;;;;OAMG;IACH,WAFU,mBAAmB,GAAC,IAAI,CAEjB;IAEjB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAFU,oBAAkB,IAAI,CAEpB;IAEZ;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAFU,MAAM,CAEP;IAET;;;;;OAKG;IACH,uBAAmB;IAEnB;;;;;OAKG;IACH,cAFU,OAAO,CAEI;IAErB;;;OAGG;IACH,oBAAwB;IAExB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,uBAKE;IAEF;;;;;OAKG;IACH,2CAiBC;IAED;;;;;OAKG;IACH,YALW,KAAK,kCAEL,MAAM,GACJ,aAAa,CAczB;IAED;;;;;;;;OAQG;IACH,iDAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,iDAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,eAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CA0BnC;IAyED;;;;;;;;;;;OAWG;IACH,eAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CAanC;IAED;;;;;;;OAOG;IACH,aAHW,MAAM,GACJ,IAAI,CAShB;IAED;;;OAGG;IACH,mBAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CAInC;IAED;;;;;OAKG;IACH,uCAFW,MAAM,QAgBhB;IAED;;;;;;;;;OASG;IACH,wBANW,aAAa,mCAEb,MAAM,GACJ,OAAO,CA8BnB;IAED;;;;;;;OAOG;IACH,iBAJW,aAAa,gCAEX,IAAI,CA4ChB;IAwFD;;;;;;;;;;;OAWG;IACH,kBAPW,aAAa,MACb,MAAM,UACN,YAAY,UACZ,MAAM,GACJ,OAAO,CAgPnB;;CA8EJ;8BAj/B6B,oBAAoB;0CAjB3C,gEAAgE;oCAcnC,0BAA0B;sBA4BxC,YAAY"}
1
+ {"version":3,"file":"ClothWorld.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothWorld.js"],"names":[],"mappings":"AA2DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH;IAEI;;;OAGG;IACH,SAFU,YAAY,CAEoB;IAE1C;;;;;;;;;;;;OAYG;IACH,WAFU,aAAa,EAAE,CAEV;IAEf;;;;;;;;;;;;;;;OAeG;IACH,QAFU;QAAC,WAAW,SAAW,MAAM,KAAG,CAAC,iBAAe,IAAI,CAAC,CAAA;KAAC,GAAC,IAAI,CAEvD;IAEd;;OAEG;IACH,eAFU,gBAAc,IAAI,CAEP;IAErB;;OAEG;IACH,aAFU,yBAAyB,GAAC,IAAI,CAErB;IAEnB;;;;;;OAMG;IACH,WAFU,mBAAmB,GAAC,IAAI,CAEjB;IAEjB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAFU,oBAAkB,IAAI,CAEpB;IAEZ;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAFU,MAAM,CAEP;IAET;;;;;OAKG;IACH,uBAAmB;IAEnB;;;;;OAKG;IACH,cAFU,OAAO,CAEI;IAErB;;;OAGG;IACH,oBAAwB;IAExB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,uBAKE;IAEF;;;;;OAKG;IACH,2CAiBC;IAED;;;;;OAKG;IACH,YALW,KAAK,kCAEL,MAAM,GACJ,aAAa,CAczB;IAED;;;;;;;;OAQG;IACH,iDAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,iDAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,eAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CA0BnC;IAyED;;;;;;;;;;;OAWG;IACH,eAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CAanC;IAED;;;;;;;OAOG;IACH,aAHW,MAAM,GACJ,IAAI,CAShB;IAED;;;OAGG;IACH,mBAHW,MAAM,GACJ,aAAa,GAAC,SAAS,CAInC;IAED;;;;;OAKG;IACH,uCAFW,MAAM,QAgBhB;IAED;;;;;;;;;OASG;IACH,wBANW,aAAa,mCAEb,MAAM,GACJ,OAAO,CA8BnB;IAED;;;;;;;OAOG;IACH,iBAJW,aAAa,gCAEX,IAAI,CA4ChB;IAwFD;;;;;;;;;;;OAWG;IACH,kBAPW,aAAa,MACb,MAAM,UACN,YAAY,UACZ,MAAM,GACJ,OAAO,CAmPnB;;CA8EJ;8BAp/B6B,oBAAoB;0CAjB3C,gEAAgE;oCAcnC,0BAA0B;sBA4BxC,YAAY"}
@@ -787,9 +787,8 @@ export class ClothWorld {
787
787
  if (instance.asleep && this.colliders !== null && instance.state !== null) {
788
788
  // §7 P5's "wake on collider motion". A sleeping cloth is neither
789
789
  // stepped nor written back, so something has to notice the world it
790
- // was resting against moving out from under it, and a broadphase
791
- // query plus a pose comparison is three orders of magnitude cheaper
792
- // than the step it decides whether to skip.
790
+ // was resting against moving out from under it. Query handles and
791
+ // revisions without preparing the solver's local collider table.
793
792
  if (cloth_colliders_moved(instance, this.colliders.index)) {
794
793
  instance.asleep = false;
795
794
  instance.still_steps = 0;
@@ -822,7 +821,7 @@ export class ClothWorld {
822
821
  return false;
823
822
  }
824
823
 
825
- if (instance.anchor_valid) {
824
+ if (moved) {
826
825
  const displacement = Math.hypot(tx - previous_translation[0], ty - previous_translation[1], tz - previous_translation[2]);
827
826
 
828
827
  const teleport = displacement > Math.max(
@@ -839,6 +838,10 @@ export class ClothWorld {
839
838
  previous_translation, previous_rotation
840
839
  );
841
840
  }
841
+ } else if (instance.anchor_valid && instance.cloth.dynamics.inertia > 0) {
842
+ // The frame is identical. Preserve the pinning side effect of
843
+ // move_local_frame without rewriting every free position/velocity.
844
+ pin_anchor(instance);
842
845
  }
843
846
 
844
847
  previous_translation[0] = tx;
@@ -879,8 +882,8 @@ export class ClothWorld {
879
882
  cloth_gather_colliders(instance, this.colliders.index, reach);
880
883
 
881
884
  // What this cloth is about to step against, for the next wake test
882
- // to compare with. Here rather than inside the gather because the
883
- // wake test gathers too, and what it asks about is the set the last
885
+ // to compare with. Here rather than inside the query because the
886
+ // wake test queries too, and what it asks about is the set the last
884
887
  // *step* saw.
885
888
  cloth_remember_colliders(instance, reach);
886
889
  } else {
@@ -1172,6 +1175,16 @@ function move_local_frame(
1172
1175
  velocity[p + 2] += inertia * (CARRIED[2] - velocity[p + 2]);
1173
1176
  }
1174
1177
 
1178
+ pin_anchor(instance);
1179
+ }
1180
+
1181
+ /**
1182
+ * @param {ClothInstance} instance
1183
+ * @private
1184
+ */
1185
+ function pin_anchor(instance) {
1186
+ const position = instance.state.position;
1187
+ const velocity = instance.state.velocity;
1175
1188
  // The anchor is pinned and is the origin of the frame it anchors, so it is
1176
1189
  // the one particle that must not be carried anywhere.
1177
1190
  const anchor = instance.particle_of_node[0] * 3;
@@ -23,10 +23,10 @@
23
23
  *
24
24
  * ## The query box
25
25
  *
26
- * The cloth's own particle bounds, fattened by exactly what
27
- * `cloth_contact_find` will reach for — no more, because a broadphase that is
28
- * wider than its narrowphase is collecting colliders it will then throw away.
29
- * {@link cloth_gather_reach} is that quantity and carries the derivation.
26
+ * The cloth's particle bounds are fattened by its contact radius and particle
27
+ * travel; the index supplies each collider's motion and inflation. Both sides
28
+ * include an outward rounding allowance for the solver's Float32 conversion.
29
+ * {@link cloth_gather_reach} carries the reach derivation.
30
30
  *
31
31
  * It used to be the velocity clamp of §7 P1 read as a distance. That was wrong
32
32
  * in both directions at once. The clamp is `4 · shortest_row · substeps ·
@@ -66,17 +66,16 @@
66
66
  *
67
67
  * The gather has one job the solver depends on: the set it hands over must
68
68
  * contain every collider `cloth_contact_find` would draw a row against. So the
69
- * margin is that function's own reach, maximised over the things the gather
70
- * cannot yet know — which collider, and which particle:
69
+ * reach is split between the cloth query and each collider's indexed bounds:
71
70
  *
72
71
  * (radius + inflation) · (1 + CLOTH_CONTACT_MARGIN) the contact itself
73
72
  * + collider travel §20, the collider's approach
74
73
  * + |v| · dt §54, the particle's own
75
74
  *
76
- * The radius term is added by {@link cloth_gather_colliders}, which knows the
77
- * cloth's `contact_radius`; this supplies the rest. Inflation and collider
78
- * travel come from the index as maxima over every live record, because the
79
- * gather has not queried yet and so cannot know which records it will get.
75
+ * The radius term is added by {@link cloth_gather_colliders}. This function
76
+ * supplies particle travel. The index expands each collider's swept bounds
77
+ * by its own travel and inflation, so an intersection covers the same sum
78
+ * without allowing one remote outlier to widen every cloth's query.
80
79
  *
81
80
  * **The velocity is read before the step and the narrowphase reads it after
82
81
  * `damp`**, which only ever scales it down — so this is an upper bound on the
@@ -92,13 +91,10 @@
92
91
  */
93
92
  export function cloth_gather_reach(state: ClothState, index: ClothColliderIndex, dt: number): number;
94
93
  /**
95
- * Query the index and rewrite the overlapping colliders into the cloth's frame.
96
- *
97
- * @param {ClothInstance} instance read for its anchor pose and filter; its
98
- * state's `collider_table`, `collider_key` and `collider_count` are filled
94
+ * Query the index and rewrite overlapping colliders into the cloth's frame.
95
+ * @param {ClothInstance} instance its state's collider table and keys are filled
99
96
  * @param {ClothColliderIndex} index
100
- * @param {number} reach how far past its particles the cloth has to look,
101
- * metres — {@link cloth_gather_reach}
97
+ * @param {number} reach particle travel from {@link cloth_gather_reach}
102
98
  * @returns {number} how many colliders were gathered
103
99
  */
104
100
  export function cloth_gather_colliders(instance: ClothInstance, index: ClothColliderIndex, reach: number): number;
@@ -108,17 +104,19 @@ export function cloth_gather_colliders(instance: ClothInstance, index: ClothColl
108
104
  *
109
105
  * A sleeping cloth is not stepped and not written back, so something has to
110
106
  * notice when the world it was resting against changes. This is that something,
111
- * and it is a broadphase query plus two comparisons: cheaper than a step by
112
- * three orders of magnitude, which is what makes sleep worth having at all.
107
+ * and it queries handles and revisions without constructing a local collider
108
+ * table or changing solver memory.
113
109
  *
114
- * **Two comparisons, and the set is the one M2 did not have.** A pose
115
- * comparison answers "did anything move", and `ClothColliderSystem#link`
110
+ * **Two comparisons, and the set is the one M2 did not have.** A revision
111
+ * comparison answers "did anything change", and `ClothColliderSystem#link`
116
112
  * *places* a new collider rather than posing it — previous equals current — so
117
113
  * a sphere spawned around a sleeping rope is a collider that has not moved.
118
114
  * Measured: the rope slept through it and stayed asleep three hundred steps
119
115
  * later with four of its six links inside. A handle appearing in the gathered
120
116
  * set, or leaving it, is a change to the world the cloth went to sleep in
121
117
  * whatever the poses say, and it costs one integer compare per record.
118
+ * Revisions also detect placements (whose swept poses are equal), changed
119
+ * surfaces, and a removed handle reused while the cloth slept.
122
120
  *
123
121
  * The query uses the reach the cloth's last *step* gathered with, so the two
124
122
  * sets are answers to the same question. A set built at zero margin against one
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_gather_colliders.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_gather_colliders.js"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qFAHW,MAAM,GACJ,MAAM,CAwBlB;AAED;;;;;;;;;GASG;AACH,kGAJW,MAAM,GAEJ,MAAM,CA6JlB;AAgDD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,2FAFa,OAAO,CAoCnB;AAED;;;;;;;;GAQG;AACH,yEAHW,MAAM,GACJ,IAAI,CAehB"}
1
+ {"version":3,"file":"cloth_gather_colliders.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_gather_colliders.js"],"names":[],"mappings":"AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qFAHW,MAAM,GACJ,MAAM,CAsBlB;AAyJD;;;;;;GAMG;AACH,kGAHW,MAAM,GACJ,MAAM,CAmBlB;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,2FAFa,OAAO,CAkBnB;AAED;;;;;;;;GAQG;AACH,yEAHW,MAAM,GACJ,IAAI,CAgBhB"}
@@ -2,6 +2,12 @@ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multip
2
2
  import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
3
3
  import { v3_quaternion_apply_inverse } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
4
4
  import {
5
+ CCR_AABB_MAX_X,
6
+ CCR_AABB_MAX_Y,
7
+ CCR_AABB_MAX_Z,
8
+ CCR_AABB_MIN_X,
9
+ CCR_AABB_MIN_Y,
10
+ CCR_AABB_MIN_Z,
5
11
  CCR_FEATURE,
6
12
  CCR_FRICTION,
7
13
  CCR_INFLATION,
@@ -26,7 +32,8 @@ import {
26
32
  CCR_TY,
27
33
  CCR_TZ
28
34
  } from "../collider/ClothColliderRecord.js";
29
- import { cloth_collider_refit_bounds } from "../collider/cloth_collider_bounds.js";
35
+ import { ClothColliderKind } from "../collider/ClothColliderKind.js";
36
+ import { cloth_collider_refit_bounds, cloth_contact_rounding } from "../collider/cloth_collider_bounds.js";
30
37
  import { CLOTH_CONTACT_MARGIN } from "../solver/cloth_contact_find.js";
31
38
  import { CLOTH_COLLIDER_SLOTS } from "../solver/cloth_solver_constants.js";
32
39
 
@@ -55,10 +62,10 @@ import { CLOTH_COLLIDER_SLOTS } from "../solver/cloth_solver_constants.js";
55
62
  *
56
63
  * ## The query box
57
64
  *
58
- * The cloth's own particle bounds, fattened by exactly what
59
- * `cloth_contact_find` will reach for — no more, because a broadphase that is
60
- * wider than its narrowphase is collecting colliders it will then throw away.
61
- * {@link cloth_gather_reach} is that quantity and carries the derivation.
65
+ * The cloth's particle bounds are fattened by its contact radius and particle
66
+ * travel; the index supplies each collider's motion and inflation. Both sides
67
+ * include an outward rounding allowance for the solver's Float32 conversion.
68
+ * {@link cloth_gather_reach} carries the reach derivation.
62
69
  *
63
70
  * It used to be the velocity clamp of §7 P1 read as a distance. That was wrong
64
71
  * in both directions at once. The clamp is `4 · shortest_row · substeps ·
@@ -99,17 +106,16 @@ import { CLOTH_COLLIDER_SLOTS } from "../solver/cloth_solver_constants.js";
99
106
  *
100
107
  * The gather has one job the solver depends on: the set it hands over must
101
108
  * contain every collider `cloth_contact_find` would draw a row against. So the
102
- * margin is that function's own reach, maximised over the things the gather
103
- * cannot yet know — which collider, and which particle:
109
+ * reach is split between the cloth query and each collider's indexed bounds:
104
110
  *
105
111
  * (radius + inflation) · (1 + CLOTH_CONTACT_MARGIN) the contact itself
106
112
  * + collider travel §20, the collider's approach
107
113
  * + |v| · dt §54, the particle's own
108
114
  *
109
- * The radius term is added by {@link cloth_gather_colliders}, which knows the
110
- * cloth's `contact_radius`; this supplies the rest. Inflation and collider
111
- * travel come from the index as maxima over every live record, because the
112
- * gather has not queried yet and so cannot know which records it will get.
115
+ * The radius term is added by {@link cloth_gather_colliders}. This function
116
+ * supplies particle travel. The index expands each collider's swept bounds
117
+ * by its own travel and inflation, so an intersection covers the same sum
118
+ * without allowing one remote outlier to widen every cloth's query.
113
119
  *
114
120
  * **The velocity is read before the step and the narrowphase reads it after
115
121
  * `damp`**, which only ever scales it down — so this is an upper bound on the
@@ -142,22 +148,20 @@ export function cloth_gather_reach(state, index, dt) {
142
148
  }
143
149
  }
144
150
 
145
- return dt * Math.sqrt(fastest_squared)
146
- + index.max_collider_travel
147
- + index.max_inflation * (1 + CLOTH_CONTACT_MARGIN);
151
+ return dt * Math.sqrt(fastest_squared);
148
152
  }
149
153
 
150
154
  /**
151
- * Query the index and rewrite the overlapping colliders into the cloth's frame.
155
+ * Query the index into HANDLES without touching the solver's collider table.
152
156
  *
153
- * @param {ClothInstance} instance read for its anchor pose and filter; its
154
- * state's `collider_table`, `collider_key` and `collider_count` are filled
157
+ * @param {ClothInstance} instance read for its bounds, anchor pose and filter
155
158
  * @param {ClothColliderIndex} index
156
159
  * @param {number} reach how far past its particles the cloth has to look,
157
160
  * metres — {@link cloth_gather_reach}
158
- * @returns {number} how many colliders were gathered
161
+ * @returns {number} how many handles fit in the collider table
162
+ * @private
159
163
  */
160
- export function cloth_gather_colliders(instance, index, reach) {
164
+ function query_colliders(instance, index, reach) {
161
165
  const state = instance.state;
162
166
 
163
167
  const particle_count = state.particle_count;
@@ -186,22 +190,9 @@ export function cloth_gather_colliders(instance, index, reach) {
186
190
  }
187
191
 
188
192
  if (particle_count === 0) {
189
- state.collider_count = 0;
190
-
191
193
  return 0;
192
194
  }
193
195
 
194
- // The contact's own reach, on the same terms `cloth_contact_find` states
195
- // it in, plus everything {@link cloth_gather_reach} already folded in.
196
- const margin = reach + state.contact_radius * (1 + CLOTH_CONTACT_MARGIN);
197
-
198
- min_x -= margin;
199
- min_y -= margin;
200
- min_z -= margin;
201
- max_x += margin;
202
- max_y += margin;
203
- max_z += margin;
204
-
205
196
  // The anchor pose the particles were carried into this step, not the live
206
197
  // component — those are the same value by the time this runs, and the
207
198
  // cached pair is the one `move_local_frame` used.
@@ -214,6 +205,20 @@ export function cloth_gather_colliders(instance, index, reach) {
214
205
  const qz = instance.anchor_rotation[2];
215
206
  const qw = instance.anchor_rotation[3];
216
207
 
208
+ const contact_reach = reach + state.contact_radius * (1 + CLOTH_CONTACT_MARGIN);
209
+ const local_scale = Math.max(Math.abs(min_x), Math.abs(max_x))
210
+ + Math.max(Math.abs(min_y), Math.abs(max_y))
211
+ + Math.max(Math.abs(min_z), Math.abs(max_z)) + contact_reach;
212
+ const world_scale = local_scale + Math.abs(anchor_x) + Math.abs(anchor_y) + Math.abs(anchor_z);
213
+ const margin = contact_reach + cloth_contact_rounding(local_scale, world_scale);
214
+
215
+ min_x -= margin;
216
+ min_y -= margin;
217
+ min_z -= margin;
218
+ max_x += margin;
219
+ max_y += margin;
220
+ max_z += margin;
221
+
217
222
  // The local box's eight corners, in world. A rotated box is not a box, so
218
223
  // the world query volume is the bounds of the rotated one rather than the
219
224
  // rotation of the bounds.
@@ -247,12 +252,37 @@ export function cloth_gather_colliders(instance, index, reach) {
247
252
 
248
253
  const cloth = instance.cloth;
249
254
 
250
- const overlapping = index.query(
255
+ const candidates = index.query(
251
256
  HANDLES, world_min_x, world_min_y, world_min_z,
252
257
  world_max_x, world_max_y, world_max_z,
253
- cloth.layer, cloth.mask
258
+ cloth.layer, cloth.mask, true
254
259
  );
255
260
 
261
+ // A half-space has no bounded world-space conversion allowance, so the
262
+ // index keeps every plane. Reject separated planes in the exact Float32
263
+ // frame used by the solver, BEFORE applying the table limit. Otherwise
264
+ // distant floors can consume all slots and hide a real nearby contact.
265
+ let overlapping = 0;
266
+ const source = index.table;
267
+ for (let i = 0; i < candidates; i++) {
268
+ const handle = HANDLES[i];
269
+ if (source[handle * CCR_STRIDE + CCR_KIND] === ClothColliderKind.Plane) {
270
+ localise_record(PLANE_RECORD, 0, source, handle, instance);
271
+ const extra = Math.max(0, PLANE_RECORD[CCR_INFLATION]) * (1 + CLOTH_CONTACT_MARGIN)
272
+ + Math.hypot(
273
+ PLANE_RECORD[CCR_TX] - PLANE_RECORD[CCR_PREV_TX],
274
+ PLANE_RECORD[CCR_TY] - PLANE_RECORD[CCR_PREV_TY],
275
+ PLANE_RECORD[CCR_TZ] - PLANE_RECORD[CCR_PREV_TZ]
276
+ );
277
+ if (max_x + extra < PLANE_RECORD[CCR_AABB_MIN_X] || min_x - extra > PLANE_RECORD[CCR_AABB_MAX_X]
278
+ || max_y + extra < PLANE_RECORD[CCR_AABB_MIN_Y] || min_y - extra > PLANE_RECORD[CCR_AABB_MAX_Y]
279
+ || max_z + extra < PLANE_RECORD[CCR_AABB_MIN_Z] || min_z - extra > PLANE_RECORD[CCR_AABB_MAX_Z]) {
280
+ continue;
281
+ }
282
+ }
283
+ HANDLES[overlapping++] = handle;
284
+ }
285
+
256
286
  let found = overlapping;
257
287
 
258
288
  if (found > CLOTH_COLLIDER_SLOTS) {
@@ -269,44 +299,28 @@ export function cloth_gather_colliders(instance, index, reach) {
269
299
  }
270
300
  }
271
301
 
302
+ return found;
303
+ }
304
+
305
+ /**
306
+ * Query the index and rewrite overlapping colliders into the cloth's frame.
307
+ * @param {ClothInstance} instance its state's collider table and keys are filled
308
+ * @param {ClothColliderIndex} index
309
+ * @param {number} reach particle travel from {@link cloth_gather_reach}
310
+ * @returns {number} how many colliders were gathered
311
+ */
312
+ export function cloth_gather_colliders(instance, index, reach) {
313
+ const found = query_colliders(instance, index, reach);
314
+ const state = instance.state;
272
315
  const table = state.collider_table;
273
316
  const keys = state.collider_key;
274
-
275
317
  const source = index.table;
276
318
 
277
319
  for (let i = 0; i < found; i++) {
278
320
  const handle = HANDLES[i];
279
-
280
- const from = handle * CCR_STRIDE;
281
- const to = i * CCR_STRIDE;
282
-
283
321
  keys[i] = handle;
284
-
285
- table[to + CCR_KIND] = source[from + CCR_KIND];
286
- table[to + CCR_PARAM_0] = source[from + CCR_PARAM_0];
287
- table[to + CCR_PARAM_1] = source[from + CCR_PARAM_1];
288
- table[to + CCR_PARAM_2] = source[from + CCR_PARAM_2];
289
- table[to + CCR_PARAM_3] = source[from + CCR_PARAM_3];
290
- table[to + CCR_FEATURE] = source[from + CCR_FEATURE];
291
- table[to + CCR_FRICTION] = source[from + CCR_FRICTION];
292
- table[to + CCR_INFLATION] = source[from + CCR_INFLATION];
293
-
294
- localise(
295
- table, to + CCR_TX, to + CCR_QX,
296
- source[from + CCR_TX], source[from + CCR_TY], source[from + CCR_TZ],
297
- source[from + CCR_QX], source[from + CCR_QY], source[from + CCR_QZ], source[from + CCR_QW],
298
- anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
299
- );
300
-
301
- localise(
302
- table, to + CCR_PREV_TX, to + CCR_PREV_QX,
303
- source[from + CCR_PREV_TX], source[from + CCR_PREV_TY], source[from + CCR_PREV_TZ],
304
- source[from + CCR_PREV_QX], source[from + CCR_PREV_QY],
305
- source[from + CCR_PREV_QZ], source[from + CCR_PREV_QW],
306
- anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
307
- );
308
-
309
- cloth_collider_refit_bounds(table, i, CCR_STRIDE);
322
+ instance.gathered_collider_revisions[i] = index.revisionOf(handle);
323
+ localise_record(table, i, source, handle, instance);
310
324
  }
311
325
 
312
326
  state.collider_count = found;
@@ -314,6 +328,54 @@ export function cloth_gather_colliders(instance, index, reach) {
314
328
  return found;
315
329
  }
316
330
 
331
+ /**
332
+ * Convert a complete record using the solver's storage precision. Shared with
333
+ * the plane prefilter so its bounds and travel match what discovery will read.
334
+ * @param {Float32Array} table
335
+ * @param {number} record
336
+ * @param {Float64Array} source
337
+ * @param {number} handle
338
+ * @param {ClothInstance} instance
339
+ * @private
340
+ */
341
+ function localise_record(table, record, source, handle, instance) {
342
+ const anchor_x = instance.anchor_translation[0];
343
+ const anchor_y = instance.anchor_translation[1];
344
+ const anchor_z = instance.anchor_translation[2];
345
+ const qx = instance.anchor_rotation[0];
346
+ const qy = instance.anchor_rotation[1];
347
+ const qz = instance.anchor_rotation[2];
348
+ const qw = instance.anchor_rotation[3];
349
+ const from = handle * CCR_STRIDE;
350
+ const to = record * CCR_STRIDE;
351
+
352
+ table[to + CCR_KIND] = source[from + CCR_KIND];
353
+ table[to + CCR_PARAM_0] = source[from + CCR_PARAM_0];
354
+ table[to + CCR_PARAM_1] = source[from + CCR_PARAM_1];
355
+ table[to + CCR_PARAM_2] = source[from + CCR_PARAM_2];
356
+ table[to + CCR_PARAM_3] = source[from + CCR_PARAM_3];
357
+ table[to + CCR_FEATURE] = source[from + CCR_FEATURE];
358
+ table[to + CCR_FRICTION] = source[from + CCR_FRICTION];
359
+ table[to + CCR_INFLATION] = source[from + CCR_INFLATION];
360
+
361
+ localise(
362
+ table, to + CCR_TX, to + CCR_QX,
363
+ source[from + CCR_TX], source[from + CCR_TY], source[from + CCR_TZ],
364
+ source[from + CCR_QX], source[from + CCR_QY], source[from + CCR_QZ], source[from + CCR_QW],
365
+ anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
366
+ );
367
+
368
+ localise(
369
+ table, to + CCR_PREV_TX, to + CCR_PREV_QX,
370
+ source[from + CCR_PREV_TX], source[from + CCR_PREV_TY], source[from + CCR_PREV_TZ],
371
+ source[from + CCR_PREV_QX], source[from + CCR_PREV_QY],
372
+ source[from + CCR_PREV_QZ], source[from + CCR_PREV_QW],
373
+ anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
374
+ );
375
+
376
+ cloth_collider_refit_bounds(table, record, CCR_STRIDE);
377
+ }
378
+
317
379
  /**
318
380
  * Write a world pose into a record's translation and rotation slots, expressed
319
381
  * in the anchor's frame.
@@ -366,17 +428,19 @@ function localise(
366
428
  *
367
429
  * A sleeping cloth is not stepped and not written back, so something has to
368
430
  * notice when the world it was resting against changes. This is that something,
369
- * and it is a broadphase query plus two comparisons: cheaper than a step by
370
- * three orders of magnitude, which is what makes sleep worth having at all.
431
+ * and it queries handles and revisions without constructing a local collider
432
+ * table or changing solver memory.
371
433
  *
372
- * **Two comparisons, and the set is the one M2 did not have.** A pose
373
- * comparison answers "did anything move", and `ClothColliderSystem#link`
434
+ * **Two comparisons, and the set is the one M2 did not have.** A revision
435
+ * comparison answers "did anything change", and `ClothColliderSystem#link`
374
436
  * *places* a new collider rather than posing it — previous equals current — so
375
437
  * a sphere spawned around a sleeping rope is a collider that has not moved.
376
438
  * Measured: the rope slept through it and stayed asleep three hundred steps
377
439
  * later with four of its six links inside. A handle appearing in the gathered
378
440
  * set, or leaving it, is a change to the world the cloth went to sleep in
379
441
  * whatever the poses say, and it costs one integer compare per record.
442
+ * Revisions also detect placements (whose swept poses are equal), changed
443
+ * surfaces, and a removed handle reused while the cloth slept.
380
444
  *
381
445
  * The query uses the reach the cloth's last *step* gathered with, so the two
382
446
  * sets are answers to the same question. A set built at zero margin against one
@@ -387,9 +451,7 @@ function localise(
387
451
  * @returns {boolean}
388
452
  */
389
453
  export function cloth_colliders_moved(instance, index) {
390
- const found = cloth_gather_colliders(instance, index, instance.gather_reach);
391
-
392
- const keys = instance.state.collider_key;
454
+ const found = query_colliders(instance, index, instance.gather_reach);
393
455
 
394
456
  if (found !== instance.collider_key_count) {
395
457
  return true;
@@ -398,23 +460,7 @@ export function cloth_colliders_moved(instance, index) {
398
460
  const seen = instance.collider_keys;
399
461
 
400
462
  for (let i = 0; i < found; i++) {
401
- if (keys[i] !== seen[i]) {
402
- return true;
403
- }
404
- }
405
-
406
- const table = instance.state.collider_table;
407
-
408
- for (let i = 0; i < found; i++) {
409
- const r = i * CCR_STRIDE;
410
-
411
- if (table[r + CCR_TX] !== table[r + CCR_PREV_TX]
412
- || table[r + CCR_TY] !== table[r + CCR_PREV_TY]
413
- || table[r + CCR_TZ] !== table[r + CCR_PREV_TZ]
414
- || table[r + CCR_QX] !== table[r + CCR_PREV_QX]
415
- || table[r + CCR_QY] !== table[r + CCR_PREV_QY]
416
- || table[r + CCR_QZ] !== table[r + CCR_PREV_QZ]
417
- || table[r + CCR_QW] !== table[r + CCR_PREV_QW]) {
463
+ if (HANDLES[i] !== seen[i] || index.revisionOf(HANDLES[i]) !== instance.collider_revisions[i]) {
418
464
  return true;
419
465
  }
420
466
  }
@@ -440,6 +486,7 @@ export function cloth_remember_colliders(instance, reach) {
440
486
 
441
487
  for (let i = 0; i < count; i++) {
442
488
  seen[i] = keys[i];
489
+ instance.collider_revisions[i] = instance.gathered_collider_revisions[i];
443
490
  }
444
491
 
445
492
  instance.collider_key_count = count;
@@ -452,6 +499,9 @@ export function cloth_remember_colliders(instance, reach) {
452
499
  */
453
500
  const HANDLES = [];
454
501
 
502
+ /** @type {Float32Array} @private */
503
+ const PLANE_RECORD = new Float32Array(CCR_STRIDE);
504
+
455
505
  /**
456
506
  * @type {Float64Array}
457
507
  * @private
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicsSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/PhysicsSystem.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PhysicsSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/PhysicsSystem.js"],"names":[],"mappings":"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"}