@react-three/rapier 0.12.1 → 0.13.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 (26) hide show
  1. package/dist/declarations/src/{AnyCollider.d.ts → components/AnyCollider.d.ts} +51 -11
  2. package/dist/declarations/src/{Attractor.d.ts → components/Attractor.d.ts} +0 -0
  3. package/dist/declarations/src/{Debug.d.ts → components/Debug.d.ts} +0 -0
  4. package/dist/declarations/src/components/InstancedRigidBodies.d.ts +12 -0
  5. package/dist/declarations/src/{MeshCollider.d.ts → components/MeshCollider.d.ts} +5 -1
  6. package/dist/declarations/src/{Physics.d.ts → components/Physics.d.ts} +7 -2
  7. package/dist/declarations/src/{RigidBody.d.ts → components/RigidBody.d.ts} +10 -8
  8. package/dist/declarations/src/{hooks.d.ts → hooks/hooks.d.ts} +17 -5
  9. package/dist/declarations/src/{joints.d.ts → hooks/joints.d.ts} +19 -8
  10. package/dist/declarations/src/hooks/use-imperative-instance.d.ts +4 -0
  11. package/dist/declarations/src/index.d.ts +18 -17
  12. package/dist/declarations/src/types.d.ts +10 -10
  13. package/dist/declarations/src/utils/api.d.ts +18 -0
  14. package/dist/declarations/src/{interaction-groups.d.ts → utils/interaction-groups.d.ts} +0 -0
  15. package/dist/declarations/src/{shared-objects.d.ts → utils/shared-objects.d.ts} +0 -0
  16. package/dist/declarations/src/utils/three-object-helpers.d.ts +29 -0
  17. package/dist/declarations/src/{utils-collider.d.ts → utils/utils-collider.d.ts} +6 -7
  18. package/dist/declarations/src/{utils-rigidbody.d.ts → utils/utils-rigidbody.d.ts} +6 -6
  19. package/dist/declarations/src/{utils.d.ts → utils/utils.d.ts} +2 -2
  20. package/dist/react-three-rapier.cjs.dev.js +548 -600
  21. package/dist/react-three-rapier.cjs.prod.js +548 -600
  22. package/dist/react-three-rapier.esm.js +549 -604
  23. package/package.json +12 -12
  24. package/readme.md +165 -30
  25. package/dist/declarations/src/InstancedRigidBodies.d.ts +0 -10
  26. package/dist/declarations/src/api.d.ts +0 -179
@@ -72,10 +72,44 @@ function _objectSpread2(target) {
72
72
  return target;
73
73
  }
74
74
 
75
+ const createWorldApi = ref => {
76
+ return {
77
+ raw: () => ref.current(),
78
+ getCollider: handle => ref.current().getCollider(handle),
79
+ getRigidBody: handle => ref.current().getRigidBody(handle),
80
+ createRigidBody: desc => ref.current().createRigidBody(desc),
81
+ createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
82
+ removeRigidBody: rigidBody => {
83
+ if (!ref.current().bodies.contains(rigidBody.handle)) return;
84
+ ref.current().removeRigidBody(rigidBody);
85
+ },
86
+ removeCollider: (collider, wakeUp = true) => {
87
+ if (!ref.current().colliders.contains(collider.handle)) return;
88
+ ref.current().removeCollider(collider, wakeUp);
89
+ },
90
+ createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
91
+ removeImpulseJoint: (joint, wakeUp = true) => {
92
+ if (!ref.current().impulseJoints.contains(joint.handle)) return;
93
+ ref.current().removeImpulseJoint(joint, wakeUp);
94
+ },
95
+ forEachCollider: callback => ref.current().forEachCollider(callback),
96
+ setGravity: ({
97
+ x,
98
+ y,
99
+ z
100
+ }) => ref.current().gravity = {
101
+ x,
102
+ y,
103
+ z
104
+ },
105
+ debugRender: () => ref.current().debugRender()
106
+ };
107
+ };
108
+
75
109
  const _quaternion = new three.Quaternion();
76
110
  new three.Euler();
77
111
  const _vector3 = new three.Vector3();
78
- const _object3d = new three.Object3D();
112
+ new three.Object3D();
79
113
  const _matrix4 = new three.Matrix4();
80
114
  const _position = new three.Vector3();
81
115
  const _rotation = new three.Quaternion();
@@ -91,11 +125,6 @@ const tupleToObject = (tuple, keys) => {
91
125
  return obj;
92
126
  }, {});
93
127
  };
94
- const rapierVector3ToVector3 = ({
95
- x,
96
- y,
97
- z
98
- }) => _vector3.set(x, y, z);
99
128
  const rapierQuaternionToQuaternion = ({
100
129
  x,
101
130
  y,
@@ -149,152 +178,6 @@ function useConst(initialValue) {
149
178
  return ref.current.value;
150
179
  }
151
180
 
152
- const createRigidBodyApi = ref => {
153
- return {
154
- raw: () => ref.current(),
155
-
156
- get handle() {
157
- return ref.current().handle;
158
- },
159
-
160
- mass: () => ref.current().mass(),
161
-
162
- applyImpulse(impulseVector, wakeUp = true) {
163
- ref.current().applyImpulse(impulseVector, wakeUp);
164
- },
165
-
166
- applyTorqueImpulse(torqueVector, wakeUp = true) {
167
- ref.current().applyTorqueImpulse(torqueVector, wakeUp);
168
- },
169
-
170
- applyImpulseAtPoint: (impulseVector, impulsePoint, wakeUp = true) => ref.current().applyImpulseAtPoint(impulseVector, impulsePoint, wakeUp),
171
- addForce: (force, wakeUp = true) => ref.current().addForce(force, wakeUp),
172
- addForceAtPoint: (force, point, wakeUp = true) => ref.current().addForceAtPoint(force, point, wakeUp),
173
- addTorque: (torque, wakeUp = true) => ref.current().addTorque(torque, wakeUp),
174
-
175
- translation() {
176
- return rapierVector3ToVector3(ref.current().translation());
177
- },
178
-
179
- setTranslation: (translation, wakeUp = true) => ref.current().setTranslation(translation, wakeUp),
180
-
181
- rotation() {
182
- const {
183
- x,
184
- y,
185
- z,
186
- w
187
- } = ref.current().rotation();
188
- return new three.Quaternion(x, y, z, w);
189
- },
190
-
191
- setRotation: (rotation, wakeUp = true) => {
192
- ref.current().setRotation(rotation, wakeUp);
193
- },
194
-
195
- linvel() {
196
- const {
197
- x,
198
- y,
199
- z
200
- } = ref.current().linvel();
201
- return new three.Vector3(x, y, z);
202
- },
203
-
204
- setLinvel: (velocity, wakeUp = true) => ref.current().setLinvel(velocity, wakeUp),
205
-
206
- angvel() {
207
- const {
208
- x,
209
- y,
210
- z
211
- } = ref.current().angvel();
212
- return new three.Vector3(x, y, z);
213
- },
214
-
215
- setAngvel: (velocity, wakeUp = true) => ref.current().setAngvel(velocity, wakeUp),
216
-
217
- linearDamping() {
218
- return ref.current().linearDamping();
219
- },
220
-
221
- setLinearDamping: factor => ref.current().setLinearDamping(factor),
222
-
223
- angularDamping() {
224
- return ref.current().angularDamping();
225
- },
226
-
227
- setAngularDamping: factor => ref.current().setAngularDamping(factor),
228
- setNextKinematicRotation: rotation => {
229
- ref.current().setNextKinematicRotation(rotation);
230
- },
231
- setNextKinematicTranslation: translation => ref.current().setNextKinematicTranslation(translation),
232
- resetForces: (wakeUp = true) => ref.current().resetForces(wakeUp),
233
- resetTorques: (wakeUp = true) => ref.current().resetTorques(wakeUp),
234
- lockRotations: (locked, wakeUp = true) => ref.current().lockRotations(locked, wakeUp),
235
- lockTranslations: (locked, wakeUp = true) => ref.current().lockTranslations(locked, wakeUp),
236
- setEnabledRotations: (x, y, z, wakeUp = true) => ref.current().setEnabledRotations(x, y, z, wakeUp),
237
- setEnabledTranslations: (x, y, z, wakeUp = true) => ref.current().setEnabledTranslations(x, y, z, wakeUp)
238
- };
239
- };
240
- const createInstancedRigidBodiesApi = bodiesGetter => ({
241
- at: index => bodiesGetter.current()[index].api,
242
-
243
- forEach(callback) {
244
- return bodiesGetter.current().map(b => b.api).forEach(callback);
245
- },
246
-
247
- get count() {
248
- return bodiesGetter.current().length;
249
- }
250
-
251
- });
252
- const createWorldApi = ref => {
253
- return {
254
- raw: () => ref.current(),
255
- getCollider: handle => ref.current().getCollider(handle),
256
- getRigidBody: handle => ref.current().getRigidBody(handle),
257
- createRigidBody: desc => ref.current().createRigidBody(desc),
258
- createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
259
- removeRigidBody: rigidBody => {
260
- if (!ref.current().bodies.contains(rigidBody.handle)) return;
261
- ref.current().removeRigidBody(rigidBody);
262
- },
263
- removeCollider: (collider, wakeUp = true) => {
264
- if (!ref.current().colliders.contains(collider.handle)) return;
265
- ref.current().removeCollider(collider, wakeUp);
266
- },
267
- createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
268
- removeImpulseJoint: (joint, wakeUp = true) => {
269
- if (!ref.current().impulseJoints.contains(joint.handle)) return;
270
- ref.current().removeImpulseJoint(joint, wakeUp);
271
- },
272
- forEachCollider: callback => ref.current().forEachCollider(callback),
273
- setGravity: ({
274
- x,
275
- y,
276
- z
277
- }) => ref.current().gravity = {
278
- x,
279
- y,
280
- z
281
- },
282
- debugRender: () => ref.current().debugRender()
283
- };
284
- };
285
- const createJointApi = ref => {
286
- return {
287
- raw: () => ref.current(),
288
-
289
- get handle() {
290
- return ref.current().handle;
291
- },
292
-
293
- configureMotorPosition: (targetPos, stiffness, damping) => ref.current().configureMotorPosition(targetPos, stiffness, damping),
294
- configureMotorVelocity: (targetVel, damping) => ref.current().configureMotorVelocity(targetVel, damping)
295
- };
296
- };
297
-
298
181
  const scaleColliderArgs = (shape, args, scale) => {
299
182
  const newArgs = args.slice(); // Heightfield uses a vector
300
183
 
@@ -316,11 +199,11 @@ const scaleColliderArgs = (shape, args, scale) => {
316
199
  const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
317
200
  return newArgs.map((arg, index) => scaleArray[index] * arg);
318
201
  };
319
- const createColliderFromOptions = (options, world, scale, rigidBody) => {
202
+ const createColliderFromOptions = (options, world, scale, getRigidBody) => {
320
203
  const scaledArgs = scaleColliderArgs(options.shape, options.args, scale); // @ts-ignore
321
204
 
322
205
  const desc = rapier3dCompat.ColliderDesc[options.shape](...scaledArgs);
323
- return world.createCollider(desc, rigidBody);
206
+ return world.createCollider(desc, getRigidBody === null || getRigidBody === void 0 ? void 0 : getRigidBody());
324
207
  };
325
208
  const massPropertiesConflictError = "Please pick ONLY ONE of the `density`, `mass` and `massProperties` options.";
326
209
 
@@ -424,15 +307,14 @@ const setColliderOptions = (collider, options, states) => {
424
307
  setColliderMassOptions(collider, options);
425
308
  }
426
309
  };
427
- const useUpdateColliderOptions = (collidersRef, props, states) => {
310
+ const useUpdateColliderOptions = (getCollider, props, states) => {
428
311
  // TODO: Improve this, split each prop into its own effect
429
312
  const mutablePropsAsFlatArray = React.useMemo(() => mutableColliderOptionKeys.flatMap(key => {
430
313
  return vectorToTuple(props[key]);
431
314
  }), [props]);
432
315
  React.useEffect(() => {
433
- collidersRef.current.forEach(collider => {
434
- setColliderOptions(collider, props, states);
435
- });
316
+ const collider = getCollider();
317
+ setColliderOptions(collider, props, states);
436
318
  }, mutablePropsAsFlatArray);
437
319
  };
438
320
 
@@ -555,7 +437,7 @@ const getColliderArgsFromGeometry = (geometry, colliders) => {
555
437
  offset: new three.Vector3()
556
438
  };
557
439
  };
558
- const useColliderEvents = (collidersRef, props, events) => {
440
+ const useColliderEvents = (getCollider, props, events) => {
559
441
  const {
560
442
  onCollisionEnter,
561
443
  onCollisionExit,
@@ -564,9 +446,9 @@ const useColliderEvents = (collidersRef, props, events) => {
564
446
  onContactForce
565
447
  } = props;
566
448
  React.useEffect(() => {
567
- var _collidersRef$current;
449
+ const collider = getCollider();
568
450
 
569
- (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
451
+ if (collider) {
570
452
  const hasCollisionEvent = !!(onCollisionEnter || onCollisionExit || onIntersectionEnter || onIntersectionExit);
571
453
  const hasContactForceEvent = !!onContactForce;
572
454
 
@@ -585,265 +467,76 @@ const useColliderEvents = (collidersRef, props, events) => {
585
467
  onIntersectionExit,
586
468
  onContactForce
587
469
  });
588
- });
589
- return () => {
590
- var _collidersRef$current2;
470
+ }
591
471
 
592
- (_collidersRef$current2 = collidersRef.current) === null || _collidersRef$current2 === void 0 ? void 0 : _collidersRef$current2.forEach(collider => events.delete(collider.handle));
472
+ return () => {
473
+ if (collider) {
474
+ events.delete(collider.handle);
475
+ }
593
476
  };
594
477
  }, [onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit, onContactForce]);
595
478
  };
596
479
 
597
- const rigidBodyDescFromOptions = options => {
598
- var _options$canSleep;
599
-
600
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
601
- const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
480
+ /**
481
+ * Exposes the Rapier context, and world
482
+ * @category Hooks
483
+ */
602
484
 
603
- desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
604
- return desc;
605
- };
606
- const createRigidBodyState = ({
607
- rigidBody,
608
- object,
609
- setMatrix,
610
- getMatrix,
611
- worldScale
612
- }) => {
613
- object.updateWorldMatrix(true, false);
614
- const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
615
- return {
616
- object,
617
- rigidBody,
618
- invertedWorldMatrix,
619
- setMatrix: setMatrix ? setMatrix : matrix => {
620
- object.matrix.copy(matrix);
621
- },
622
- getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
623
- scale: worldScale || object.getWorldScale(_scale).clone(),
624
- isSleeping: false
625
- };
485
+ const useRapier = () => {
486
+ return React.useContext(rapierContext);
626
487
  };
627
- const mutableRigidBodyOptions = {
628
- gravityScale: (rb, value) => {
629
- rb.setGravityScale(value, true);
630
- },
631
- linearDamping: (rb, value) => {
632
- rb.setLinearDamping(value);
633
- },
634
- angularDamping: (rb, value) => {
635
- rb.setAngularDamping(value);
636
- },
637
- enabledRotations: (rb, [x, y, z]) => {
638
- rb.setEnabledRotations(x, y, z, true);
639
- },
640
- enabledTranslations: (rb, [x, y, z]) => {
641
- rb.setEnabledTranslations(x, y, z, true);
642
- },
643
- lockRotations: (rb, value) => {
644
- rb.lockRotations(value, true);
645
- },
646
- lockTranslations: (rb, value) => {
647
- rb.lockTranslations(value, true);
648
- },
649
- angularVelocity: (rb, [x, y, z]) => {
650
- rb.setAngvel({
651
- x,
652
- y,
653
- z
654
- }, true);
655
- },
656
- linearVelocity: (rb, [x, y, z]) => {
657
- rb.setLinvel({
658
- x,
659
- y,
660
- z
661
- }, true);
662
- },
663
- ccd: (rb, value) => {
664
- rb.enableCcd(value);
665
- },
666
- userData: (rb, value) => {
667
- rb.userData = value;
668
- },
669
-
670
- type(rb, value) {
671
- rb.setBodyType(rigidBodyTypeFromString(value));
672
- },
488
+ /**
489
+ * Registers a callback to be called before the physics step
490
+ * @category Hooks
491
+ */
673
492
 
674
- position: () => {},
675
- rotation: () => {},
676
- quaternion: () => {},
677
- scale: () => {}
493
+ const useBeforePhysicsStep = callback => {
494
+ const {
495
+ beforeStepCallbacks
496
+ } = useRapier();
497
+ React.useEffect(() => {
498
+ beforeStepCallbacks.add(callback);
499
+ return () => {
500
+ beforeStepCallbacks.delete(callback);
501
+ };
502
+ }, []);
678
503
  };
679
- const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
680
- const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
681
- if (!rigidBody) {
682
- return;
683
- }
504
+ /**
505
+ * Registers a callback to be called after the physics step
506
+ * @category Hooks
507
+ */
684
508
 
685
- const state = states.get(rigidBody.handle);
509
+ const useAfterPhysicsStep = callback => {
510
+ const {
511
+ afterStepCallbacks
512
+ } = useRapier();
513
+ React.useEffect(() => {
514
+ afterStepCallbacks.add(callback);
515
+ return () => {
516
+ afterStepCallbacks.delete(callback);
517
+ };
518
+ }, []);
519
+ }; // Internal hooks
686
520
 
687
- if (state) {
688
- if (updateTranslations) {
689
- state.object.updateWorldMatrix(true, false);
521
+ /**
522
+ * @internal
523
+ */
690
524
 
691
- _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
525
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
526
+ const [colliderProps, setColliderProps] = React.useState([]);
527
+ React.useEffect(() => {
528
+ const object = ref.current;
692
529
 
693
- rigidBody.setTranslation(_position, false);
694
- rigidBody.setRotation(_rotation, false);
530
+ if (object && options.colliders !== false) {
531
+ setColliderProps(createColliderPropsFromChildren({
532
+ object: ref.current,
533
+ options,
534
+ ignoreMeshColliders
535
+ }));
695
536
  }
696
-
697
- mutableRigidBodyOptionKeys.forEach(key => {
698
- if (key in options) {
699
- mutableRigidBodyOptions[key](rigidBody, options[key]);
700
- }
701
- });
702
- }
703
- };
704
- const useUpdateRigidBodyOptions = (rigidBodyRef, props, states, updateTranslations = true) => {
705
- // TODO: Improve this, split each prop into its own effect
706
- const mutablePropsAsFlatArray = React.useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
707
- return vectorToTuple(props[key]);
708
- }), [props]);
709
- React.useEffect(() => {
710
- if (Array.isArray(rigidBodyRef.current)) {
711
- for (const rigidBody of rigidBodyRef.current) {
712
- setRigidBodyOptions(rigidBody, props, states, updateTranslations);
713
- }
714
- } else if (rigidBodyRef.current) {
715
- setRigidBodyOptions(rigidBodyRef.current, props, states, updateTranslations);
716
- }
717
- }, mutablePropsAsFlatArray);
718
- };
719
- const useRigidBodyEvents = (rigidBodyRef, props, events) => {
720
- const {
721
- onWake,
722
- onSleep,
723
- onCollisionEnter,
724
- onCollisionExit,
725
- onIntersectionEnter,
726
- onIntersectionExit
727
- } = props;
728
- const eventHandlers = {
729
- onWake,
730
- onSleep,
731
- onCollisionEnter,
732
- onCollisionExit,
733
- onIntersectionEnter,
734
- onIntersectionExit
735
- };
736
- React.useEffect(() => {
737
- if (Array.isArray(rigidBodyRef.current)) {
738
- for (const rigidBody of rigidBodyRef.current) {
739
- events.set(rigidBody.handle, eventHandlers);
740
- }
741
- } else if (rigidBodyRef.current) {
742
- events.set(rigidBodyRef.current.handle, eventHandlers);
743
- }
744
-
745
- return () => {
746
- if (Array.isArray(rigidBodyRef.current)) {
747
- for (const rigidBody of rigidBodyRef.current) {
748
- events.delete(rigidBody.handle);
749
- }
750
- } else if (rigidBodyRef.current) {
751
- events.delete(rigidBodyRef.current.handle);
752
- }
753
- };
754
- }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
755
- };
756
-
757
- const useRapier = () => {
758
- return React.useContext(rapierContext);
759
- };
760
- const useBeforePhysicsStep = callback => {
761
- const {
762
- beforeStepCallbacks
763
- } = useRapier();
764
- React.useEffect(() => {
765
- beforeStepCallbacks.add(callback);
766
- return () => {
767
- beforeStepCallbacks.delete(callback);
768
- };
769
- }, []);
770
- };
771
- const useAfterPhysicsStep = callback => {
772
- const {
773
- afterStepCallbacks
774
- } = useRapier();
775
- React.useEffect(() => {
776
- afterStepCallbacks.add(callback);
777
- return () => {
778
- afterStepCallbacks.delete(callback);
779
- };
780
- }, []);
781
- }; // Internal hooks
782
-
783
- const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
784
- const [colliderProps, setColliderProps] = React.useState([]);
785
- React.useEffect(() => {
786
- const object = ref.current;
787
-
788
- if (object && options.colliders !== false) {
789
- setColliderProps(createColliderPropsFromChildren({
790
- object: ref.current,
791
- options,
792
- ignoreMeshColliders
793
- }));
794
- }
795
- }, [options.colliders]);
796
- return colliderProps;
797
- };
798
- const useRigidBody = (options = {}) => {
799
- const {
800
- world,
801
- rigidBodyStates,
802
- physicsOptions,
803
- rigidBodyEvents
804
- } = useRapier();
805
- const ref = React.useRef();
806
- const mergedOptions = React.useMemo(() => {
807
- return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
808
- children: undefined
809
- });
810
- }, [physicsOptions, options]);
811
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
812
-
813
- const rigidBodyRef = React.useRef();
814
- const getRigidBodyRef = React.useRef(() => {
815
- if (!rigidBodyRef.current) {
816
- const desc = rigidBodyDescFromOptions(options);
817
- const rigidBody = world.createRigidBody(desc);
818
- rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
819
- }
820
-
821
- return rigidBodyRef.current;
822
- }); // Setup
823
-
824
- React.useEffect(() => {
825
- const rigidBody = getRigidBodyRef.current();
826
- rigidBodyRef.current = rigidBody;
827
-
828
- if (!ref.current) {
829
- ref.current = new three.Object3D();
830
- }
831
-
832
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
833
- rigidBody,
834
- object: ref.current
835
- }));
836
- return () => {
837
- world.removeRigidBody(rigidBody);
838
- rigidBodyStates.delete(rigidBody.handle);
839
- rigidBodyRef.current = undefined;
840
- };
841
- }, []);
842
- useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
843
- useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
844
- const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
845
- return [ref, api, childColliderProps];
846
- };
537
+ }, [options.colliders]);
538
+ return colliderProps;
539
+ };
847
540
 
848
541
  const calcForceByType = {
849
542
  static: (s, m2, r, d, G) => s,
@@ -961,6 +654,10 @@ const importRapier = async () => {
961
654
  return r;
962
655
  };
963
656
 
657
+ /**
658
+ * The main physics component used to create a physics world.
659
+ * @category Components
660
+ */
964
661
  const Physics = ({
965
662
  colliders: _colliders = "cuboid",
966
663
  gravity: _gravity = [0, -9.81, 0],
@@ -1054,7 +751,13 @@ const Physics = ({
1054
751
  const clampedDelta = three.MathUtils.clamp(dt, 0, 0.2);
1055
752
 
1056
753
  const stepWorld = () => {
1057
- // Trigger beforeStep callbacks
754
+ // Apply attractors
755
+ world.forEachRigidBody(body => {
756
+ attractorStates.forEach(attractorState => {
757
+ applyAttractorForceOnRigidBody(body, attractorState);
758
+ });
759
+ }); // Trigger beforeStep callbacks
760
+
1058
761
  beforeStepCallbacks.forEach(callback => {
1059
762
  callback(api);
1060
763
  });
@@ -1075,22 +778,18 @@ const Physics = ({
1075
778
  steppingState.accumulator += clampedDelta;
1076
779
 
1077
780
  while (steppingState.accumulator >= _timeStep) {
1078
- world.forEachRigidBody(body => {
1079
- // Set up previous state
1080
- // needed for accurate interpolations if the world steps more than once
1081
- if (_interpolate) {
1082
- steppingState.previousState = {};
781
+ // Set up previous state
782
+ // needed for accurate interpolations if the world steps more than once
783
+ if (_interpolate) {
784
+ steppingState.previousState = {};
785
+ world.forEachRigidBody(body => {
1083
786
  steppingState.previousState[body.handle] = {
1084
787
  position: body.translation(),
1085
788
  rotation: body.rotation()
1086
789
  };
1087
- } // Apply attractors
1088
-
1089
-
1090
- attractorStates.forEach(attractorState => {
1091
- applyAttractorForceOnRigidBody(body, attractorState);
1092
790
  });
1093
- });
791
+ }
792
+
1094
793
  stepWorld();
1095
794
  steppingState.accumulator -= _timeStep;
1096
795
  }
@@ -1118,7 +817,7 @@ const Physics = ({
1118
817
  state.isSleeping = rigidBody.isSleeping();
1119
818
  }
1120
819
 
1121
- if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
820
+ if (!rigidBody || rigidBody.isSleeping() && !("isInstancedMesh" in state.object) || !state.setMatrix) {
1122
821
  return;
1123
822
  } // New states
1124
823
 
@@ -1132,7 +831,7 @@ const Physics = ({
1132
831
  _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1133
832
 
1134
833
 
1135
- if (!(state.object instanceof three.InstancedMesh)) {
834
+ if (state.meshType == "mesh") {
1136
835
  state.object.position.copy(_position);
1137
836
  state.object.quaternion.copy(_rotation);
1138
837
  }
@@ -1141,9 +840,8 @@ const Physics = ({
1141
840
 
1142
841
  _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1143
842
 
1144
- if (state.object instanceof three.InstancedMesh) {
843
+ if (state.meshType == "instancedMesh") {
1145
844
  state.setMatrix(_matrix4);
1146
- state.object.instanceMatrix.needsUpdate = true;
1147
845
  } else {
1148
846
  // Interpolate to new position
1149
847
  state.object.position.lerp(_position, interpolationAlpha);
@@ -1327,8 +1025,87 @@ function _objectWithoutProperties(source, excluded) {
1327
1025
  return target;
1328
1026
  }
1329
1027
 
1028
+ /**
1029
+ * Initiate an instance and return a safe getter
1030
+ */
1031
+
1032
+ const useImperativeInstance = (createFn, destroyFn) => {
1033
+ const ref = React.useRef();
1034
+ const refGetter = React.useMemo(() => () => {
1035
+ if (!ref.current) {
1036
+ ref.current = createFn();
1037
+ }
1038
+
1039
+ return ref.current;
1040
+ }, []);
1041
+ React.useEffect(() => {
1042
+ const instance = refGetter();
1043
+ return () => {
1044
+ destroyFn(instance);
1045
+ ref.current = undefined;
1046
+ };
1047
+ }, []);
1048
+ return refGetter;
1049
+ };
1050
+
1051
+ /**
1052
+ * Takes an object resembling a Vector3 and returs a Three.Vector3
1053
+ * @category Math helpers
1054
+ */
1055
+
1056
+ const vec3 = ({
1057
+ x,
1058
+ y,
1059
+ z
1060
+ } = {
1061
+ x: 0,
1062
+ y: 0,
1063
+ z: 0
1064
+ }) => {
1065
+ return new three.Vector3(x, y, z);
1066
+ };
1067
+ /**
1068
+ * Takes an object resembling a Quaternion and returs a Three.Quaternion
1069
+ * @category Math helpers
1070
+ */
1071
+
1072
+ const quat = ({
1073
+ x,
1074
+ y,
1075
+ z,
1076
+ w
1077
+ } = {
1078
+ x: 0,
1079
+ y: 0,
1080
+ z: 0,
1081
+ w: 1
1082
+ }) => {
1083
+ return new three.Quaternion(x, y, z, w);
1084
+ };
1085
+ /**
1086
+ * Takes an object resembling an Euler and returs a Three.Euler
1087
+ * @category Math helpers
1088
+ */
1089
+
1090
+ const euler = ({
1091
+ x,
1092
+ y,
1093
+ z
1094
+ } = {
1095
+ x: 0,
1096
+ y: 0,
1097
+ z: 0
1098
+ }) => {
1099
+ return new three.Euler(x, y, z);
1100
+ };
1101
+
1330
1102
  // Colliders
1331
- const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["default"].forwardRef((props, forwardedRef) => {
1103
+
1104
+ /**
1105
+ * A collider is a shape that can be attached to a rigid body to define its physical properties.
1106
+ * @internal
1107
+ */
1108
+ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1332
1109
  const {
1333
1110
  children,
1334
1111
  position,
@@ -1344,52 +1121,21 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1344
1121
  } = useRapier();
1345
1122
  const rigidBodyContext = useRigidBodyContext();
1346
1123
  const ref = React.useRef(null);
1347
- const collidersRef = React.useMemo(() => {
1348
- if (forwardedRef !== null) {
1349
- return forwardedRef;
1350
- }
1351
-
1352
- const result = /*#__PURE__*/React__default["default"].createRef();
1353
- result.current = [];
1354
- return result;
1355
- }, []);
1356
- React.useEffect(() => {
1357
- const object = ref.current;
1358
- const worldScale = object.getWorldScale(new three.Vector3());
1359
- const colliders = []; // If this is an InstancedRigidBody api
1360
-
1361
- if (rigidBodyContext && "at" in rigidBodyContext.api) {
1362
- rigidBodyContext.api.forEach((body, index) => {
1363
- var _rigidBodyContext$opt, _rigidBodyContext$opt2;
1364
-
1365
- let instanceScale = worldScale;
1366
-
1367
- if ("scales" in rigidBodyContext.options && rigidBodyContext !== null && rigidBodyContext !== void 0 && (_rigidBodyContext$opt = rigidBodyContext.options) !== null && _rigidBodyContext$opt !== void 0 && (_rigidBodyContext$opt2 = _rigidBodyContext$opt.scales) !== null && _rigidBodyContext$opt2 !== void 0 && _rigidBodyContext$opt2[index]) {
1368
- instanceScale = instanceScale.clone().multiply(vectorArrayToVector3(rigidBodyContext.options.scales[index]));
1369
- }
1370
-
1371
- const collider = createColliderFromOptions(props, world, instanceScale, body.raw());
1372
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1373
- colliders.push(collider);
1374
- });
1375
- } else {
1376
- const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext && (rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.api).raw());
1377
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1378
- colliders.push(collider);
1379
- }
1380
-
1381
- collidersRef.current = colliders;
1382
- return () => {
1383
- colliders.forEach(collider => {
1384
- world.removeCollider(collider);
1385
- });
1386
- };
1387
- }, []);
1124
+ const getInstance = useImperativeInstance(() => {
1125
+ const worldScale = ref.current.getWorldScale(vec3());
1126
+ const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1127
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1128
+ return collider;
1129
+ }, collider => {
1130
+ colliderStates.delete(collider.handle);
1131
+ world.removeCollider(collider);
1132
+ });
1133
+ React.useImperativeHandle(forwardedRef, () => getInstance());
1388
1134
  const mergedProps = React.useMemo(() => {
1389
1135
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
1390
1136
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
1391
- useUpdateColliderOptions(collidersRef, mergedProps, colliderStates);
1392
- useColliderEvents(collidersRef, mergedProps, colliderEvents);
1137
+ useUpdateColliderOptions(getInstance, mergedProps, colliderStates);
1138
+ useColliderEvents(getInstance, mergedProps, colliderEvents);
1393
1139
  return /*#__PURE__*/React__default["default"].createElement("object3D", {
1394
1140
  position: position,
1395
1141
  rotation: rotation,
@@ -1399,54 +1145,99 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1399
1145
  name: name
1400
1146
  }, children);
1401
1147
  }));
1148
+
1149
+ /**
1150
+ * A cuboid collider shape
1151
+ * @category Colliders
1152
+ */
1402
1153
  const CuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1403
1154
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1404
1155
  shape: "cuboid",
1405
1156
  ref: ref
1406
1157
  }));
1407
1158
  });
1159
+ /**
1160
+ * A round cuboid collider shape
1161
+ * @category Colliders
1162
+ */
1163
+
1408
1164
  const RoundCuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1409
1165
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1410
1166
  shape: "roundCuboid",
1411
1167
  ref: ref
1412
1168
  }));
1413
1169
  });
1170
+ /**
1171
+ * A ball collider shape
1172
+ * @category Colliders
1173
+ */
1174
+
1414
1175
  const BallCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1415
1176
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1416
1177
  shape: "ball",
1417
1178
  ref: ref
1418
1179
  }));
1419
1180
  });
1181
+ /**
1182
+ * A capsule collider shape
1183
+ * @category Colliders
1184
+ */
1185
+
1420
1186
  const CapsuleCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1421
1187
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1422
1188
  shape: "capsule",
1423
1189
  ref: ref
1424
1190
  }));
1425
1191
  });
1192
+ /**
1193
+ * A heightfield collider shape
1194
+ * @category Colliders
1195
+ */
1196
+
1426
1197
  const HeightfieldCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1427
1198
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1428
1199
  shape: "heightfield",
1429
1200
  ref: ref
1430
1201
  }));
1431
1202
  });
1203
+ /**
1204
+ * A trimesh collider shape
1205
+ * @category Colliders
1206
+ */
1207
+
1432
1208
  const TrimeshCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1433
1209
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1434
1210
  shape: "trimesh",
1435
1211
  ref: ref
1436
1212
  }));
1437
1213
  });
1214
+ /**
1215
+ * A cone collider shape
1216
+ * @category Colliders
1217
+ */
1218
+
1438
1219
  const ConeCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1439
1220
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1440
1221
  shape: "cone",
1441
1222
  ref: ref
1442
1223
  }));
1443
1224
  });
1225
+ /**
1226
+ * A cylinder collider shape
1227
+ * @category Colliders
1228
+ */
1229
+
1444
1230
  const CylinderCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1445
1231
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1446
1232
  shape: "cylinder",
1447
1233
  ref: ref
1448
1234
  }));
1449
1235
  });
1236
+ /**
1237
+ * A convex hull collider shape
1238
+ * @category Colliders
1239
+ */
1240
+
1450
1241
  const ConvexHullCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1451
1242
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1452
1243
  shape: "convexHull",
@@ -1463,31 +1254,212 @@ ConeCollider.displayName = "ConeCollider";
1463
1254
  CylinderCollider.displayName = "CylinderCollider";
1464
1255
  ConvexHullCollider.displayName = "ConvexHullCollider";
1465
1256
 
1466
- const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1257
+ const rigidBodyDescFromOptions = options => {
1258
+ var _options$canSleep;
1259
+
1260
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
1261
+ const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
1262
+
1263
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
1264
+ return desc;
1265
+ };
1266
+ const createRigidBodyState = ({
1267
+ rigidBody,
1268
+ object,
1269
+ setMatrix,
1270
+ getMatrix,
1271
+ worldScale,
1272
+ meshType: _meshType = "mesh"
1273
+ }) => {
1274
+ object.updateWorldMatrix(true, false);
1275
+ const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
1276
+ return {
1277
+ object,
1278
+ rigidBody,
1279
+ invertedWorldMatrix,
1280
+ setMatrix: setMatrix ? setMatrix : matrix => {
1281
+ object.matrix.copy(matrix);
1282
+ },
1283
+ getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
1284
+ scale: worldScale || object.getWorldScale(_scale).clone(),
1285
+ isSleeping: false,
1286
+ meshType: _meshType
1287
+ };
1288
+ };
1289
+ const mutableRigidBodyOptions = {
1290
+ gravityScale: (rb, value) => {
1291
+ rb.setGravityScale(value, true);
1292
+ },
1293
+ linearDamping: (rb, value) => {
1294
+ rb.setLinearDamping(value);
1295
+ },
1296
+ angularDamping: (rb, value) => {
1297
+ rb.setAngularDamping(value);
1298
+ },
1299
+ enabledRotations: (rb, [x, y, z]) => {
1300
+ rb.setEnabledRotations(x, y, z, true);
1301
+ },
1302
+ enabledTranslations: (rb, [x, y, z]) => {
1303
+ rb.setEnabledTranslations(x, y, z, true);
1304
+ },
1305
+ lockRotations: (rb, value) => {
1306
+ rb.lockRotations(value, true);
1307
+ },
1308
+ lockTranslations: (rb, value) => {
1309
+ rb.lockTranslations(value, true);
1310
+ },
1311
+ angularVelocity: (rb, [x, y, z]) => {
1312
+ rb.setAngvel({
1313
+ x,
1314
+ y,
1315
+ z
1316
+ }, true);
1317
+ },
1318
+ linearVelocity: (rb, [x, y, z]) => {
1319
+ rb.setLinvel({
1320
+ x,
1321
+ y,
1322
+ z
1323
+ }, true);
1324
+ },
1325
+ ccd: (rb, value) => {
1326
+ rb.enableCcd(value);
1327
+ },
1328
+ userData: (rb, value) => {
1329
+ rb.userData = value;
1330
+ },
1331
+
1332
+ type(rb, value) {
1333
+ rb.setBodyType(rigidBodyTypeFromString(value), true);
1334
+ },
1335
+
1336
+ position: () => {},
1337
+ rotation: () => {},
1338
+ quaternion: () => {},
1339
+ scale: () => {}
1340
+ };
1341
+ const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
1342
+ const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
1343
+ if (!rigidBody) {
1344
+ return;
1345
+ }
1346
+
1347
+ const state = states.get(rigidBody.handle);
1348
+
1349
+ if (state) {
1350
+ if (updateTranslations) {
1351
+ state.object.updateWorldMatrix(true, false);
1352
+
1353
+ _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
1354
+
1355
+ rigidBody.setTranslation(_position, false);
1356
+ rigidBody.setRotation(_rotation, false);
1357
+ }
1358
+
1359
+ mutableRigidBodyOptionKeys.forEach(key => {
1360
+ if (key in options) {
1361
+ mutableRigidBodyOptions[key](rigidBody, options[key]);
1362
+ }
1363
+ });
1364
+ }
1365
+ };
1366
+ const useUpdateRigidBodyOptions = (getRigidBody, props, states, updateTranslations = true) => {
1367
+ // TODO: Improve this, split each prop into its own effect
1368
+ const mutablePropsAsFlatArray = React.useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
1369
+ return vectorToTuple(props[key]);
1370
+ }), [props]);
1371
+ React.useEffect(() => {
1372
+ const rigidBody = getRigidBody();
1373
+ setRigidBodyOptions(rigidBody, props, states, updateTranslations);
1374
+ }, mutablePropsAsFlatArray);
1375
+ };
1376
+ const useRigidBodyEvents = (getRigidBody, props, events) => {
1377
+ const {
1378
+ onWake,
1379
+ onSleep,
1380
+ onCollisionEnter,
1381
+ onCollisionExit,
1382
+ onIntersectionEnter,
1383
+ onIntersectionExit
1384
+ } = props;
1385
+ const eventHandlers = {
1386
+ onWake,
1387
+ onSleep,
1388
+ onCollisionEnter,
1389
+ onCollisionExit,
1390
+ onIntersectionEnter,
1391
+ onIntersectionExit
1392
+ };
1393
+ React.useEffect(() => {
1394
+ const rigidBody = getRigidBody();
1395
+ events.set(rigidBody.handle, eventHandlers);
1396
+ return () => {
1397
+ events.delete(rigidBody.handle);
1398
+ };
1399
+ }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
1400
+ };
1401
+
1402
+ const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion", "transformState"];
1467
1403
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
1468
1404
  const useRigidBodyContext = () => React.useContext(RigidBodyContext);
1469
- const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1405
+
1406
+ /**
1407
+ * A rigid body is a physical object that can be simulated by the physics engine.
1408
+ * @category Components
1409
+ */
1410
+ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1470
1411
  const {
1471
1412
  children,
1472
1413
  type,
1473
1414
  position,
1474
1415
  rotation,
1475
1416
  scale,
1476
- quaternion
1417
+ quaternion,
1418
+ transformState
1477
1419
  } = props,
1478
1420
  objectProps = _objectWithoutProperties(props, _excluded$1);
1479
1421
 
1480
- const [object, api, childColliderProps] = useRigidBody(props);
1481
- React.useImperativeHandle(ref, () => api);
1482
- const contextValue = React.useMemo(() => ({
1483
- ref: object,
1484
- api,
1485
- options: props
1486
- }), [object, api, props]);
1422
+ const ref = React.useRef(null);
1423
+ const {
1424
+ world,
1425
+ rigidBodyStates,
1426
+ physicsOptions,
1427
+ rigidBodyEvents
1428
+ } = useRapier();
1429
+ const mergedOptions = React.useMemo(() => {
1430
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), props), {}, {
1431
+ children: undefined
1432
+ });
1433
+ }, [physicsOptions, props]);
1434
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1435
+
1436
+ const getInstance = useImperativeInstance(() => {
1437
+ const desc = rigidBodyDescFromOptions(mergedOptions);
1438
+ const rigidBody = world.createRigidBody(desc);
1439
+ const state = createRigidBodyState({
1440
+ rigidBody,
1441
+ object: ref.current
1442
+ });
1443
+ rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1444
+ return rigidBody;
1445
+ }, rigidBody => {
1446
+ world.removeRigidBody(rigidBody);
1447
+ rigidBodyStates.delete(rigidBody.handle);
1448
+ });
1449
+ useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1450
+ useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1451
+ React.useImperativeHandle(forwardedRef, () => getInstance());
1452
+ const contextValue = React.useMemo(() => {
1453
+ return {
1454
+ ref,
1455
+ getRigidBody: getInstance,
1456
+ options: mergedOptions
1457
+ };
1458
+ }, [mergedOptions]);
1487
1459
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1488
1460
  value: contextValue
1489
1461
  }, /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1490
- ref: object
1462
+ ref: ref
1491
1463
  }, objectProps, {
1492
1464
  position: position,
1493
1465
  rotation: rotation,
@@ -1499,14 +1471,17 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1499
1471
  }));
1500
1472
  RigidBody.displayName = "RigidBody";
1501
1473
 
1474
+ /**
1475
+ * A mesh collider is a collider that is automatically generated from the geometry of the children.
1476
+ * @category Colliders
1477
+ */
1502
1478
  const MeshCollider = /*#__PURE__*/React.memo(props => {
1503
1479
  const {
1504
1480
  children,
1505
1481
  type
1506
1482
  } = props;
1507
1483
  const {
1508
- physicsOptions,
1509
- world
1484
+ physicsOptions
1510
1485
  } = useRapier();
1511
1486
  const object = React.useRef(null);
1512
1487
  const {
@@ -1620,155 +1595,119 @@ const Debug = /*#__PURE__*/React.memo(() => {
1620
1595
  }, attractor))));
1621
1596
  });
1622
1597
 
1623
- const _excluded = ["positions", "rotations", "children"];
1624
- const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1625
- const {
1626
- world,
1627
- rigidBodyStates,
1628
- physicsOptions,
1629
- rigidBodyEvents
1630
- } = useRapier();
1598
+ const _excluded = ["children", "instances", "colliderNodes", "position", "rotation", "quaternion", "scale"];
1599
+ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1631
1600
  const object = React.useRef(null);
1601
+ const instancedWrapper = React.useRef(null);
1632
1602
 
1633
1603
  const {
1634
- positions,
1635
- rotations,
1636
- children
1604
+ // instanced props
1605
+ children,
1606
+ instances,
1607
+ colliderNodes = [],
1608
+ // wrapper object props
1609
+ position,
1610
+ rotation,
1611
+ quaternion,
1612
+ scale
1637
1613
  } = props,
1638
- options = _objectWithoutProperties(props, _excluded);
1614
+ rigidBodyProps = _objectWithoutProperties(props, _excluded);
1639
1615
 
1640
- const instancesRef = React.useRef([]);
1641
- const rigidBodyRefs = React.useRef([]);
1642
- const instancesRefGetter = React.useRef(() => {
1643
- if (!instancesRef.current) {
1644
- instancesRef.current = [];
1645
- }
1616
+ const rigidBodyApis = React.useRef([]);
1617
+ React.useImperativeHandle(ref, () => rigidBodyApis.current, [instances]);
1618
+ const childColliderProps = useChildColliderProps(object, _objectSpread2(_objectSpread2({}, props), {}, {
1619
+ children: undefined
1620
+ }));
1646
1621
 
1647
- return instancesRef.current;
1648
- });
1649
- const mergedOptions = React.useMemo(() => {
1650
- return _objectSpread2(_objectSpread2({}, physicsOptions), options);
1651
- }, [physicsOptions, options]);
1652
- const childColliderProps = useChildColliderProps(object, mergedOptions);
1653
- React.useLayoutEffect(() => {
1654
- object.current.updateWorldMatrix(true, false);
1655
- const instances = instancesRefGetter.current();
1656
- const invertedWorld = object.current.matrixWorld.clone().invert();
1657
- object.current.traverseVisible(mesh => {
1658
- if (mesh instanceof three.InstancedMesh) {
1659
- mesh.instanceMatrix.setUsage(three.DynamicDrawUsage);
1660
- const worldScale = mesh.getWorldScale(_scale);
1661
-
1662
- for (let index = 0; index < mesh.count; index++) {
1663
- var _options$scales;
1664
-
1665
- const desc = rigidBodyDescFromOptions(props);
1666
- const rigidBody = world.createRigidBody(desc);
1667
- rigidBodyRefs.current.push(rigidBody);
1668
- const scale = ((_options$scales = options.scales) === null || _options$scales === void 0 ? void 0 : _options$scales[index]) || [1, 1, 1];
1669
- const instanceScale = worldScale.clone().multiply(vectorArrayToVector3(scale));
1670
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
1671
- rigidBody,
1672
- object: mesh,
1673
- setMatrix: matrix => mesh.setMatrixAt(index, matrix),
1674
- getMatrix: matrix => {
1675
- mesh.getMatrixAt(index, matrix);
1676
- return matrix;
1677
- },
1678
- worldScale: instanceScale
1679
- }));
1680
- const [x, y, z] = (positions === null || positions === void 0 ? void 0 : positions[index]) || [0, 0, 0];
1681
- const [rx, ry, rz] = (rotations === null || rotations === void 0 ? void 0 : rotations[index]) || [0, 0, 0];
1622
+ const getInstancedMesh = () => {
1623
+ const firstChild = instancedWrapper.current.children[0];
1682
1624
 
1683
- _object3d.position.set(x, y, z);
1625
+ if (firstChild && "isInstancedMesh" in firstChild) {
1626
+ return firstChild;
1627
+ }
1684
1628
 
1685
- _object3d.rotation.set(rx, ry, rz);
1629
+ return undefined;
1630
+ };
1686
1631
 
1687
- _object3d.applyMatrix4(invertedWorld);
1632
+ React.useEffect(() => {
1633
+ const instancedMesh = getInstancedMesh();
1688
1634
 
1689
- mesh.setMatrixAt(index, _object3d.matrix);
1690
- rigidBody.setTranslation(_object3d.position, false);
1691
- rigidBody.setRotation(_object3d.quaternion, false);
1692
- const api = createRigidBodyApi({
1693
- current() {
1694
- return rigidBody;
1695
- }
1635
+ if (instancedMesh) {
1636
+ instancedMesh.instanceMatrix.setUsage(three.DynamicDrawUsage);
1637
+ } else {
1638
+ console.warn("InstancedRigidBodies expects exactly one child, which must be an InstancedMesh");
1639
+ }
1640
+ }, []); // Update the RigidBodyStates whenever the instances change
1696
1641
 
1697
- });
1698
- instances.push({
1699
- rigidBody,
1700
- api
1701
- });
1702
- }
1703
- }
1704
- });
1705
- return () => {
1706
- instances.forEach(rb => {
1707
- world.removeRigidBody(rb.rigidBody);
1708
- rigidBodyStates.delete(rb.rigidBody.handle);
1642
+ const applyInstancedState = (state, index) => {
1643
+ const instancedMesh = getInstancedMesh();
1644
+
1645
+ if (instancedMesh) {
1646
+ return _objectSpread2(_objectSpread2({}, state), {}, {
1647
+ getMatrix: matrix => {
1648
+ instancedMesh.getMatrixAt(index, matrix);
1649
+ return matrix;
1650
+ },
1651
+ setMatrix: matrix => {
1652
+ instancedMesh.setMatrixAt(index, matrix);
1653
+ instancedMesh.instanceMatrix.needsUpdate = true;
1654
+ },
1655
+ meshType: "instancedMesh"
1709
1656
  });
1710
- rigidBodyRefs.current = [];
1711
- instancesRef.current = [];
1712
- };
1713
- }, []);
1714
- const api = React.useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1715
- React.useImperativeHandle(ref, () => api);
1716
- useUpdateRigidBodyOptions(rigidBodyRefs, mergedOptions, rigidBodyStates, false);
1717
- useRigidBodyEvents(rigidBodyRefs, mergedOptions, rigidBodyEvents);
1718
- const contextValue = React.useMemo(() => {
1719
- return {
1720
- ref: object,
1721
- api,
1722
- options: mergedOptions
1723
- };
1724
- }, [api, mergedOptions]);
1725
- return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1726
- value: contextValue
1727
- }, /*#__PURE__*/React__default["default"].createElement("object3D", {
1657
+ }
1658
+
1659
+ return state;
1660
+ };
1661
+
1662
+ return /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1728
1663
  ref: object
1729
- }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1664
+ }, rigidBodyProps, {
1665
+ position: position,
1666
+ rotation: rotation,
1667
+ quaternion: quaternion,
1668
+ scale: scale
1669
+ }), /*#__PURE__*/React__default["default"].createElement("object3D", {
1670
+ ref: instancedWrapper
1671
+ }, children), instances === null || instances === void 0 ? void 0 : instances.map((instance, index) => /*#__PURE__*/React__default["default"].createElement(RigidBody, _extends({}, rigidBodyProps, instance, {
1672
+ ref: body => rigidBodyApis.current[index] = body,
1673
+ transformState: state => applyInstancedState(state, index)
1674
+ }), /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, colliderNodes.map((node, index) => /*#__PURE__*/React__default["default"].createElement(React.Fragment, {
1730
1675
  key: index
1731
- }, colliderProps)))));
1732
- });
1676
+ }, node)), childColliderProps.map((colliderProps, colliderIndex) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1677
+ key: colliderIndex
1678
+ }, colliderProps)))))));
1679
+ }));
1733
1680
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1734
1681
 
1682
+ /**
1683
+ * @internal
1684
+ */
1685
+
1735
1686
  const useImpulseJoint = (body1, body2, params) => {
1736
1687
  const {
1737
1688
  world
1738
1689
  } = useRapier();
1739
1690
  const jointRef = React.useRef();
1740
- const getJointRef = React.useRef(() => {
1741
- if (!jointRef.current) {
1742
- let rb1;
1743
- let rb2;
1744
-
1745
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1746
- rb1 = world.getRigidBody(body1.current.handle);
1747
- rb2 = world.getRigidBody(body2.current.handle);
1748
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
1749
- jointRef.current = newJoint;
1750
- }
1691
+ useImperativeInstance(() => {
1692
+ if (body1.current && body2.current) {
1693
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1694
+ jointRef.current = newJoint;
1695
+ return newJoint;
1696
+ }
1697
+ }, joint => {
1698
+ if (joint) {
1699
+ jointRef.current = undefined;
1700
+ world.removeImpulseJoint(joint);
1751
1701
  }
1752
-
1753
- return jointRef.current;
1754
1702
  });
1755
- React.useEffect(() => {
1756
- const joint = getJointRef.current();
1757
- return () => {
1758
- if (joint) {
1759
- world.removeImpulseJoint(joint);
1760
- jointRef.current = undefined;
1761
- }
1762
- };
1763
- }, []);
1764
- const api = React.useMemo(() => createJointApi(getJointRef), []);
1765
- return api;
1703
+ return jointRef;
1766
1704
  };
1767
1705
  /**
1768
- *
1769
1706
  * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1770
1707
  * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1771
1708
  * The fixed-joint makes these frames coincide in world-space.
1709
+ *
1710
+ * @category Hooks - Joints
1772
1711
  */
1773
1712
 
1774
1713
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
@@ -1782,6 +1721,8 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
1782
1721
  * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1783
1722
  * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1784
1723
  * points that need to coincide on the local-space of each rigid-body.
1724
+ *
1725
+ * @category Hooks - Joints
1785
1726
  */
1786
1727
 
1787
1728
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
@@ -1794,6 +1735,8 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1794
1735
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1795
1736
  * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1796
1737
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
1738
+ *
1739
+ * @category Hooks - Joints
1797
1740
  */
1798
1741
 
1799
1742
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1813,6 +1756,8 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
1813
1756
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1814
1757
  * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1815
1758
  * local tangent axis can be specified for each rigid-body.
1759
+ *
1760
+ * @category Hooks - Joints
1816
1761
  */
1817
1762
 
1818
1763
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1893,7 +1838,9 @@ exports.Physics = Physics;
1893
1838
  exports.RigidBody = RigidBody;
1894
1839
  exports.RoundCuboidCollider = RoundCuboidCollider;
1895
1840
  exports.TrimeshCollider = TrimeshCollider;
1841
+ exports.euler = euler;
1896
1842
  exports.interactionGroups = interactionGroups;
1843
+ exports.quat = quat;
1897
1844
  exports.useAfterPhysicsStep = useAfterPhysicsStep;
1898
1845
  exports.useBeforePhysicsStep = useBeforePhysicsStep;
1899
1846
  exports.useFixedJoint = useFixedJoint;
@@ -1902,3 +1849,4 @@ exports.usePrismaticJoint = usePrismaticJoint;
1902
1849
  exports.useRapier = useRapier;
1903
1850
  exports.useRevoluteJoint = useRevoluteJoint;
1904
1851
  exports.useSphericalJoint = useSphericalJoint;
1852
+ exports.vec3 = vec3;