@react-three/rapier 0.12.2 → 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 +534 -588
  21. package/dist/react-three-rapier.cjs.prod.js +534 -588
  22. package/dist/react-three-rapier.esm.js +535 -592
  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],
@@ -1120,7 +817,7 @@ const Physics = ({
1120
817
  state.isSleeping = rigidBody.isSleeping();
1121
818
  }
1122
819
 
1123
- if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
820
+ if (!rigidBody || rigidBody.isSleeping() && !("isInstancedMesh" in state.object) || !state.setMatrix) {
1124
821
  return;
1125
822
  } // New states
1126
823
 
@@ -1134,7 +831,7 @@ const Physics = ({
1134
831
  _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1135
832
 
1136
833
 
1137
- if (!(state.object instanceof three.InstancedMesh)) {
834
+ if (state.meshType == "mesh") {
1138
835
  state.object.position.copy(_position);
1139
836
  state.object.quaternion.copy(_rotation);
1140
837
  }
@@ -1143,9 +840,8 @@ const Physics = ({
1143
840
 
1144
841
  _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1145
842
 
1146
- if (state.object instanceof three.InstancedMesh) {
843
+ if (state.meshType == "instancedMesh") {
1147
844
  state.setMatrix(_matrix4);
1148
- state.object.instanceMatrix.needsUpdate = true;
1149
845
  } else {
1150
846
  // Interpolate to new position
1151
847
  state.object.position.lerp(_position, interpolationAlpha);
@@ -1329,8 +1025,87 @@ function _objectWithoutProperties(source, excluded) {
1329
1025
  return target;
1330
1026
  }
1331
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
+
1332
1102
  // Colliders
1333
- 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) => {
1334
1109
  const {
1335
1110
  children,
1336
1111
  position,
@@ -1346,52 +1121,21 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1346
1121
  } = useRapier();
1347
1122
  const rigidBodyContext = useRigidBodyContext();
1348
1123
  const ref = React.useRef(null);
1349
- const collidersRef = React.useMemo(() => {
1350
- if (forwardedRef !== null) {
1351
- return forwardedRef;
1352
- }
1353
-
1354
- const result = /*#__PURE__*/React__default["default"].createRef();
1355
- result.current = [];
1356
- return result;
1357
- }, []);
1358
- React.useEffect(() => {
1359
- const object = ref.current;
1360
- const worldScale = object.getWorldScale(new three.Vector3());
1361
- const colliders = []; // If this is an InstancedRigidBody api
1362
-
1363
- if (rigidBodyContext && "at" in rigidBodyContext.api) {
1364
- rigidBodyContext.api.forEach((body, index) => {
1365
- var _rigidBodyContext$opt, _rigidBodyContext$opt2;
1366
-
1367
- let instanceScale = worldScale;
1368
-
1369
- 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]) {
1370
- instanceScale = instanceScale.clone().multiply(vectorArrayToVector3(rigidBodyContext.options.scales[index]));
1371
- }
1372
-
1373
- const collider = createColliderFromOptions(props, world, instanceScale, body.raw());
1374
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1375
- colliders.push(collider);
1376
- });
1377
- } else {
1378
- const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext && (rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.api).raw());
1379
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1380
- colliders.push(collider);
1381
- }
1382
-
1383
- collidersRef.current = colliders;
1384
- return () => {
1385
- colliders.forEach(collider => {
1386
- world.removeCollider(collider);
1387
- });
1388
- };
1389
- }, []);
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());
1390
1134
  const mergedProps = React.useMemo(() => {
1391
1135
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
1392
1136
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
1393
- useUpdateColliderOptions(collidersRef, mergedProps, colliderStates);
1394
- useColliderEvents(collidersRef, mergedProps, colliderEvents);
1137
+ useUpdateColliderOptions(getInstance, mergedProps, colliderStates);
1138
+ useColliderEvents(getInstance, mergedProps, colliderEvents);
1395
1139
  return /*#__PURE__*/React__default["default"].createElement("object3D", {
1396
1140
  position: position,
1397
1141
  rotation: rotation,
@@ -1401,54 +1145,99 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1401
1145
  name: name
1402
1146
  }, children);
1403
1147
  }));
1148
+
1149
+ /**
1150
+ * A cuboid collider shape
1151
+ * @category Colliders
1152
+ */
1404
1153
  const CuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1405
1154
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1406
1155
  shape: "cuboid",
1407
1156
  ref: ref
1408
1157
  }));
1409
1158
  });
1159
+ /**
1160
+ * A round cuboid collider shape
1161
+ * @category Colliders
1162
+ */
1163
+
1410
1164
  const RoundCuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1411
1165
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1412
1166
  shape: "roundCuboid",
1413
1167
  ref: ref
1414
1168
  }));
1415
1169
  });
1170
+ /**
1171
+ * A ball collider shape
1172
+ * @category Colliders
1173
+ */
1174
+
1416
1175
  const BallCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1417
1176
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1418
1177
  shape: "ball",
1419
1178
  ref: ref
1420
1179
  }));
1421
1180
  });
1181
+ /**
1182
+ * A capsule collider shape
1183
+ * @category Colliders
1184
+ */
1185
+
1422
1186
  const CapsuleCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1423
1187
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1424
1188
  shape: "capsule",
1425
1189
  ref: ref
1426
1190
  }));
1427
1191
  });
1192
+ /**
1193
+ * A heightfield collider shape
1194
+ * @category Colliders
1195
+ */
1196
+
1428
1197
  const HeightfieldCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1429
1198
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1430
1199
  shape: "heightfield",
1431
1200
  ref: ref
1432
1201
  }));
1433
1202
  });
1203
+ /**
1204
+ * A trimesh collider shape
1205
+ * @category Colliders
1206
+ */
1207
+
1434
1208
  const TrimeshCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1435
1209
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1436
1210
  shape: "trimesh",
1437
1211
  ref: ref
1438
1212
  }));
1439
1213
  });
1214
+ /**
1215
+ * A cone collider shape
1216
+ * @category Colliders
1217
+ */
1218
+
1440
1219
  const ConeCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1441
1220
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1442
1221
  shape: "cone",
1443
1222
  ref: ref
1444
1223
  }));
1445
1224
  });
1225
+ /**
1226
+ * A cylinder collider shape
1227
+ * @category Colliders
1228
+ */
1229
+
1446
1230
  const CylinderCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1447
1231
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1448
1232
  shape: "cylinder",
1449
1233
  ref: ref
1450
1234
  }));
1451
1235
  });
1236
+ /**
1237
+ * A convex hull collider shape
1238
+ * @category Colliders
1239
+ */
1240
+
1452
1241
  const ConvexHullCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1453
1242
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1454
1243
  shape: "convexHull",
@@ -1465,31 +1254,212 @@ ConeCollider.displayName = "ConeCollider";
1465
1254
  CylinderCollider.displayName = "CylinderCollider";
1466
1255
  ConvexHullCollider.displayName = "ConvexHullCollider";
1467
1256
 
1468
- 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"];
1469
1403
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
1470
1404
  const useRigidBodyContext = () => React.useContext(RigidBodyContext);
1471
- 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) => {
1472
1411
  const {
1473
1412
  children,
1474
1413
  type,
1475
1414
  position,
1476
1415
  rotation,
1477
1416
  scale,
1478
- quaternion
1417
+ quaternion,
1418
+ transformState
1479
1419
  } = props,
1480
1420
  objectProps = _objectWithoutProperties(props, _excluded$1);
1481
1421
 
1482
- const [object, api, childColliderProps] = useRigidBody(props);
1483
- React.useImperativeHandle(ref, () => api);
1484
- const contextValue = React.useMemo(() => ({
1485
- ref: object,
1486
- api,
1487
- options: props
1488
- }), [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]);
1489
1459
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1490
1460
  value: contextValue
1491
1461
  }, /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1492
- ref: object
1462
+ ref: ref
1493
1463
  }, objectProps, {
1494
1464
  position: position,
1495
1465
  rotation: rotation,
@@ -1501,14 +1471,17 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1501
1471
  }));
1502
1472
  RigidBody.displayName = "RigidBody";
1503
1473
 
1474
+ /**
1475
+ * A mesh collider is a collider that is automatically generated from the geometry of the children.
1476
+ * @category Colliders
1477
+ */
1504
1478
  const MeshCollider = /*#__PURE__*/React.memo(props => {
1505
1479
  const {
1506
1480
  children,
1507
1481
  type
1508
1482
  } = props;
1509
1483
  const {
1510
- physicsOptions,
1511
- world
1484
+ physicsOptions
1512
1485
  } = useRapier();
1513
1486
  const object = React.useRef(null);
1514
1487
  const {
@@ -1622,155 +1595,119 @@ const Debug = /*#__PURE__*/React.memo(() => {
1622
1595
  }, attractor))));
1623
1596
  });
1624
1597
 
1625
- const _excluded = ["positions", "rotations", "children"];
1626
- const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1627
- const {
1628
- world,
1629
- rigidBodyStates,
1630
- physicsOptions,
1631
- rigidBodyEvents
1632
- } = useRapier();
1598
+ const _excluded = ["children", "instances", "colliderNodes", "position", "rotation", "quaternion", "scale"];
1599
+ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1633
1600
  const object = React.useRef(null);
1601
+ const instancedWrapper = React.useRef(null);
1634
1602
 
1635
1603
  const {
1636
- positions,
1637
- rotations,
1638
- children
1604
+ // instanced props
1605
+ children,
1606
+ instances,
1607
+ colliderNodes = [],
1608
+ // wrapper object props
1609
+ position,
1610
+ rotation,
1611
+ quaternion,
1612
+ scale
1639
1613
  } = props,
1640
- options = _objectWithoutProperties(props, _excluded);
1614
+ rigidBodyProps = _objectWithoutProperties(props, _excluded);
1641
1615
 
1642
- const instancesRef = React.useRef([]);
1643
- const rigidBodyRefs = React.useRef([]);
1644
- const instancesRefGetter = React.useRef(() => {
1645
- if (!instancesRef.current) {
1646
- instancesRef.current = [];
1647
- }
1616
+ const rigidBodyApis = React.useRef([]);
1617
+ React.useImperativeHandle(ref, () => rigidBodyApis.current, [instances]);
1618
+ const childColliderProps = useChildColliderProps(object, _objectSpread2(_objectSpread2({}, props), {}, {
1619
+ children: undefined
1620
+ }));
1648
1621
 
1649
- return instancesRef.current;
1650
- });
1651
- const mergedOptions = React.useMemo(() => {
1652
- return _objectSpread2(_objectSpread2({}, physicsOptions), options);
1653
- }, [physicsOptions, options]);
1654
- const childColliderProps = useChildColliderProps(object, mergedOptions);
1655
- React.useLayoutEffect(() => {
1656
- object.current.updateWorldMatrix(true, false);
1657
- const instances = instancesRefGetter.current();
1658
- const invertedWorld = object.current.matrixWorld.clone().invert();
1659
- object.current.traverseVisible(mesh => {
1660
- if (mesh instanceof three.InstancedMesh) {
1661
- mesh.instanceMatrix.setUsage(three.DynamicDrawUsage);
1662
- const worldScale = mesh.getWorldScale(_scale);
1663
-
1664
- for (let index = 0; index < mesh.count; index++) {
1665
- var _options$scales;
1666
-
1667
- const desc = rigidBodyDescFromOptions(props);
1668
- const rigidBody = world.createRigidBody(desc);
1669
- rigidBodyRefs.current.push(rigidBody);
1670
- const scale = ((_options$scales = options.scales) === null || _options$scales === void 0 ? void 0 : _options$scales[index]) || [1, 1, 1];
1671
- const instanceScale = worldScale.clone().multiply(vectorArrayToVector3(scale));
1672
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
1673
- rigidBody,
1674
- object: mesh,
1675
- setMatrix: matrix => mesh.setMatrixAt(index, matrix),
1676
- getMatrix: matrix => {
1677
- mesh.getMatrixAt(index, matrix);
1678
- return matrix;
1679
- },
1680
- worldScale: instanceScale
1681
- }));
1682
- const [x, y, z] = (positions === null || positions === void 0 ? void 0 : positions[index]) || [0, 0, 0];
1683
- 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];
1684
1624
 
1685
- _object3d.position.set(x, y, z);
1625
+ if (firstChild && "isInstancedMesh" in firstChild) {
1626
+ return firstChild;
1627
+ }
1686
1628
 
1687
- _object3d.rotation.set(rx, ry, rz);
1629
+ return undefined;
1630
+ };
1688
1631
 
1689
- _object3d.applyMatrix4(invertedWorld);
1632
+ React.useEffect(() => {
1633
+ const instancedMesh = getInstancedMesh();
1690
1634
 
1691
- mesh.setMatrixAt(index, _object3d.matrix);
1692
- rigidBody.setTranslation(_object3d.position, false);
1693
- rigidBody.setRotation(_object3d.quaternion, false);
1694
- const api = createRigidBodyApi({
1695
- current() {
1696
- return rigidBody;
1697
- }
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
1698
1641
 
1699
- });
1700
- instances.push({
1701
- rigidBody,
1702
- api
1703
- });
1704
- }
1705
- }
1706
- });
1707
- return () => {
1708
- instances.forEach(rb => {
1709
- world.removeRigidBody(rb.rigidBody);
1710
- 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"
1711
1656
  });
1712
- rigidBodyRefs.current = [];
1713
- instancesRef.current = [];
1714
- };
1715
- }, []);
1716
- const api = React.useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1717
- React.useImperativeHandle(ref, () => api);
1718
- useUpdateRigidBodyOptions(rigidBodyRefs, mergedOptions, rigidBodyStates, false);
1719
- useRigidBodyEvents(rigidBodyRefs, mergedOptions, rigidBodyEvents);
1720
- const contextValue = React.useMemo(() => {
1721
- return {
1722
- ref: object,
1723
- api,
1724
- options: mergedOptions
1725
- };
1726
- }, [api, mergedOptions]);
1727
- return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1728
- value: contextValue
1729
- }, /*#__PURE__*/React__default["default"].createElement("object3D", {
1657
+ }
1658
+
1659
+ return state;
1660
+ };
1661
+
1662
+ return /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1730
1663
  ref: object
1731
- }, 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, {
1732
1675
  key: index
1733
- }, colliderProps)))));
1734
- });
1676
+ }, node)), childColliderProps.map((colliderProps, colliderIndex) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1677
+ key: colliderIndex
1678
+ }, colliderProps)))))));
1679
+ }));
1735
1680
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1736
1681
 
1682
+ /**
1683
+ * @internal
1684
+ */
1685
+
1737
1686
  const useImpulseJoint = (body1, body2, params) => {
1738
1687
  const {
1739
1688
  world
1740
1689
  } = useRapier();
1741
1690
  const jointRef = React.useRef();
1742
- const getJointRef = React.useRef(() => {
1743
- if (!jointRef.current) {
1744
- let rb1;
1745
- let rb2;
1746
-
1747
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1748
- rb1 = world.getRigidBody(body1.current.handle);
1749
- rb2 = world.getRigidBody(body2.current.handle);
1750
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
1751
- jointRef.current = newJoint;
1752
- }
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);
1753
1701
  }
1754
-
1755
- return jointRef.current;
1756
1702
  });
1757
- React.useEffect(() => {
1758
- const joint = getJointRef.current();
1759
- return () => {
1760
- if (joint) {
1761
- world.removeImpulseJoint(joint);
1762
- jointRef.current = undefined;
1763
- }
1764
- };
1765
- }, []);
1766
- const api = React.useMemo(() => createJointApi(getJointRef), []);
1767
- return api;
1703
+ return jointRef;
1768
1704
  };
1769
1705
  /**
1770
- *
1771
1706
  * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1772
1707
  * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1773
1708
  * The fixed-joint makes these frames coincide in world-space.
1709
+ *
1710
+ * @category Hooks - Joints
1774
1711
  */
1775
1712
 
1776
1713
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
@@ -1784,6 +1721,8 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
1784
1721
  * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1785
1722
  * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1786
1723
  * points that need to coincide on the local-space of each rigid-body.
1724
+ *
1725
+ * @category Hooks - Joints
1787
1726
  */
1788
1727
 
1789
1728
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
@@ -1796,6 +1735,8 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1796
1735
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1797
1736
  * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1798
1737
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
1738
+ *
1739
+ * @category Hooks - Joints
1799
1740
  */
1800
1741
 
1801
1742
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1815,6 +1756,8 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
1815
1756
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1816
1757
  * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1817
1758
  * local tangent axis can be specified for each rigid-body.
1759
+ *
1760
+ * @category Hooks - Joints
1818
1761
  */
1819
1762
 
1820
1763
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1895,7 +1838,9 @@ exports.Physics = Physics;
1895
1838
  exports.RigidBody = RigidBody;
1896
1839
  exports.RoundCuboidCollider = RoundCuboidCollider;
1897
1840
  exports.TrimeshCollider = TrimeshCollider;
1841
+ exports.euler = euler;
1898
1842
  exports.interactionGroups = interactionGroups;
1843
+ exports.quat = quat;
1899
1844
  exports.useAfterPhysicsStep = useAfterPhysicsStep;
1900
1845
  exports.useBeforePhysicsStep = useBeforePhysicsStep;
1901
1846
  exports.useFixedJoint = useFixedJoint;
@@ -1904,3 +1849,4 @@ exports.usePrismaticJoint = usePrismaticJoint;
1904
1849
  exports.useRapier = useRapier;
1905
1850
  exports.useRevoluteJoint = useRevoluteJoint;
1906
1851
  exports.useSphericalJoint = useSphericalJoint;
1852
+ exports.vec3 = vec3;