@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
@@ -1,8 +1,8 @@
1
- import { ColliderDesc, ActiveEvents, RigidBodyDesc, EventQueue } from '@dimforge/rapier3d-compat';
1
+ import { ActiveEvents, ColliderDesc, EventQueue, RigidBodyDesc } from '@dimforge/rapier3d-compat';
2
2
  export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
3
3
  import { useFrame, useThree } from '@react-three/fiber';
4
- import React, { useRef, useMemo, useEffect, useContext, useState, memo, createContext, useCallback, forwardRef, useImperativeHandle, useLayoutEffect } from 'react';
5
- import { Quaternion, Euler, Vector3, Object3D, Matrix4, MathUtils, InstancedMesh, BufferAttribute, DynamicDrawUsage } from 'three';
4
+ import React, { useRef, useMemo, useEffect, useContext, useState, memo, createContext, useCallback, forwardRef, useImperativeHandle, Fragment } from 'react';
5
+ import { Quaternion, Euler, Vector3, Object3D, Matrix4, MathUtils, BufferAttribute, DynamicDrawUsage } from 'three';
6
6
  import { useAsset } from 'use-asset';
7
7
  import { mergeVertices, VertexNormalsHelper } from 'three-stdlib';
8
8
 
@@ -47,10 +47,44 @@ function _objectSpread2(target) {
47
47
  return target;
48
48
  }
49
49
 
50
+ const createWorldApi = ref => {
51
+ return {
52
+ raw: () => ref.current(),
53
+ getCollider: handle => ref.current().getCollider(handle),
54
+ getRigidBody: handle => ref.current().getRigidBody(handle),
55
+ createRigidBody: desc => ref.current().createRigidBody(desc),
56
+ createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
57
+ removeRigidBody: rigidBody => {
58
+ if (!ref.current().bodies.contains(rigidBody.handle)) return;
59
+ ref.current().removeRigidBody(rigidBody);
60
+ },
61
+ removeCollider: (collider, wakeUp = true) => {
62
+ if (!ref.current().colliders.contains(collider.handle)) return;
63
+ ref.current().removeCollider(collider, wakeUp);
64
+ },
65
+ createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
66
+ removeImpulseJoint: (joint, wakeUp = true) => {
67
+ if (!ref.current().impulseJoints.contains(joint.handle)) return;
68
+ ref.current().removeImpulseJoint(joint, wakeUp);
69
+ },
70
+ forEachCollider: callback => ref.current().forEachCollider(callback),
71
+ setGravity: ({
72
+ x,
73
+ y,
74
+ z
75
+ }) => ref.current().gravity = {
76
+ x,
77
+ y,
78
+ z
79
+ },
80
+ debugRender: () => ref.current().debugRender()
81
+ };
82
+ };
83
+
50
84
  const _quaternion = new Quaternion();
51
85
  new Euler();
52
86
  const _vector3 = new Vector3();
53
- const _object3d = new Object3D();
87
+ new Object3D();
54
88
  const _matrix4 = new Matrix4();
55
89
  const _position = new Vector3();
56
90
  const _rotation = new Quaternion();
@@ -66,11 +100,6 @@ const tupleToObject = (tuple, keys) => {
66
100
  return obj;
67
101
  }, {});
68
102
  };
69
- const rapierVector3ToVector3 = ({
70
- x,
71
- y,
72
- z
73
- }) => _vector3.set(x, y, z);
74
103
  const rapierQuaternionToQuaternion = ({
75
104
  x,
76
105
  y,
@@ -124,152 +153,6 @@ function useConst(initialValue) {
124
153
  return ref.current.value;
125
154
  }
126
155
 
127
- const createRigidBodyApi = ref => {
128
- return {
129
- raw: () => ref.current(),
130
-
131
- get handle() {
132
- return ref.current().handle;
133
- },
134
-
135
- mass: () => ref.current().mass(),
136
-
137
- applyImpulse(impulseVector, wakeUp = true) {
138
- ref.current().applyImpulse(impulseVector, wakeUp);
139
- },
140
-
141
- applyTorqueImpulse(torqueVector, wakeUp = true) {
142
- ref.current().applyTorqueImpulse(torqueVector, wakeUp);
143
- },
144
-
145
- applyImpulseAtPoint: (impulseVector, impulsePoint, wakeUp = true) => ref.current().applyImpulseAtPoint(impulseVector, impulsePoint, wakeUp),
146
- addForce: (force, wakeUp = true) => ref.current().addForce(force, wakeUp),
147
- addForceAtPoint: (force, point, wakeUp = true) => ref.current().addForceAtPoint(force, point, wakeUp),
148
- addTorque: (torque, wakeUp = true) => ref.current().addTorque(torque, wakeUp),
149
-
150
- translation() {
151
- return rapierVector3ToVector3(ref.current().translation());
152
- },
153
-
154
- setTranslation: (translation, wakeUp = true) => ref.current().setTranslation(translation, wakeUp),
155
-
156
- rotation() {
157
- const {
158
- x,
159
- y,
160
- z,
161
- w
162
- } = ref.current().rotation();
163
- return new Quaternion(x, y, z, w);
164
- },
165
-
166
- setRotation: (rotation, wakeUp = true) => {
167
- ref.current().setRotation(rotation, wakeUp);
168
- },
169
-
170
- linvel() {
171
- const {
172
- x,
173
- y,
174
- z
175
- } = ref.current().linvel();
176
- return new Vector3(x, y, z);
177
- },
178
-
179
- setLinvel: (velocity, wakeUp = true) => ref.current().setLinvel(velocity, wakeUp),
180
-
181
- angvel() {
182
- const {
183
- x,
184
- y,
185
- z
186
- } = ref.current().angvel();
187
- return new Vector3(x, y, z);
188
- },
189
-
190
- setAngvel: (velocity, wakeUp = true) => ref.current().setAngvel(velocity, wakeUp),
191
-
192
- linearDamping() {
193
- return ref.current().linearDamping();
194
- },
195
-
196
- setLinearDamping: factor => ref.current().setLinearDamping(factor),
197
-
198
- angularDamping() {
199
- return ref.current().angularDamping();
200
- },
201
-
202
- setAngularDamping: factor => ref.current().setAngularDamping(factor),
203
- setNextKinematicRotation: rotation => {
204
- ref.current().setNextKinematicRotation(rotation);
205
- },
206
- setNextKinematicTranslation: translation => ref.current().setNextKinematicTranslation(translation),
207
- resetForces: (wakeUp = true) => ref.current().resetForces(wakeUp),
208
- resetTorques: (wakeUp = true) => ref.current().resetTorques(wakeUp),
209
- lockRotations: (locked, wakeUp = true) => ref.current().lockRotations(locked, wakeUp),
210
- lockTranslations: (locked, wakeUp = true) => ref.current().lockTranslations(locked, wakeUp),
211
- setEnabledRotations: (x, y, z, wakeUp = true) => ref.current().setEnabledRotations(x, y, z, wakeUp),
212
- setEnabledTranslations: (x, y, z, wakeUp = true) => ref.current().setEnabledTranslations(x, y, z, wakeUp)
213
- };
214
- };
215
- const createInstancedRigidBodiesApi = bodiesGetter => ({
216
- at: index => bodiesGetter.current()[index].api,
217
-
218
- forEach(callback) {
219
- return bodiesGetter.current().map(b => b.api).forEach(callback);
220
- },
221
-
222
- get count() {
223
- return bodiesGetter.current().length;
224
- }
225
-
226
- });
227
- const createWorldApi = ref => {
228
- return {
229
- raw: () => ref.current(),
230
- getCollider: handle => ref.current().getCollider(handle),
231
- getRigidBody: handle => ref.current().getRigidBody(handle),
232
- createRigidBody: desc => ref.current().createRigidBody(desc),
233
- createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
234
- removeRigidBody: rigidBody => {
235
- if (!ref.current().bodies.contains(rigidBody.handle)) return;
236
- ref.current().removeRigidBody(rigidBody);
237
- },
238
- removeCollider: (collider, wakeUp = true) => {
239
- if (!ref.current().colliders.contains(collider.handle)) return;
240
- ref.current().removeCollider(collider, wakeUp);
241
- },
242
- createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
243
- removeImpulseJoint: (joint, wakeUp = true) => {
244
- if (!ref.current().impulseJoints.contains(joint.handle)) return;
245
- ref.current().removeImpulseJoint(joint, wakeUp);
246
- },
247
- forEachCollider: callback => ref.current().forEachCollider(callback),
248
- setGravity: ({
249
- x,
250
- y,
251
- z
252
- }) => ref.current().gravity = {
253
- x,
254
- y,
255
- z
256
- },
257
- debugRender: () => ref.current().debugRender()
258
- };
259
- };
260
- const createJointApi = ref => {
261
- return {
262
- raw: () => ref.current(),
263
-
264
- get handle() {
265
- return ref.current().handle;
266
- },
267
-
268
- configureMotorPosition: (targetPos, stiffness, damping) => ref.current().configureMotorPosition(targetPos, stiffness, damping),
269
- configureMotorVelocity: (targetVel, damping) => ref.current().configureMotorVelocity(targetVel, damping)
270
- };
271
- };
272
-
273
156
  const scaleColliderArgs = (shape, args, scale) => {
274
157
  const newArgs = args.slice(); // Heightfield uses a vector
275
158
 
@@ -291,11 +174,11 @@ const scaleColliderArgs = (shape, args, scale) => {
291
174
  const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
292
175
  return newArgs.map((arg, index) => scaleArray[index] * arg);
293
176
  };
294
- const createColliderFromOptions = (options, world, scale, rigidBody) => {
177
+ const createColliderFromOptions = (options, world, scale, getRigidBody) => {
295
178
  const scaledArgs = scaleColliderArgs(options.shape, options.args, scale); // @ts-ignore
296
179
 
297
180
  const desc = ColliderDesc[options.shape](...scaledArgs);
298
- return world.createCollider(desc, rigidBody);
181
+ return world.createCollider(desc, getRigidBody === null || getRigidBody === void 0 ? void 0 : getRigidBody());
299
182
  };
300
183
  const massPropertiesConflictError = "Please pick ONLY ONE of the `density`, `mass` and `massProperties` options.";
301
184
 
@@ -399,15 +282,14 @@ const setColliderOptions = (collider, options, states) => {
399
282
  setColliderMassOptions(collider, options);
400
283
  }
401
284
  };
402
- const useUpdateColliderOptions = (collidersRef, props, states) => {
285
+ const useUpdateColliderOptions = (getCollider, props, states) => {
403
286
  // TODO: Improve this, split each prop into its own effect
404
287
  const mutablePropsAsFlatArray = useMemo(() => mutableColliderOptionKeys.flatMap(key => {
405
288
  return vectorToTuple(props[key]);
406
289
  }), [props]);
407
290
  useEffect(() => {
408
- collidersRef.current.forEach(collider => {
409
- setColliderOptions(collider, props, states);
410
- });
291
+ const collider = getCollider();
292
+ setColliderOptions(collider, props, states);
411
293
  }, mutablePropsAsFlatArray);
412
294
  };
413
295
 
@@ -530,7 +412,7 @@ const getColliderArgsFromGeometry = (geometry, colliders) => {
530
412
  offset: new Vector3()
531
413
  };
532
414
  };
533
- const useColliderEvents = (collidersRef, props, events) => {
415
+ const useColliderEvents = (getCollider, props, events) => {
534
416
  const {
535
417
  onCollisionEnter,
536
418
  onCollisionExit,
@@ -539,9 +421,9 @@ const useColliderEvents = (collidersRef, props, events) => {
539
421
  onContactForce
540
422
  } = props;
541
423
  useEffect(() => {
542
- var _collidersRef$current;
424
+ const collider = getCollider();
543
425
 
544
- (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
426
+ if (collider) {
545
427
  const hasCollisionEvent = !!(onCollisionEnter || onCollisionExit || onIntersectionEnter || onIntersectionExit);
546
428
  const hasContactForceEvent = !!onContactForce;
547
429
 
@@ -560,265 +442,76 @@ const useColliderEvents = (collidersRef, props, events) => {
560
442
  onIntersectionExit,
561
443
  onContactForce
562
444
  });
563
- });
564
- return () => {
565
- var _collidersRef$current2;
445
+ }
566
446
 
567
- (_collidersRef$current2 = collidersRef.current) === null || _collidersRef$current2 === void 0 ? void 0 : _collidersRef$current2.forEach(collider => events.delete(collider.handle));
447
+ return () => {
448
+ if (collider) {
449
+ events.delete(collider.handle);
450
+ }
568
451
  };
569
452
  }, [onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit, onContactForce]);
570
453
  };
571
454
 
572
- const rigidBodyDescFromOptions = options => {
573
- var _options$canSleep;
574
-
575
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
576
- const desc = new RigidBodyDesc(type); // Apply immutable options
455
+ /**
456
+ * Exposes the Rapier context, and world
457
+ * @category Hooks
458
+ */
577
459
 
578
- desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
579
- return desc;
580
- };
581
- const createRigidBodyState = ({
582
- rigidBody,
583
- object,
584
- setMatrix,
585
- getMatrix,
586
- worldScale
587
- }) => {
588
- object.updateWorldMatrix(true, false);
589
- const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
590
- return {
591
- object,
592
- rigidBody,
593
- invertedWorldMatrix,
594
- setMatrix: setMatrix ? setMatrix : matrix => {
595
- object.matrix.copy(matrix);
596
- },
597
- getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
598
- scale: worldScale || object.getWorldScale(_scale).clone(),
599
- isSleeping: false
600
- };
460
+ const useRapier = () => {
461
+ return useContext(rapierContext);
601
462
  };
602
- const mutableRigidBodyOptions = {
603
- gravityScale: (rb, value) => {
604
- rb.setGravityScale(value, true);
605
- },
606
- linearDamping: (rb, value) => {
607
- rb.setLinearDamping(value);
608
- },
609
- angularDamping: (rb, value) => {
610
- rb.setAngularDamping(value);
611
- },
612
- enabledRotations: (rb, [x, y, z]) => {
613
- rb.setEnabledRotations(x, y, z, true);
614
- },
615
- enabledTranslations: (rb, [x, y, z]) => {
616
- rb.setEnabledTranslations(x, y, z, true);
617
- },
618
- lockRotations: (rb, value) => {
619
- rb.lockRotations(value, true);
620
- },
621
- lockTranslations: (rb, value) => {
622
- rb.lockTranslations(value, true);
623
- },
624
- angularVelocity: (rb, [x, y, z]) => {
625
- rb.setAngvel({
626
- x,
627
- y,
628
- z
629
- }, true);
630
- },
631
- linearVelocity: (rb, [x, y, z]) => {
632
- rb.setLinvel({
633
- x,
634
- y,
635
- z
636
- }, true);
637
- },
638
- ccd: (rb, value) => {
639
- rb.enableCcd(value);
640
- },
641
- userData: (rb, value) => {
642
- rb.userData = value;
643
- },
644
-
645
- type(rb, value) {
646
- rb.setBodyType(rigidBodyTypeFromString(value));
647
- },
463
+ /**
464
+ * Registers a callback to be called before the physics step
465
+ * @category Hooks
466
+ */
648
467
 
649
- position: () => {},
650
- rotation: () => {},
651
- quaternion: () => {},
652
- scale: () => {}
468
+ const useBeforePhysicsStep = callback => {
469
+ const {
470
+ beforeStepCallbacks
471
+ } = useRapier();
472
+ useEffect(() => {
473
+ beforeStepCallbacks.add(callback);
474
+ return () => {
475
+ beforeStepCallbacks.delete(callback);
476
+ };
477
+ }, []);
653
478
  };
654
- const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
655
- const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
656
- if (!rigidBody) {
657
- return;
658
- }
479
+ /**
480
+ * Registers a callback to be called after the physics step
481
+ * @category Hooks
482
+ */
659
483
 
660
- const state = states.get(rigidBody.handle);
484
+ const useAfterPhysicsStep = callback => {
485
+ const {
486
+ afterStepCallbacks
487
+ } = useRapier();
488
+ useEffect(() => {
489
+ afterStepCallbacks.add(callback);
490
+ return () => {
491
+ afterStepCallbacks.delete(callback);
492
+ };
493
+ }, []);
494
+ }; // Internal hooks
661
495
 
662
- if (state) {
663
- if (updateTranslations) {
664
- state.object.updateWorldMatrix(true, false);
496
+ /**
497
+ * @internal
498
+ */
665
499
 
666
- _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
500
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
501
+ const [colliderProps, setColliderProps] = useState([]);
502
+ useEffect(() => {
503
+ const object = ref.current;
667
504
 
668
- rigidBody.setTranslation(_position, false);
669
- rigidBody.setRotation(_rotation, false);
505
+ if (object && options.colliders !== false) {
506
+ setColliderProps(createColliderPropsFromChildren({
507
+ object: ref.current,
508
+ options,
509
+ ignoreMeshColliders
510
+ }));
670
511
  }
671
-
672
- mutableRigidBodyOptionKeys.forEach(key => {
673
- if (key in options) {
674
- mutableRigidBodyOptions[key](rigidBody, options[key]);
675
- }
676
- });
677
- }
678
- };
679
- const useUpdateRigidBodyOptions = (rigidBodyRef, props, states, updateTranslations = true) => {
680
- // TODO: Improve this, split each prop into its own effect
681
- const mutablePropsAsFlatArray = useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
682
- return vectorToTuple(props[key]);
683
- }), [props]);
684
- useEffect(() => {
685
- if (Array.isArray(rigidBodyRef.current)) {
686
- for (const rigidBody of rigidBodyRef.current) {
687
- setRigidBodyOptions(rigidBody, props, states, updateTranslations);
688
- }
689
- } else if (rigidBodyRef.current) {
690
- setRigidBodyOptions(rigidBodyRef.current, props, states, updateTranslations);
691
- }
692
- }, mutablePropsAsFlatArray);
693
- };
694
- const useRigidBodyEvents = (rigidBodyRef, props, events) => {
695
- const {
696
- onWake,
697
- onSleep,
698
- onCollisionEnter,
699
- onCollisionExit,
700
- onIntersectionEnter,
701
- onIntersectionExit
702
- } = props;
703
- const eventHandlers = {
704
- onWake,
705
- onSleep,
706
- onCollisionEnter,
707
- onCollisionExit,
708
- onIntersectionEnter,
709
- onIntersectionExit
710
- };
711
- useEffect(() => {
712
- if (Array.isArray(rigidBodyRef.current)) {
713
- for (const rigidBody of rigidBodyRef.current) {
714
- events.set(rigidBody.handle, eventHandlers);
715
- }
716
- } else if (rigidBodyRef.current) {
717
- events.set(rigidBodyRef.current.handle, eventHandlers);
718
- }
719
-
720
- return () => {
721
- if (Array.isArray(rigidBodyRef.current)) {
722
- for (const rigidBody of rigidBodyRef.current) {
723
- events.delete(rigidBody.handle);
724
- }
725
- } else if (rigidBodyRef.current) {
726
- events.delete(rigidBodyRef.current.handle);
727
- }
728
- };
729
- }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
730
- };
731
-
732
- const useRapier = () => {
733
- return useContext(rapierContext);
734
- };
735
- const useBeforePhysicsStep = callback => {
736
- const {
737
- beforeStepCallbacks
738
- } = useRapier();
739
- useEffect(() => {
740
- beforeStepCallbacks.add(callback);
741
- return () => {
742
- beforeStepCallbacks.delete(callback);
743
- };
744
- }, []);
745
- };
746
- const useAfterPhysicsStep = callback => {
747
- const {
748
- afterStepCallbacks
749
- } = useRapier();
750
- useEffect(() => {
751
- afterStepCallbacks.add(callback);
752
- return () => {
753
- afterStepCallbacks.delete(callback);
754
- };
755
- }, []);
756
- }; // Internal hooks
757
-
758
- const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
759
- const [colliderProps, setColliderProps] = useState([]);
760
- useEffect(() => {
761
- const object = ref.current;
762
-
763
- if (object && options.colliders !== false) {
764
- setColliderProps(createColliderPropsFromChildren({
765
- object: ref.current,
766
- options,
767
- ignoreMeshColliders
768
- }));
769
- }
770
- }, [options.colliders]);
771
- return colliderProps;
772
- };
773
- const useRigidBody = (options = {}) => {
774
- const {
775
- world,
776
- rigidBodyStates,
777
- physicsOptions,
778
- rigidBodyEvents
779
- } = useRapier();
780
- const ref = useRef();
781
- const mergedOptions = useMemo(() => {
782
- return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
783
- children: undefined
784
- });
785
- }, [physicsOptions, options]);
786
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
787
-
788
- const rigidBodyRef = useRef();
789
- const getRigidBodyRef = useRef(() => {
790
- if (!rigidBodyRef.current) {
791
- const desc = rigidBodyDescFromOptions(options);
792
- const rigidBody = world.createRigidBody(desc);
793
- rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
794
- }
795
-
796
- return rigidBodyRef.current;
797
- }); // Setup
798
-
799
- useEffect(() => {
800
- const rigidBody = getRigidBodyRef.current();
801
- rigidBodyRef.current = rigidBody;
802
-
803
- if (!ref.current) {
804
- ref.current = new Object3D();
805
- }
806
-
807
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
808
- rigidBody,
809
- object: ref.current
810
- }));
811
- return () => {
812
- world.removeRigidBody(rigidBody);
813
- rigidBodyStates.delete(rigidBody.handle);
814
- rigidBodyRef.current = undefined;
815
- };
816
- }, []);
817
- useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
818
- useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
819
- const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
820
- return [ref, api, childColliderProps];
821
- };
512
+ }, [options.colliders]);
513
+ return colliderProps;
514
+ };
822
515
 
823
516
  const calcForceByType = {
824
517
  static: (s, m2, r, d, G) => s,
@@ -936,6 +629,10 @@ const importRapier = async () => {
936
629
  return r;
937
630
  };
938
631
 
632
+ /**
633
+ * The main physics component used to create a physics world.
634
+ * @category Components
635
+ */
939
636
  const Physics = ({
940
637
  colliders: _colliders = "cuboid",
941
638
  gravity: _gravity = [0, -9.81, 0],
@@ -1095,7 +792,7 @@ const Physics = ({
1095
792
  state.isSleeping = rigidBody.isSleeping();
1096
793
  }
1097
794
 
1098
- if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
795
+ if (!rigidBody || rigidBody.isSleeping() && !("isInstancedMesh" in state.object) || !state.setMatrix) {
1099
796
  return;
1100
797
  } // New states
1101
798
 
@@ -1109,7 +806,7 @@ const Physics = ({
1109
806
  _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1110
807
 
1111
808
 
1112
- if (!(state.object instanceof InstancedMesh)) {
809
+ if (state.meshType == "mesh") {
1113
810
  state.object.position.copy(_position);
1114
811
  state.object.quaternion.copy(_rotation);
1115
812
  }
@@ -1118,9 +815,8 @@ const Physics = ({
1118
815
 
1119
816
  _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1120
817
 
1121
- if (state.object instanceof InstancedMesh) {
818
+ if (state.meshType == "instancedMesh") {
1122
819
  state.setMatrix(_matrix4);
1123
- state.object.instanceMatrix.needsUpdate = true;
1124
820
  } else {
1125
821
  // Interpolate to new position
1126
822
  state.object.position.lerp(_position, interpolationAlpha);
@@ -1304,8 +1000,87 @@ function _objectWithoutProperties(source, excluded) {
1304
1000
  return target;
1305
1001
  }
1306
1002
 
1003
+ /**
1004
+ * Initiate an instance and return a safe getter
1005
+ */
1006
+
1007
+ const useImperativeInstance = (createFn, destroyFn) => {
1008
+ const ref = useRef();
1009
+ const refGetter = useMemo(() => () => {
1010
+ if (!ref.current) {
1011
+ ref.current = createFn();
1012
+ }
1013
+
1014
+ return ref.current;
1015
+ }, []);
1016
+ useEffect(() => {
1017
+ const instance = refGetter();
1018
+ return () => {
1019
+ destroyFn(instance);
1020
+ ref.current = undefined;
1021
+ };
1022
+ }, []);
1023
+ return refGetter;
1024
+ };
1025
+
1026
+ /**
1027
+ * Takes an object resembling a Vector3 and returs a Three.Vector3
1028
+ * @category Math helpers
1029
+ */
1030
+
1031
+ const vec3 = ({
1032
+ x,
1033
+ y,
1034
+ z
1035
+ } = {
1036
+ x: 0,
1037
+ y: 0,
1038
+ z: 0
1039
+ }) => {
1040
+ return new Vector3(x, y, z);
1041
+ };
1042
+ /**
1043
+ * Takes an object resembling a Quaternion and returs a Three.Quaternion
1044
+ * @category Math helpers
1045
+ */
1046
+
1047
+ const quat = ({
1048
+ x,
1049
+ y,
1050
+ z,
1051
+ w
1052
+ } = {
1053
+ x: 0,
1054
+ y: 0,
1055
+ z: 0,
1056
+ w: 1
1057
+ }) => {
1058
+ return new Quaternion(x, y, z, w);
1059
+ };
1060
+ /**
1061
+ * Takes an object resembling an Euler and returs a Three.Euler
1062
+ * @category Math helpers
1063
+ */
1064
+
1065
+ const euler = ({
1066
+ x,
1067
+ y,
1068
+ z
1069
+ } = {
1070
+ x: 0,
1071
+ y: 0,
1072
+ z: 0
1073
+ }) => {
1074
+ return new Euler(x, y, z);
1075
+ };
1076
+
1307
1077
  // Colliders
1308
- const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1078
+
1079
+ /**
1080
+ * A collider is a shape that can be attached to a rigid body to define its physical properties.
1081
+ * @internal
1082
+ */
1083
+ const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, forwardedRef) => {
1309
1084
  const {
1310
1085
  children,
1311
1086
  position,
@@ -1321,52 +1096,21 @@ const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/React.forwardRef((props, for
1321
1096
  } = useRapier();
1322
1097
  const rigidBodyContext = useRigidBodyContext();
1323
1098
  const ref = useRef(null);
1324
- const collidersRef = useMemo(() => {
1325
- if (forwardedRef !== null) {
1326
- return forwardedRef;
1327
- }
1328
-
1329
- const result = /*#__PURE__*/React.createRef();
1330
- result.current = [];
1331
- return result;
1332
- }, []);
1333
- useEffect(() => {
1334
- const object = ref.current;
1335
- const worldScale = object.getWorldScale(new Vector3());
1336
- const colliders = []; // If this is an InstancedRigidBody api
1337
-
1338
- if (rigidBodyContext && "at" in rigidBodyContext.api) {
1339
- rigidBodyContext.api.forEach((body, index) => {
1340
- var _rigidBodyContext$opt, _rigidBodyContext$opt2;
1341
-
1342
- let instanceScale = worldScale;
1343
-
1344
- 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]) {
1345
- instanceScale = instanceScale.clone().multiply(vectorArrayToVector3(rigidBodyContext.options.scales[index]));
1346
- }
1347
-
1348
- const collider = createColliderFromOptions(props, world, instanceScale, body.raw());
1349
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1350
- colliders.push(collider);
1351
- });
1352
- } else {
1353
- const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext && (rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.api).raw());
1354
- colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1355
- colliders.push(collider);
1356
- }
1357
-
1358
- collidersRef.current = colliders;
1359
- return () => {
1360
- colliders.forEach(collider => {
1361
- world.removeCollider(collider);
1362
- });
1363
- };
1364
- }, []);
1099
+ const getInstance = useImperativeInstance(() => {
1100
+ const worldScale = ref.current.getWorldScale(vec3());
1101
+ const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1102
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1103
+ return collider;
1104
+ }, collider => {
1105
+ colliderStates.delete(collider.handle);
1106
+ world.removeCollider(collider);
1107
+ });
1108
+ useImperativeHandle(forwardedRef, () => getInstance());
1365
1109
  const mergedProps = useMemo(() => {
1366
1110
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
1367
1111
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
1368
- useUpdateColliderOptions(collidersRef, mergedProps, colliderStates);
1369
- useColliderEvents(collidersRef, mergedProps, colliderEvents);
1112
+ useUpdateColliderOptions(getInstance, mergedProps, colliderStates);
1113
+ useColliderEvents(getInstance, mergedProps, colliderEvents);
1370
1114
  return /*#__PURE__*/React.createElement("object3D", {
1371
1115
  position: position,
1372
1116
  rotation: rotation,
@@ -1376,54 +1120,99 @@ const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/React.forwardRef((props, for
1376
1120
  name: name
1377
1121
  }, children);
1378
1122
  }));
1123
+
1124
+ /**
1125
+ * A cuboid collider shape
1126
+ * @category Colliders
1127
+ */
1379
1128
  const CuboidCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1380
1129
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1381
1130
  shape: "cuboid",
1382
1131
  ref: ref
1383
1132
  }));
1384
1133
  });
1134
+ /**
1135
+ * A round cuboid collider shape
1136
+ * @category Colliders
1137
+ */
1138
+
1385
1139
  const RoundCuboidCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1386
1140
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1387
1141
  shape: "roundCuboid",
1388
1142
  ref: ref
1389
1143
  }));
1390
1144
  });
1145
+ /**
1146
+ * A ball collider shape
1147
+ * @category Colliders
1148
+ */
1149
+
1391
1150
  const BallCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1392
1151
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1393
1152
  shape: "ball",
1394
1153
  ref: ref
1395
1154
  }));
1396
1155
  });
1156
+ /**
1157
+ * A capsule collider shape
1158
+ * @category Colliders
1159
+ */
1160
+
1397
1161
  const CapsuleCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1398
1162
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1399
1163
  shape: "capsule",
1400
1164
  ref: ref
1401
1165
  }));
1402
1166
  });
1167
+ /**
1168
+ * A heightfield collider shape
1169
+ * @category Colliders
1170
+ */
1171
+
1403
1172
  const HeightfieldCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1404
1173
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1405
1174
  shape: "heightfield",
1406
1175
  ref: ref
1407
1176
  }));
1408
1177
  });
1178
+ /**
1179
+ * A trimesh collider shape
1180
+ * @category Colliders
1181
+ */
1182
+
1409
1183
  const TrimeshCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1410
1184
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1411
1185
  shape: "trimesh",
1412
1186
  ref: ref
1413
1187
  }));
1414
1188
  });
1189
+ /**
1190
+ * A cone collider shape
1191
+ * @category Colliders
1192
+ */
1193
+
1415
1194
  const ConeCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1416
1195
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1417
1196
  shape: "cone",
1418
1197
  ref: ref
1419
1198
  }));
1420
1199
  });
1200
+ /**
1201
+ * A cylinder collider shape
1202
+ * @category Colliders
1203
+ */
1204
+
1421
1205
  const CylinderCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1422
1206
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1423
1207
  shape: "cylinder",
1424
1208
  ref: ref
1425
1209
  }));
1426
1210
  });
1211
+ /**
1212
+ * A convex hull collider shape
1213
+ * @category Colliders
1214
+ */
1215
+
1427
1216
  const ConvexHullCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1428
1217
  return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1429
1218
  shape: "convexHull",
@@ -1440,31 +1229,212 @@ ConeCollider.displayName = "ConeCollider";
1440
1229
  CylinderCollider.displayName = "CylinderCollider";
1441
1230
  ConvexHullCollider.displayName = "ConvexHullCollider";
1442
1231
 
1443
- const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1232
+ const rigidBodyDescFromOptions = options => {
1233
+ var _options$canSleep;
1234
+
1235
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
1236
+ const desc = new RigidBodyDesc(type); // Apply immutable options
1237
+
1238
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
1239
+ return desc;
1240
+ };
1241
+ const createRigidBodyState = ({
1242
+ rigidBody,
1243
+ object,
1244
+ setMatrix,
1245
+ getMatrix,
1246
+ worldScale,
1247
+ meshType: _meshType = "mesh"
1248
+ }) => {
1249
+ object.updateWorldMatrix(true, false);
1250
+ const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
1251
+ return {
1252
+ object,
1253
+ rigidBody,
1254
+ invertedWorldMatrix,
1255
+ setMatrix: setMatrix ? setMatrix : matrix => {
1256
+ object.matrix.copy(matrix);
1257
+ },
1258
+ getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
1259
+ scale: worldScale || object.getWorldScale(_scale).clone(),
1260
+ isSleeping: false,
1261
+ meshType: _meshType
1262
+ };
1263
+ };
1264
+ const mutableRigidBodyOptions = {
1265
+ gravityScale: (rb, value) => {
1266
+ rb.setGravityScale(value, true);
1267
+ },
1268
+ linearDamping: (rb, value) => {
1269
+ rb.setLinearDamping(value);
1270
+ },
1271
+ angularDamping: (rb, value) => {
1272
+ rb.setAngularDamping(value);
1273
+ },
1274
+ enabledRotations: (rb, [x, y, z]) => {
1275
+ rb.setEnabledRotations(x, y, z, true);
1276
+ },
1277
+ enabledTranslations: (rb, [x, y, z]) => {
1278
+ rb.setEnabledTranslations(x, y, z, true);
1279
+ },
1280
+ lockRotations: (rb, value) => {
1281
+ rb.lockRotations(value, true);
1282
+ },
1283
+ lockTranslations: (rb, value) => {
1284
+ rb.lockTranslations(value, true);
1285
+ },
1286
+ angularVelocity: (rb, [x, y, z]) => {
1287
+ rb.setAngvel({
1288
+ x,
1289
+ y,
1290
+ z
1291
+ }, true);
1292
+ },
1293
+ linearVelocity: (rb, [x, y, z]) => {
1294
+ rb.setLinvel({
1295
+ x,
1296
+ y,
1297
+ z
1298
+ }, true);
1299
+ },
1300
+ ccd: (rb, value) => {
1301
+ rb.enableCcd(value);
1302
+ },
1303
+ userData: (rb, value) => {
1304
+ rb.userData = value;
1305
+ },
1306
+
1307
+ type(rb, value) {
1308
+ rb.setBodyType(rigidBodyTypeFromString(value), true);
1309
+ },
1310
+
1311
+ position: () => {},
1312
+ rotation: () => {},
1313
+ quaternion: () => {},
1314
+ scale: () => {}
1315
+ };
1316
+ const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
1317
+ const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
1318
+ if (!rigidBody) {
1319
+ return;
1320
+ }
1321
+
1322
+ const state = states.get(rigidBody.handle);
1323
+
1324
+ if (state) {
1325
+ if (updateTranslations) {
1326
+ state.object.updateWorldMatrix(true, false);
1327
+
1328
+ _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
1329
+
1330
+ rigidBody.setTranslation(_position, false);
1331
+ rigidBody.setRotation(_rotation, false);
1332
+ }
1333
+
1334
+ mutableRigidBodyOptionKeys.forEach(key => {
1335
+ if (key in options) {
1336
+ mutableRigidBodyOptions[key](rigidBody, options[key]);
1337
+ }
1338
+ });
1339
+ }
1340
+ };
1341
+ const useUpdateRigidBodyOptions = (getRigidBody, props, states, updateTranslations = true) => {
1342
+ // TODO: Improve this, split each prop into its own effect
1343
+ const mutablePropsAsFlatArray = useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
1344
+ return vectorToTuple(props[key]);
1345
+ }), [props]);
1346
+ useEffect(() => {
1347
+ const rigidBody = getRigidBody();
1348
+ setRigidBodyOptions(rigidBody, props, states, updateTranslations);
1349
+ }, mutablePropsAsFlatArray);
1350
+ };
1351
+ const useRigidBodyEvents = (getRigidBody, props, events) => {
1352
+ const {
1353
+ onWake,
1354
+ onSleep,
1355
+ onCollisionEnter,
1356
+ onCollisionExit,
1357
+ onIntersectionEnter,
1358
+ onIntersectionExit
1359
+ } = props;
1360
+ const eventHandlers = {
1361
+ onWake,
1362
+ onSleep,
1363
+ onCollisionEnter,
1364
+ onCollisionExit,
1365
+ onIntersectionEnter,
1366
+ onIntersectionExit
1367
+ };
1368
+ useEffect(() => {
1369
+ const rigidBody = getRigidBody();
1370
+ events.set(rigidBody.handle, eventHandlers);
1371
+ return () => {
1372
+ events.delete(rigidBody.handle);
1373
+ };
1374
+ }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
1375
+ };
1376
+
1377
+ const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion", "transformState"];
1444
1378
  const RigidBodyContext = /*#__PURE__*/createContext(undefined);
1445
1379
  const useRigidBodyContext = () => useContext(RigidBodyContext);
1446
- const RigidBody = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, ref) => {
1380
+
1381
+ /**
1382
+ * A rigid body is a physical object that can be simulated by the physics engine.
1383
+ * @category Components
1384
+ */
1385
+ const RigidBody = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, forwardedRef) => {
1447
1386
  const {
1448
1387
  children,
1449
1388
  type,
1450
1389
  position,
1451
1390
  rotation,
1452
1391
  scale,
1453
- quaternion
1392
+ quaternion,
1393
+ transformState
1454
1394
  } = props,
1455
1395
  objectProps = _objectWithoutProperties(props, _excluded$1);
1456
1396
 
1457
- const [object, api, childColliderProps] = useRigidBody(props);
1458
- useImperativeHandle(ref, () => api);
1459
- const contextValue = useMemo(() => ({
1460
- ref: object,
1461
- api,
1462
- options: props
1463
- }), [object, api, props]);
1397
+ const ref = useRef(null);
1398
+ const {
1399
+ world,
1400
+ rigidBodyStates,
1401
+ physicsOptions,
1402
+ rigidBodyEvents
1403
+ } = useRapier();
1404
+ const mergedOptions = useMemo(() => {
1405
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), props), {}, {
1406
+ children: undefined
1407
+ });
1408
+ }, [physicsOptions, props]);
1409
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1410
+
1411
+ const getInstance = useImperativeInstance(() => {
1412
+ const desc = rigidBodyDescFromOptions(mergedOptions);
1413
+ const rigidBody = world.createRigidBody(desc);
1414
+ const state = createRigidBodyState({
1415
+ rigidBody,
1416
+ object: ref.current
1417
+ });
1418
+ rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1419
+ return rigidBody;
1420
+ }, rigidBody => {
1421
+ world.removeRigidBody(rigidBody);
1422
+ rigidBodyStates.delete(rigidBody.handle);
1423
+ });
1424
+ useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1425
+ useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1426
+ useImperativeHandle(forwardedRef, () => getInstance());
1427
+ const contextValue = useMemo(() => {
1428
+ return {
1429
+ ref,
1430
+ getRigidBody: getInstance,
1431
+ options: mergedOptions
1432
+ };
1433
+ }, [mergedOptions]);
1464
1434
  return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
1465
1435
  value: contextValue
1466
1436
  }, /*#__PURE__*/React.createElement("object3D", _extends({
1467
- ref: object
1437
+ ref: ref
1468
1438
  }, objectProps, {
1469
1439
  position: position,
1470
1440
  rotation: rotation,
@@ -1476,14 +1446,17 @@ const RigidBody = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, ref) => {
1476
1446
  }));
1477
1447
  RigidBody.displayName = "RigidBody";
1478
1448
 
1449
+ /**
1450
+ * A mesh collider is a collider that is automatically generated from the geometry of the children.
1451
+ * @category Colliders
1452
+ */
1479
1453
  const MeshCollider = /*#__PURE__*/memo(props => {
1480
1454
  const {
1481
1455
  children,
1482
1456
  type
1483
1457
  } = props;
1484
1458
  const {
1485
- physicsOptions,
1486
- world
1459
+ physicsOptions
1487
1460
  } = useRapier();
1488
1461
  const object = useRef(null);
1489
1462
  const {
@@ -1597,155 +1570,119 @@ const Debug = /*#__PURE__*/memo(() => {
1597
1570
  }, attractor))));
1598
1571
  });
1599
1572
 
1600
- const _excluded = ["positions", "rotations", "children"];
1601
- const InstancedRigidBodies = /*#__PURE__*/forwardRef((props, ref) => {
1602
- const {
1603
- world,
1604
- rigidBodyStates,
1605
- physicsOptions,
1606
- rigidBodyEvents
1607
- } = useRapier();
1573
+ const _excluded = ["children", "instances", "colliderNodes", "position", "rotation", "quaternion", "scale"];
1574
+ const InstancedRigidBodies = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, ref) => {
1608
1575
  const object = useRef(null);
1576
+ const instancedWrapper = useRef(null);
1609
1577
 
1610
1578
  const {
1611
- positions,
1612
- rotations,
1613
- children
1579
+ // instanced props
1580
+ children,
1581
+ instances,
1582
+ colliderNodes = [],
1583
+ // wrapper object props
1584
+ position,
1585
+ rotation,
1586
+ quaternion,
1587
+ scale
1614
1588
  } = props,
1615
- options = _objectWithoutProperties(props, _excluded);
1589
+ rigidBodyProps = _objectWithoutProperties(props, _excluded);
1616
1590
 
1617
- const instancesRef = useRef([]);
1618
- const rigidBodyRefs = useRef([]);
1619
- const instancesRefGetter = useRef(() => {
1620
- if (!instancesRef.current) {
1621
- instancesRef.current = [];
1622
- }
1591
+ const rigidBodyApis = useRef([]);
1592
+ useImperativeHandle(ref, () => rigidBodyApis.current, [instances]);
1593
+ const childColliderProps = useChildColliderProps(object, _objectSpread2(_objectSpread2({}, props), {}, {
1594
+ children: undefined
1595
+ }));
1623
1596
 
1624
- return instancesRef.current;
1625
- });
1626
- const mergedOptions = useMemo(() => {
1627
- return _objectSpread2(_objectSpread2({}, physicsOptions), options);
1628
- }, [physicsOptions, options]);
1629
- const childColliderProps = useChildColliderProps(object, mergedOptions);
1630
- useLayoutEffect(() => {
1631
- object.current.updateWorldMatrix(true, false);
1632
- const instances = instancesRefGetter.current();
1633
- const invertedWorld = object.current.matrixWorld.clone().invert();
1634
- object.current.traverseVisible(mesh => {
1635
- if (mesh instanceof InstancedMesh) {
1636
- mesh.instanceMatrix.setUsage(DynamicDrawUsage);
1637
- const worldScale = mesh.getWorldScale(_scale);
1638
-
1639
- for (let index = 0; index < mesh.count; index++) {
1640
- var _options$scales;
1641
-
1642
- const desc = rigidBodyDescFromOptions(props);
1643
- const rigidBody = world.createRigidBody(desc);
1644
- rigidBodyRefs.current.push(rigidBody);
1645
- const scale = ((_options$scales = options.scales) === null || _options$scales === void 0 ? void 0 : _options$scales[index]) || [1, 1, 1];
1646
- const instanceScale = worldScale.clone().multiply(vectorArrayToVector3(scale));
1647
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
1648
- rigidBody,
1649
- object: mesh,
1650
- setMatrix: matrix => mesh.setMatrixAt(index, matrix),
1651
- getMatrix: matrix => {
1652
- mesh.getMatrixAt(index, matrix);
1653
- return matrix;
1654
- },
1655
- worldScale: instanceScale
1656
- }));
1657
- const [x, y, z] = (positions === null || positions === void 0 ? void 0 : positions[index]) || [0, 0, 0];
1658
- const [rx, ry, rz] = (rotations === null || rotations === void 0 ? void 0 : rotations[index]) || [0, 0, 0];
1597
+ const getInstancedMesh = () => {
1598
+ const firstChild = instancedWrapper.current.children[0];
1659
1599
 
1660
- _object3d.position.set(x, y, z);
1600
+ if (firstChild && "isInstancedMesh" in firstChild) {
1601
+ return firstChild;
1602
+ }
1661
1603
 
1662
- _object3d.rotation.set(rx, ry, rz);
1604
+ return undefined;
1605
+ };
1663
1606
 
1664
- _object3d.applyMatrix4(invertedWorld);
1607
+ useEffect(() => {
1608
+ const instancedMesh = getInstancedMesh();
1665
1609
 
1666
- mesh.setMatrixAt(index, _object3d.matrix);
1667
- rigidBody.setTranslation(_object3d.position, false);
1668
- rigidBody.setRotation(_object3d.quaternion, false);
1669
- const api = createRigidBodyApi({
1670
- current() {
1671
- return rigidBody;
1672
- }
1610
+ if (instancedMesh) {
1611
+ instancedMesh.instanceMatrix.setUsage(DynamicDrawUsage);
1612
+ } else {
1613
+ console.warn("InstancedRigidBodies expects exactly one child, which must be an InstancedMesh");
1614
+ }
1615
+ }, []); // Update the RigidBodyStates whenever the instances change
1673
1616
 
1674
- });
1675
- instances.push({
1676
- rigidBody,
1677
- api
1678
- });
1679
- }
1680
- }
1681
- });
1682
- return () => {
1683
- instances.forEach(rb => {
1684
- world.removeRigidBody(rb.rigidBody);
1685
- rigidBodyStates.delete(rb.rigidBody.handle);
1617
+ const applyInstancedState = (state, index) => {
1618
+ const instancedMesh = getInstancedMesh();
1619
+
1620
+ if (instancedMesh) {
1621
+ return _objectSpread2(_objectSpread2({}, state), {}, {
1622
+ getMatrix: matrix => {
1623
+ instancedMesh.getMatrixAt(index, matrix);
1624
+ return matrix;
1625
+ },
1626
+ setMatrix: matrix => {
1627
+ instancedMesh.setMatrixAt(index, matrix);
1628
+ instancedMesh.instanceMatrix.needsUpdate = true;
1629
+ },
1630
+ meshType: "instancedMesh"
1686
1631
  });
1687
- rigidBodyRefs.current = [];
1688
- instancesRef.current = [];
1689
- };
1690
- }, []);
1691
- const api = useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1692
- useImperativeHandle(ref, () => api);
1693
- useUpdateRigidBodyOptions(rigidBodyRefs, mergedOptions, rigidBodyStates, false);
1694
- useRigidBodyEvents(rigidBodyRefs, mergedOptions, rigidBodyEvents);
1695
- const contextValue = useMemo(() => {
1696
- return {
1697
- ref: object,
1698
- api,
1699
- options: mergedOptions
1700
- };
1701
- }, [api, mergedOptions]);
1702
- return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
1703
- value: contextValue
1704
- }, /*#__PURE__*/React.createElement("object3D", {
1632
+ }
1633
+
1634
+ return state;
1635
+ };
1636
+
1637
+ return /*#__PURE__*/React.createElement("object3D", _extends({
1705
1638
  ref: object
1706
- }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1639
+ }, rigidBodyProps, {
1640
+ position: position,
1641
+ rotation: rotation,
1642
+ quaternion: quaternion,
1643
+ scale: scale
1644
+ }), /*#__PURE__*/React.createElement("object3D", {
1645
+ ref: instancedWrapper
1646
+ }, children), instances === null || instances === void 0 ? void 0 : instances.map((instance, index) => /*#__PURE__*/React.createElement(RigidBody, _extends({}, rigidBodyProps, instance, {
1647
+ ref: body => rigidBodyApis.current[index] = body,
1648
+ transformState: state => applyInstancedState(state, index)
1649
+ }), /*#__PURE__*/React.createElement(React.Fragment, null, colliderNodes.map((node, index) => /*#__PURE__*/React.createElement(Fragment, {
1707
1650
  key: index
1708
- }, colliderProps)))));
1709
- });
1651
+ }, node)), childColliderProps.map((colliderProps, colliderIndex) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1652
+ key: colliderIndex
1653
+ }, colliderProps)))))));
1654
+ }));
1710
1655
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1711
1656
 
1657
+ /**
1658
+ * @internal
1659
+ */
1660
+
1712
1661
  const useImpulseJoint = (body1, body2, params) => {
1713
1662
  const {
1714
1663
  world
1715
1664
  } = useRapier();
1716
1665
  const jointRef = useRef();
1717
- const getJointRef = useRef(() => {
1718
- if (!jointRef.current) {
1719
- let rb1;
1720
- let rb2;
1721
-
1722
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1723
- rb1 = world.getRigidBody(body1.current.handle);
1724
- rb2 = world.getRigidBody(body2.current.handle);
1725
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
1726
- jointRef.current = newJoint;
1727
- }
1666
+ useImperativeInstance(() => {
1667
+ if (body1.current && body2.current) {
1668
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1669
+ jointRef.current = newJoint;
1670
+ return newJoint;
1671
+ }
1672
+ }, joint => {
1673
+ if (joint) {
1674
+ jointRef.current = undefined;
1675
+ world.removeImpulseJoint(joint);
1728
1676
  }
1729
-
1730
- return jointRef.current;
1731
1677
  });
1732
- useEffect(() => {
1733
- const joint = getJointRef.current();
1734
- return () => {
1735
- if (joint) {
1736
- world.removeImpulseJoint(joint);
1737
- jointRef.current = undefined;
1738
- }
1739
- };
1740
- }, []);
1741
- const api = useMemo(() => createJointApi(getJointRef), []);
1742
- return api;
1678
+ return jointRef;
1743
1679
  };
1744
1680
  /**
1745
- *
1746
1681
  * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1747
1682
  * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1748
1683
  * The fixed-joint makes these frames coincide in world-space.
1684
+ *
1685
+ * @category Hooks - Joints
1749
1686
  */
1750
1687
 
1751
1688
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
@@ -1759,6 +1696,8 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
1759
1696
  * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1760
1697
  * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1761
1698
  * points that need to coincide on the local-space of each rigid-body.
1699
+ *
1700
+ * @category Hooks - Joints
1762
1701
  */
1763
1702
 
1764
1703
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
@@ -1771,6 +1710,8 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1771
1710
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1772
1711
  * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1773
1712
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
1713
+ *
1714
+ * @category Hooks - Joints
1774
1715
  */
1775
1716
 
1776
1717
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1790,6 +1731,8 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
1790
1731
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1791
1732
  * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1792
1733
  * local tangent axis can be specified for each rigid-body.
1734
+ *
1735
+ * @category Hooks - Joints
1793
1736
  */
1794
1737
 
1795
1738
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
@@ -1842,4 +1785,4 @@ const interactionGroups = (memberships, filters) => (bitmask(memberships) << 16)
1842
1785
 
1843
1786
  const bitmask = groups => [groups].flat().reduce((acc, layer) => acc | 1 << layer, 0);
1844
1787
 
1845
- export { AnyCollider, Attractor, BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, Debug, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundCuboidCollider, TrimeshCollider, interactionGroups, useAfterPhysicsStep, useBeforePhysicsStep, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useSphericalJoint };
1788
+ export { AnyCollider, Attractor, BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, Debug, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundCuboidCollider, TrimeshCollider, euler, interactionGroups, quat, useAfterPhysicsStep, useBeforePhysicsStep, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useSphericalJoint, vec3 };