@react-three/rapier 0.12.2 → 0.13.1

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} +10 -3
  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 +546 -589
  21. package/dist/react-three-rapier.cjs.prod.js +546 -589
  22. package/dist/react-three-rapier.esm.js +547 -593
  23. package/package.json +12 -12
  24. package/readme.md +165 -52
  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,87 @@ 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;
480
+ const useMutableCallback = fn => {
481
+ const ref = React.useRef(fn);
482
+ React.useEffect(() => {
483
+ ref.current = fn;
484
+ }, [fn]);
485
+ return ref;
486
+ }; // External hooks
599
487
 
600
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
601
- const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
488
+ /**
489
+ * Exposes the Rapier context, and world
490
+ * @category Hooks
491
+ */
602
492
 
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
- };
626
- };
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
493
 
670
- type(rb, value) {
671
- rb.setBodyType(rigidBodyTypeFromString(value));
672
- },
494
+ const useRapier = () => {
495
+ return React.useContext(rapierContext);
496
+ };
497
+ /**
498
+ * Registers a callback to be called before the physics step
499
+ * @category Hooks
500
+ */
673
501
 
674
- position: () => {},
675
- rotation: () => {},
676
- quaternion: () => {},
677
- scale: () => {}
502
+ const useBeforePhysicsStep = callback => {
503
+ const {
504
+ beforeStepCallbacks
505
+ } = useRapier();
506
+ const ref = useMutableCallback(callback);
507
+ React.useEffect(() => {
508
+ beforeStepCallbacks.add(ref);
509
+ return () => {
510
+ beforeStepCallbacks.delete(ref);
511
+ };
512
+ }, []);
678
513
  };
679
- const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
680
- const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
681
- if (!rigidBody) {
682
- return;
683
- }
514
+ /**
515
+ * Registers a callback to be called after the physics step
516
+ * @category Hooks
517
+ */
684
518
 
685
- const state = states.get(rigidBody.handle);
519
+ const useAfterPhysicsStep = callback => {
520
+ const {
521
+ afterStepCallbacks
522
+ } = useRapier();
523
+ const ref = useMutableCallback(callback);
524
+ React.useEffect(() => {
525
+ afterStepCallbacks.add(ref);
526
+ return () => {
527
+ afterStepCallbacks.delete(ref);
528
+ };
529
+ }, []);
530
+ }; // Internal hooks
686
531
 
687
- if (state) {
688
- if (updateTranslations) {
689
- state.object.updateWorldMatrix(true, false);
532
+ /**
533
+ * @internal
534
+ */
690
535
 
691
- _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
536
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
537
+ const [colliderProps, setColliderProps] = React.useState([]);
538
+ React.useEffect(() => {
539
+ const object = ref.current;
692
540
 
693
- rigidBody.setTranslation(_position, false);
694
- rigidBody.setRotation(_rotation, false);
541
+ if (object && options.colliders !== false) {
542
+ setColliderProps(createColliderPropsFromChildren({
543
+ object: ref.current,
544
+ options,
545
+ ignoreMeshColliders
546
+ }));
695
547
  }
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
- };
548
+ }, [options.colliders]);
549
+ return colliderProps;
550
+ };
847
551
 
848
552
  const calcForceByType = {
849
553
  static: (s, m2, r, d, G) => s,
@@ -961,6 +665,10 @@ const importRapier = async () => {
961
665
  return r;
962
666
  };
963
667
 
668
+ /**
669
+ * The main physics component used to create a physics world.
670
+ * @category Components
671
+ */
964
672
  const Physics = ({
965
673
  colliders: _colliders = "cuboid",
966
674
  gravity: _gravity = [0, -9.81, 0],
@@ -1062,12 +770,12 @@ const Physics = ({
1062
770
  }); // Trigger beforeStep callbacks
1063
771
 
1064
772
  beforeStepCallbacks.forEach(callback => {
1065
- callback(api);
773
+ callback.current(api);
1066
774
  });
1067
775
  world.step(eventQueue); // Trigger afterStep callbacks
1068
776
 
1069
777
  afterStepCallbacks.forEach(callback => {
1070
- callback(api);
778
+ callback.current(api);
1071
779
  });
1072
780
  };
1073
781
 
@@ -1120,7 +828,7 @@ const Physics = ({
1120
828
  state.isSleeping = rigidBody.isSleeping();
1121
829
  }
1122
830
 
1123
- if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
831
+ if (!rigidBody || rigidBody.isSleeping() && !("isInstancedMesh" in state.object) || !state.setMatrix) {
1124
832
  return;
1125
833
  } // New states
1126
834
 
@@ -1134,7 +842,7 @@ const Physics = ({
1134
842
  _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1135
843
 
1136
844
 
1137
- if (!(state.object instanceof three.InstancedMesh)) {
845
+ if (state.meshType == "mesh") {
1138
846
  state.object.position.copy(_position);
1139
847
  state.object.quaternion.copy(_rotation);
1140
848
  }
@@ -1143,9 +851,8 @@ const Physics = ({
1143
851
 
1144
852
  _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1145
853
 
1146
- if (state.object instanceof three.InstancedMesh) {
854
+ if (state.meshType == "instancedMesh") {
1147
855
  state.setMatrix(_matrix4);
1148
- state.object.instanceMatrix.needsUpdate = true;
1149
856
  } else {
1150
857
  // Interpolate to new position
1151
858
  state.object.position.lerp(_position, interpolationAlpha);
@@ -1329,8 +1036,87 @@ function _objectWithoutProperties(source, excluded) {
1329
1036
  return target;
1330
1037
  }
1331
1038
 
1039
+ /**
1040
+ * Initiate an instance and return a safe getter
1041
+ */
1042
+
1043
+ const useImperativeInstance = (createFn, destroyFn) => {
1044
+ const ref = React.useRef();
1045
+ const refGetter = React.useMemo(() => () => {
1046
+ if (!ref.current) {
1047
+ ref.current = createFn();
1048
+ }
1049
+
1050
+ return ref.current;
1051
+ }, []);
1052
+ React.useEffect(() => {
1053
+ const instance = refGetter();
1054
+ return () => {
1055
+ destroyFn(instance);
1056
+ ref.current = undefined;
1057
+ };
1058
+ }, []);
1059
+ return refGetter;
1060
+ };
1061
+
1062
+ /**
1063
+ * Takes an object resembling a Vector3 and returs a Three.Vector3
1064
+ * @category Math helpers
1065
+ */
1066
+
1067
+ const vec3 = ({
1068
+ x,
1069
+ y,
1070
+ z
1071
+ } = {
1072
+ x: 0,
1073
+ y: 0,
1074
+ z: 0
1075
+ }) => {
1076
+ return new three.Vector3(x, y, z);
1077
+ };
1078
+ /**
1079
+ * Takes an object resembling a Quaternion and returs a Three.Quaternion
1080
+ * @category Math helpers
1081
+ */
1082
+
1083
+ const quat = ({
1084
+ x,
1085
+ y,
1086
+ z,
1087
+ w
1088
+ } = {
1089
+ x: 0,
1090
+ y: 0,
1091
+ z: 0,
1092
+ w: 1
1093
+ }) => {
1094
+ return new three.Quaternion(x, y, z, w);
1095
+ };
1096
+ /**
1097
+ * Takes an object resembling an Euler and returs a Three.Euler
1098
+ * @category Math helpers
1099
+ */
1100
+
1101
+ const euler = ({
1102
+ x,
1103
+ y,
1104
+ z
1105
+ } = {
1106
+ x: 0,
1107
+ y: 0,
1108
+ z: 0
1109
+ }) => {
1110
+ return new three.Euler(x, y, z);
1111
+ };
1112
+
1332
1113
  // Colliders
1333
- const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["default"].forwardRef((props, forwardedRef) => {
1114
+
1115
+ /**
1116
+ * A collider is a shape that can be attached to a rigid body to define its physical properties.
1117
+ * @internal
1118
+ */
1119
+ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1334
1120
  const {
1335
1121
  children,
1336
1122
  position,
@@ -1346,52 +1132,21 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1346
1132
  } = useRapier();
1347
1133
  const rigidBodyContext = useRigidBodyContext();
1348
1134
  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
- }, []);
1135
+ const getInstance = useImperativeInstance(() => {
1136
+ const worldScale = ref.current.getWorldScale(vec3());
1137
+ const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1138
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1139
+ return collider;
1140
+ }, collider => {
1141
+ colliderStates.delete(collider.handle);
1142
+ world.removeCollider(collider);
1143
+ });
1144
+ React.useImperativeHandle(forwardedRef, () => getInstance());
1390
1145
  const mergedProps = React.useMemo(() => {
1391
1146
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
1392
1147
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
1393
- useUpdateColliderOptions(collidersRef, mergedProps, colliderStates);
1394
- useColliderEvents(collidersRef, mergedProps, colliderEvents);
1148
+ useUpdateColliderOptions(getInstance, mergedProps, colliderStates);
1149
+ useColliderEvents(getInstance, mergedProps, colliderEvents);
1395
1150
  return /*#__PURE__*/React__default["default"].createElement("object3D", {
1396
1151
  position: position,
1397
1152
  rotation: rotation,
@@ -1401,54 +1156,99 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1401
1156
  name: name
1402
1157
  }, children);
1403
1158
  }));
1159
+
1160
+ /**
1161
+ * A cuboid collider shape
1162
+ * @category Colliders
1163
+ */
1404
1164
  const CuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1405
1165
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1406
1166
  shape: "cuboid",
1407
1167
  ref: ref
1408
1168
  }));
1409
1169
  });
1170
+ /**
1171
+ * A round cuboid collider shape
1172
+ * @category Colliders
1173
+ */
1174
+
1410
1175
  const RoundCuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1411
1176
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1412
1177
  shape: "roundCuboid",
1413
1178
  ref: ref
1414
1179
  }));
1415
1180
  });
1181
+ /**
1182
+ * A ball collider shape
1183
+ * @category Colliders
1184
+ */
1185
+
1416
1186
  const BallCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1417
1187
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1418
1188
  shape: "ball",
1419
1189
  ref: ref
1420
1190
  }));
1421
1191
  });
1192
+ /**
1193
+ * A capsule collider shape
1194
+ * @category Colliders
1195
+ */
1196
+
1422
1197
  const CapsuleCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1423
1198
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1424
1199
  shape: "capsule",
1425
1200
  ref: ref
1426
1201
  }));
1427
1202
  });
1203
+ /**
1204
+ * A heightfield collider shape
1205
+ * @category Colliders
1206
+ */
1207
+
1428
1208
  const HeightfieldCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1429
1209
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1430
1210
  shape: "heightfield",
1431
1211
  ref: ref
1432
1212
  }));
1433
1213
  });
1214
+ /**
1215
+ * A trimesh collider shape
1216
+ * @category Colliders
1217
+ */
1218
+
1434
1219
  const TrimeshCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1435
1220
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1436
1221
  shape: "trimesh",
1437
1222
  ref: ref
1438
1223
  }));
1439
1224
  });
1225
+ /**
1226
+ * A cone collider shape
1227
+ * @category Colliders
1228
+ */
1229
+
1440
1230
  const ConeCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1441
1231
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1442
1232
  shape: "cone",
1443
1233
  ref: ref
1444
1234
  }));
1445
1235
  });
1236
+ /**
1237
+ * A cylinder collider shape
1238
+ * @category Colliders
1239
+ */
1240
+
1446
1241
  const CylinderCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1447
1242
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1448
1243
  shape: "cylinder",
1449
1244
  ref: ref
1450
1245
  }));
1451
1246
  });
1247
+ /**
1248
+ * A convex hull collider shape
1249
+ * @category Colliders
1250
+ */
1251
+
1452
1252
  const ConvexHullCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
1453
1253
  return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
1454
1254
  shape: "convexHull",
@@ -1465,31 +1265,212 @@ ConeCollider.displayName = "ConeCollider";
1465
1265
  CylinderCollider.displayName = "CylinderCollider";
1466
1266
  ConvexHullCollider.displayName = "ConvexHullCollider";
1467
1267
 
1468
- const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1268
+ const rigidBodyDescFromOptions = options => {
1269
+ var _options$canSleep;
1270
+
1271
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
1272
+ const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
1273
+
1274
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
1275
+ return desc;
1276
+ };
1277
+ const createRigidBodyState = ({
1278
+ rigidBody,
1279
+ object,
1280
+ setMatrix,
1281
+ getMatrix,
1282
+ worldScale,
1283
+ meshType: _meshType = "mesh"
1284
+ }) => {
1285
+ object.updateWorldMatrix(true, false);
1286
+ const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
1287
+ return {
1288
+ object,
1289
+ rigidBody,
1290
+ invertedWorldMatrix,
1291
+ setMatrix: setMatrix ? setMatrix : matrix => {
1292
+ object.matrix.copy(matrix);
1293
+ },
1294
+ getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
1295
+ scale: worldScale || object.getWorldScale(_scale).clone(),
1296
+ isSleeping: false,
1297
+ meshType: _meshType
1298
+ };
1299
+ };
1300
+ const mutableRigidBodyOptions = {
1301
+ gravityScale: (rb, value) => {
1302
+ rb.setGravityScale(value, true);
1303
+ },
1304
+ linearDamping: (rb, value) => {
1305
+ rb.setLinearDamping(value);
1306
+ },
1307
+ angularDamping: (rb, value) => {
1308
+ rb.setAngularDamping(value);
1309
+ },
1310
+ enabledRotations: (rb, [x, y, z]) => {
1311
+ rb.setEnabledRotations(x, y, z, true);
1312
+ },
1313
+ enabledTranslations: (rb, [x, y, z]) => {
1314
+ rb.setEnabledTranslations(x, y, z, true);
1315
+ },
1316
+ lockRotations: (rb, value) => {
1317
+ rb.lockRotations(value, true);
1318
+ },
1319
+ lockTranslations: (rb, value) => {
1320
+ rb.lockTranslations(value, true);
1321
+ },
1322
+ angularVelocity: (rb, [x, y, z]) => {
1323
+ rb.setAngvel({
1324
+ x,
1325
+ y,
1326
+ z
1327
+ }, true);
1328
+ },
1329
+ linearVelocity: (rb, [x, y, z]) => {
1330
+ rb.setLinvel({
1331
+ x,
1332
+ y,
1333
+ z
1334
+ }, true);
1335
+ },
1336
+ ccd: (rb, value) => {
1337
+ rb.enableCcd(value);
1338
+ },
1339
+ userData: (rb, value) => {
1340
+ rb.userData = value;
1341
+ },
1342
+
1343
+ type(rb, value) {
1344
+ rb.setBodyType(rigidBodyTypeFromString(value), true);
1345
+ },
1346
+
1347
+ position: () => {},
1348
+ rotation: () => {},
1349
+ quaternion: () => {},
1350
+ scale: () => {}
1351
+ };
1352
+ const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
1353
+ const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
1354
+ if (!rigidBody) {
1355
+ return;
1356
+ }
1357
+
1358
+ const state = states.get(rigidBody.handle);
1359
+
1360
+ if (state) {
1361
+ if (updateTranslations) {
1362
+ state.object.updateWorldMatrix(true, false);
1363
+
1364
+ _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
1365
+
1366
+ rigidBody.setTranslation(_position, false);
1367
+ rigidBody.setRotation(_rotation, false);
1368
+ }
1369
+
1370
+ mutableRigidBodyOptionKeys.forEach(key => {
1371
+ if (key in options) {
1372
+ mutableRigidBodyOptions[key](rigidBody, options[key]);
1373
+ }
1374
+ });
1375
+ }
1376
+ };
1377
+ const useUpdateRigidBodyOptions = (getRigidBody, props, states, updateTranslations = true) => {
1378
+ // TODO: Improve this, split each prop into its own effect
1379
+ const mutablePropsAsFlatArray = React.useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
1380
+ return vectorToTuple(props[key]);
1381
+ }), [props]);
1382
+ React.useEffect(() => {
1383
+ const rigidBody = getRigidBody();
1384
+ setRigidBodyOptions(rigidBody, props, states, updateTranslations);
1385
+ }, mutablePropsAsFlatArray);
1386
+ };
1387
+ const useRigidBodyEvents = (getRigidBody, props, events) => {
1388
+ const {
1389
+ onWake,
1390
+ onSleep,
1391
+ onCollisionEnter,
1392
+ onCollisionExit,
1393
+ onIntersectionEnter,
1394
+ onIntersectionExit
1395
+ } = props;
1396
+ const eventHandlers = {
1397
+ onWake,
1398
+ onSleep,
1399
+ onCollisionEnter,
1400
+ onCollisionExit,
1401
+ onIntersectionEnter,
1402
+ onIntersectionExit
1403
+ };
1404
+ React.useEffect(() => {
1405
+ const rigidBody = getRigidBody();
1406
+ events.set(rigidBody.handle, eventHandlers);
1407
+ return () => {
1408
+ events.delete(rigidBody.handle);
1409
+ };
1410
+ }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
1411
+ };
1412
+
1413
+ const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion", "transformState"];
1469
1414
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
1470
1415
  const useRigidBodyContext = () => React.useContext(RigidBodyContext);
1471
- const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1416
+
1417
+ /**
1418
+ * A rigid body is a physical object that can be simulated by the physics engine.
1419
+ * @category Components
1420
+ */
1421
+ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1472
1422
  const {
1473
1423
  children,
1474
1424
  type,
1475
1425
  position,
1476
1426
  rotation,
1477
1427
  scale,
1478
- quaternion
1428
+ quaternion,
1429
+ transformState
1479
1430
  } = props,
1480
1431
  objectProps = _objectWithoutProperties(props, _excluded$1);
1481
1432
 
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]);
1433
+ const ref = React.useRef(null);
1434
+ const {
1435
+ world,
1436
+ rigidBodyStates,
1437
+ physicsOptions,
1438
+ rigidBodyEvents
1439
+ } = useRapier();
1440
+ const mergedOptions = React.useMemo(() => {
1441
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), props), {}, {
1442
+ children: undefined
1443
+ });
1444
+ }, [physicsOptions, props]);
1445
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1446
+
1447
+ const getInstance = useImperativeInstance(() => {
1448
+ const desc = rigidBodyDescFromOptions(mergedOptions);
1449
+ const rigidBody = world.createRigidBody(desc);
1450
+ const state = createRigidBodyState({
1451
+ rigidBody,
1452
+ object: ref.current
1453
+ });
1454
+ rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1455
+ return rigidBody;
1456
+ }, rigidBody => {
1457
+ world.removeRigidBody(rigidBody);
1458
+ rigidBodyStates.delete(rigidBody.handle);
1459
+ });
1460
+ useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1461
+ useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1462
+ React.useImperativeHandle(forwardedRef, () => getInstance());
1463
+ const contextValue = React.useMemo(() => {
1464
+ return {
1465
+ ref,
1466
+ getRigidBody: getInstance,
1467
+ options: mergedOptions
1468
+ };
1469
+ }, [mergedOptions]);
1489
1470
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1490
1471
  value: contextValue
1491
1472
  }, /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1492
- ref: object
1473
+ ref: ref
1493
1474
  }, objectProps, {
1494
1475
  position: position,
1495
1476
  rotation: rotation,
@@ -1501,14 +1482,17 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1501
1482
  }));
1502
1483
  RigidBody.displayName = "RigidBody";
1503
1484
 
1485
+ /**
1486
+ * A mesh collider is a collider that is automatically generated from the geometry of the children.
1487
+ * @category Colliders
1488
+ */
1504
1489
  const MeshCollider = /*#__PURE__*/React.memo(props => {
1505
1490
  const {
1506
1491
  children,
1507
1492
  type
1508
1493
  } = props;
1509
1494
  const {
1510
- physicsOptions,
1511
- world
1495
+ physicsOptions
1512
1496
  } = useRapier();
1513
1497
  const object = React.useRef(null);
1514
1498
  const {
@@ -1622,155 +1606,119 @@ const Debug = /*#__PURE__*/React.memo(() => {
1622
1606
  }, attractor))));
1623
1607
  });
1624
1608
 
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();
1609
+ const _excluded = ["children", "instances", "colliderNodes", "position", "rotation", "quaternion", "scale"];
1610
+ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1633
1611
  const object = React.useRef(null);
1612
+ const instancedWrapper = React.useRef(null);
1634
1613
 
1635
1614
  const {
1636
- positions,
1637
- rotations,
1638
- children
1615
+ // instanced props
1616
+ children,
1617
+ instances,
1618
+ colliderNodes = [],
1619
+ // wrapper object props
1620
+ position,
1621
+ rotation,
1622
+ quaternion,
1623
+ scale
1639
1624
  } = props,
1640
- options = _objectWithoutProperties(props, _excluded);
1625
+ rigidBodyProps = _objectWithoutProperties(props, _excluded);
1641
1626
 
1642
- const instancesRef = React.useRef([]);
1643
- const rigidBodyRefs = React.useRef([]);
1644
- const instancesRefGetter = React.useRef(() => {
1645
- if (!instancesRef.current) {
1646
- instancesRef.current = [];
1647
- }
1627
+ const rigidBodyApis = React.useRef([]);
1628
+ React.useImperativeHandle(ref, () => rigidBodyApis.current, [instances]);
1629
+ const childColliderProps = useChildColliderProps(object, _objectSpread2(_objectSpread2({}, props), {}, {
1630
+ children: undefined
1631
+ }));
1648
1632
 
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];
1633
+ const getInstancedMesh = () => {
1634
+ const firstChild = instancedWrapper.current.children[0];
1684
1635
 
1685
- _object3d.position.set(x, y, z);
1636
+ if (firstChild && "isInstancedMesh" in firstChild) {
1637
+ return firstChild;
1638
+ }
1686
1639
 
1687
- _object3d.rotation.set(rx, ry, rz);
1640
+ return undefined;
1641
+ };
1688
1642
 
1689
- _object3d.applyMatrix4(invertedWorld);
1643
+ React.useEffect(() => {
1644
+ const instancedMesh = getInstancedMesh();
1690
1645
 
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
- }
1646
+ if (instancedMesh) {
1647
+ instancedMesh.instanceMatrix.setUsage(three.DynamicDrawUsage);
1648
+ } else {
1649
+ console.warn("InstancedRigidBodies expects exactly one child, which must be an InstancedMesh");
1650
+ }
1651
+ }, []); // Update the RigidBodyStates whenever the instances change
1698
1652
 
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);
1653
+ const applyInstancedState = (state, index) => {
1654
+ const instancedMesh = getInstancedMesh();
1655
+
1656
+ if (instancedMesh) {
1657
+ return _objectSpread2(_objectSpread2({}, state), {}, {
1658
+ getMatrix: matrix => {
1659
+ instancedMesh.getMatrixAt(index, matrix);
1660
+ return matrix;
1661
+ },
1662
+ setMatrix: matrix => {
1663
+ instancedMesh.setMatrixAt(index, matrix);
1664
+ instancedMesh.instanceMatrix.needsUpdate = true;
1665
+ },
1666
+ meshType: "instancedMesh"
1711
1667
  });
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", {
1668
+ }
1669
+
1670
+ return state;
1671
+ };
1672
+
1673
+ return /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1730
1674
  ref: object
1731
- }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1675
+ }, rigidBodyProps, {
1676
+ position: position,
1677
+ rotation: rotation,
1678
+ quaternion: quaternion,
1679
+ scale: scale
1680
+ }), /*#__PURE__*/React__default["default"].createElement("object3D", {
1681
+ ref: instancedWrapper
1682
+ }, children), instances === null || instances === void 0 ? void 0 : instances.map((instance, index) => /*#__PURE__*/React__default["default"].createElement(RigidBody, _extends({}, rigidBodyProps, instance, {
1683
+ ref: body => rigidBodyApis.current[index] = body,
1684
+ transformState: state => applyInstancedState(state, index)
1685
+ }), /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, colliderNodes.map((node, index) => /*#__PURE__*/React__default["default"].createElement(React.Fragment, {
1732
1686
  key: index
1733
- }, colliderProps)))));
1734
- });
1687
+ }, node)), childColliderProps.map((colliderProps, colliderIndex) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1688
+ key: colliderIndex
1689
+ }, colliderProps)))))));
1690
+ }));
1735
1691
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1736
1692
 
1693
+ /**
1694
+ * @internal
1695
+ */
1696
+
1737
1697
  const useImpulseJoint = (body1, body2, params) => {
1738
1698
  const {
1739
1699
  world
1740
1700
  } = useRapier();
1741
1701
  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
- }
1702
+ useImperativeInstance(() => {
1703
+ if (body1.current && body2.current) {
1704
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1705
+ jointRef.current = newJoint;
1706
+ return newJoint;
1707
+ }
1708
+ }, joint => {
1709
+ if (joint) {
1710
+ jointRef.current = undefined;
1711
+ world.removeImpulseJoint(joint);
1753
1712
  }
1754
-
1755
- return jointRef.current;
1756
1713
  });
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;
1714
+ return jointRef;
1768
1715
  };
1769
1716
  /**
1770
- *
1771
1717
  * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1772
1718
  * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1773
1719
  * The fixed-joint makes these frames coincide in world-space.
1720
+ *
1721
+ * @category Hooks - Joints
1774
1722
  */
1775
1723
 
1776
1724
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
@@ -1784,6 +1732,8 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
1784
1732
  * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1785
1733
  * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1786
1734
  * points that need to coincide on the local-space of each rigid-body.
1735
+ *
1736
+ * @category Hooks - Joints
1787
1737
  */
1788
1738
 
1789
1739
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
@@ -1796,6 +1746,8 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1796
1746
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1797
1747
  * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1798
1748
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
1749
+ *
1750
+ * @category Hooks - Joints
1799
1751
  */
1800
1752
 
1801
1753
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1815,6 +1767,8 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
1815
1767
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1816
1768
  * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1817
1769
  * local tangent axis can be specified for each rigid-body.
1770
+ *
1771
+ * @category Hooks - Joints
1818
1772
  */
1819
1773
 
1820
1774
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1895,7 +1849,9 @@ exports.Physics = Physics;
1895
1849
  exports.RigidBody = RigidBody;
1896
1850
  exports.RoundCuboidCollider = RoundCuboidCollider;
1897
1851
  exports.TrimeshCollider = TrimeshCollider;
1852
+ exports.euler = euler;
1898
1853
  exports.interactionGroups = interactionGroups;
1854
+ exports.quat = quat;
1899
1855
  exports.useAfterPhysicsStep = useAfterPhysicsStep;
1900
1856
  exports.useBeforePhysicsStep = useBeforePhysicsStep;
1901
1857
  exports.useFixedJoint = useFixedJoint;
@@ -1904,3 +1860,4 @@ exports.usePrismaticJoint = usePrismaticJoint;
1904
1860
  exports.useRapier = useRapier;
1905
1861
  exports.useRevoluteJoint = useRevoluteJoint;
1906
1862
  exports.useSphericalJoint = useSphericalJoint;
1863
+ exports.vec3 = vec3;