@react-three/rapier 0.6.8 → 0.7.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.
@@ -1,30 +1,30 @@
1
- import { ColliderDesc, ActiveEvents, RigidBodyDesc, CoefficientCombineRule, EventQueue, ShapeType } from '@dimforge/rapier3d-compat';
1
+ import { EventQueue, RigidBodyDesc, ColliderDesc, ActiveEvents, ShapeType } from '@dimforge/rapier3d-compat';
2
2
  export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
3
- import React, { useState, useEffect, useRef, useMemo, createContext, useContext, forwardRef, useImperativeHandle, memo, useLayoutEffect } from 'react';
3
+ import React, { useState, useEffect, useRef, useMemo, createContext, useContext, memo, forwardRef, useImperativeHandle, useLayoutEffect } from 'react';
4
4
  import { useAsset } from 'use-asset';
5
5
  import { useFrame } from '@react-three/fiber';
6
6
  import { Quaternion, Euler, Vector3, Object3D, Matrix4, InstancedMesh, MeshBasicMaterial, Color, PlaneGeometry, ConeBufferGeometry, CapsuleBufferGeometry, CylinderBufferGeometry, BufferGeometry, BufferAttribute, SphereBufferGeometry, BoxBufferGeometry, DynamicDrawUsage } from 'three';
7
- import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils';
8
- import { RoundedBoxGeometry } from 'three-stdlib';
7
+ import { clamp } from 'three/src/math/MathUtils';
8
+ import { mergeVertices, RoundedBoxGeometry } from 'three-stdlib';
9
9
 
10
10
  const _quaternion = new Quaternion();
11
- const _euler = new Euler();
11
+ new Euler();
12
12
  const _vector3 = new Vector3();
13
- new Object3D();
13
+ const _object3d = new Object3D();
14
14
  const _matrix4 = new Matrix4();
15
+ const _position = new Vector3();
16
+ const _rotation = new Quaternion();
17
+ const _scale = new Vector3();
15
18
 
16
19
  const vectorArrayToVector3 = arr => {
17
20
  const [x, y, z] = arr;
18
21
  return new Vector3(x, y, z);
19
22
  };
20
- const vector3ToQuaternion = v => {
21
- return _quaternion.setFromEuler(_euler.setFromVector3(v));
22
- };
23
23
  const rapierVector3ToVector3 = ({
24
24
  x,
25
25
  y,
26
26
  z
27
- }) => _vector3.set(x, y, z).clone();
27
+ }) => _vector3.set(x, y, z);
28
28
  const rapierQuaternionToQuaternion = ({
29
29
  x,
30
30
  y,
@@ -38,208 +38,6 @@ const rigidBodyTypeMap = {
38
38
  kinematicVelocity: 3
39
39
  };
40
40
  const rigidBodyTypeFromString = type => rigidBodyTypeMap[type];
41
- const decomposeMatrix4 = m => {
42
- const position = new Vector3();
43
- const rotation = new Quaternion();
44
- const scale = new Vector3();
45
- m.decompose(position, rotation, scale);
46
- return {
47
- position,
48
- rotation,
49
- scale
50
- };
51
- };
52
- const scaleColliderArgs = (shape, args, scale) => {
53
- const newArgs = args.slice(); // Heightfield uses a vector
54
-
55
- if (shape === "heightfield") {
56
- const s = newArgs[3];
57
- s.x *= scale.x;
58
- s.x *= scale.y;
59
- s.x *= scale.z;
60
- return newArgs;
61
- } // Trimesh and convex scale the vertices
62
-
63
-
64
- if (shape === "trimesh" || shape === "convexHull") {
65
- newArgs[0] = scaleVertices(newArgs[0], scale);
66
- return newArgs;
67
- } // Prepfill with some extra
68
-
69
-
70
- const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
71
- return newArgs.map((arg, index) => scaleArray[index] * arg);
72
- };
73
- const createColliderFromOptions = ({
74
- options,
75
- world,
76
- rigidBody,
77
- scale,
78
- hasCollisionEvents
79
- }) => {
80
- var _options$shape, _options$args, _options$restitution, _options$restitutionC, _options$friction, _options$frictionComb;
81
-
82
- const mass = (options === null || options === void 0 ? void 0 : options.mass) || 1;
83
- const colliderShape = (_options$shape = options === null || options === void 0 ? void 0 : options.shape) !== null && _options$shape !== void 0 ? _options$shape : "cuboid";
84
- const colliderArgs = (_options$args = options === null || options === void 0 ? void 0 : options.args) !== null && _options$args !== void 0 ? _options$args : [];
85
- const [cmx, cmy, cmz] = (options === null || options === void 0 ? void 0 : options.centerOfMass) || [0, 0, 0];
86
- const [pix, piy, piz] = (options === null || options === void 0 ? void 0 : options.principalAngularInertia) || [mass * 0.2, mass * 0.2, mass * 0.2];
87
- const [x, y, z] = (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
88
- const [rx, ry, rz] = (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
89
- const qRotation = vector3ToQuaternion(new Vector3(rx, ry, rz)); // @ts-ignore
90
-
91
- const scaledArgs = scaleColliderArgs(options.shape, colliderArgs, scale);
92
- let colliderDesc = ColliderDesc[colliderShape]( // @ts-ignore
93
- ...scaledArgs).setTranslation(x * scale.x, y * scale.y, z * scale.z).setRotation({
94
- x: qRotation.x,
95
- y: qRotation.y,
96
- z: qRotation.z,
97
- w: qRotation.w
98
- }).setRestitution((_options$restitution = options === null || options === void 0 ? void 0 : options.restitution) !== null && _options$restitution !== void 0 ? _options$restitution : 0).setRestitutionCombineRule((_options$restitutionC = options === null || options === void 0 ? void 0 : options.restitutionCombineRule) !== null && _options$restitutionC !== void 0 ? _options$restitutionC : CoefficientCombineRule.Average).setFriction((_options$friction = options === null || options === void 0 ? void 0 : options.friction) !== null && _options$friction !== void 0 ? _options$friction : 0.7).setFrictionCombineRule((_options$frictionComb = options === null || options === void 0 ? void 0 : options.frictionCombineRule) !== null && _options$frictionComb !== void 0 ? _options$frictionComb : CoefficientCombineRule.Average);
99
-
100
- if (hasCollisionEvents) {
101
- colliderDesc = colliderDesc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
102
- } // If any of the mass properties are specified, add mass properties
103
-
104
-
105
- const qMassRot = vector3ToQuaternion(new Vector3(0, 0, 0));
106
-
107
- if (options !== null && options !== void 0 && options.mass || options !== null && options !== void 0 && options.centerOfMass || options !== null && options !== void 0 && options.principalAngularInertia) {
108
- colliderDesc.setDensity(0);
109
- colliderDesc.setMassProperties(mass, {
110
- x: cmx,
111
- y: cmy,
112
- z: cmz
113
- }, {
114
- x: pix,
115
- y: piy,
116
- z: piz
117
- }, {
118
- x: qMassRot.x,
119
- y: qMassRot.y,
120
- z: qMassRot.z,
121
- w: qMassRot.w
122
- });
123
- }
124
-
125
- const collider = world.createCollider(colliderDesc, rigidBody);
126
- return collider;
127
- };
128
-
129
- const isChildOfMeshCollider = child => {
130
- let flag = false;
131
- child.traverseAncestors(a => {
132
- if (a.userData.r3RapierType === "MeshCollider") flag = true;
133
- });
134
- return flag;
135
- };
136
-
137
- const createCollidersFromChildren = ({
138
- object,
139
- rigidBody,
140
- options,
141
- world,
142
- ignoreMeshColliders: _ignoreMeshColliders = true
143
- }) => {
144
- const hasCollisionEvents = !!(options.onCollisionEnter || options.onCollisionExit);
145
- const colliders = [];
146
- object.traverseVisible(child => {
147
- if ("isMesh" in child) {
148
- if (_ignoreMeshColliders && isChildOfMeshCollider(child)) return;
149
- const {
150
- geometry
151
- } = child;
152
- const {
153
- x,
154
- y,
155
- z
156
- } = child.position;
157
- const {
158
- x: rx,
159
- y: ry,
160
- z: rz,
161
- w: rw
162
- } = new Quaternion().setFromEuler(child.rotation);
163
- const scale = child.getWorldScale(new Vector3()); // We translate the colliders based on the parent's world scale
164
-
165
- const parentWorldScale = child.parent.getWorldScale(new Vector3());
166
- const desc = colliderDescFromGeometry(geometry, options.colliders, scale, hasCollisionEvents);
167
- const offset = new Vector3(0, 0, 0);
168
-
169
- if (options.colliders === "cuboid") {
170
- var _geometry$boundingBox;
171
-
172
- geometry.computeBoundingBox();
173
- (_geometry$boundingBox = geometry.boundingBox) === null || _geometry$boundingBox === void 0 ? void 0 : _geometry$boundingBox.getCenter(offset);
174
- }
175
-
176
- if (options.colliders === "ball") {
177
- geometry.computeBoundingSphere();
178
- offset.copy(geometry.boundingSphere.center);
179
- }
180
-
181
- if (Number.isFinite(options.friction)) desc.setFriction(options.friction);
182
- if (Number.isFinite(options.restitution)) desc.setRestitution(options.restitution);
183
- desc.setTranslation((x + offset.x) * parentWorldScale.x, (y + offset.y) * parentWorldScale.y, (z + offset.z) * parentWorldScale.z).setRotation({
184
- x: rx,
185
- y: ry,
186
- z: rz,
187
- w: rw
188
- });
189
- const actualRigidBody = rigidBody ? world.getRigidBody(rigidBody.handle) : undefined;
190
- const collider = world.createCollider(desc, actualRigidBody);
191
- colliders.push(collider);
192
- }
193
- });
194
- return colliders;
195
- };
196
- const colliderDescFromGeometry = (geometry, colliders, scale, hasCollisionEvents) => {
197
- let desc;
198
-
199
- switch (colliders) {
200
- case "cuboid":
201
- {
202
- geometry.computeBoundingBox();
203
- const {
204
- boundingBox
205
- } = geometry;
206
- const size = boundingBox.getSize(new Vector3());
207
- desc = ColliderDesc.cuboid(size.x / 2 * scale.x, size.y / 2 * scale.y, size.z / 2 * scale.z);
208
- }
209
- break;
210
-
211
- case "ball":
212
- {
213
- geometry.computeBoundingSphere();
214
- const {
215
- boundingSphere
216
- } = geometry;
217
- const radius = boundingSphere.radius * scale.x;
218
- desc = ColliderDesc.ball(radius);
219
- }
220
- break;
221
-
222
- case "trimesh":
223
- {
224
- var _g$index;
225
-
226
- const clonedGeometry = geometry.index ? geometry.clone() : mergeVertices(geometry);
227
- const g = clonedGeometry.scale(scale.x, scale.y, scale.z);
228
- desc = ColliderDesc.trimesh(g.attributes.position.array, (_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.array);
229
- }
230
- break;
231
-
232
- case "hull":
233
- {
234
- const g = geometry.clone().scale(scale.x, scale.y, scale.z);
235
- desc = ColliderDesc.convexHull(g.attributes.position.array);
236
- }
237
- break;
238
- }
239
-
240
- if (hasCollisionEvents) desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
241
- return desc;
242
- };
243
41
  const scaleVertices = (vertices, scale) => {
244
42
  const scaledVerts = Array.from(vertices);
245
43
 
@@ -251,28 +49,6 @@ const scaleVertices = (vertices, scale) => {
251
49
 
252
50
  return scaledVerts;
253
51
  };
254
- const rigidBodyDescFromOptions = options => {
255
- var _options$linearVeloci, _options$angularVeloc, _options$angularDampi, _options$linearDampin, _options$gravityScale, _options$canSleep, _options$ccd, _options$enabledRotat, _options$enabledTrans;
256
-
257
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
258
- const [lvx, lvy, lvz] = (_options$linearVeloci = options === null || options === void 0 ? void 0 : options.linearVelocity) !== null && _options$linearVeloci !== void 0 ? _options$linearVeloci : [0, 0, 0];
259
- const [avx, avy, avz] = (_options$angularVeloc = options === null || options === void 0 ? void 0 : options.angularVelocity) !== null && _options$angularVeloc !== void 0 ? _options$angularVeloc : [0, 0, 0];
260
- const angularDamping = (_options$angularDampi = options === null || options === void 0 ? void 0 : options.angularDamping) !== null && _options$angularDampi !== void 0 ? _options$angularDampi : 0;
261
- const linearDamping = (_options$linearDampin = options === null || options === void 0 ? void 0 : options.linearDamping) !== null && _options$linearDampin !== void 0 ? _options$linearDampin : 0;
262
- const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
263
- const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
264
- const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
265
- const [erx, ery, erz] = (_options$enabledRotat = options === null || options === void 0 ? void 0 : options.enabledRotations) !== null && _options$enabledRotat !== void 0 ? _options$enabledRotat : [true, true, true];
266
- const [etx, ety, etz] = (_options$enabledTrans = options === null || options === void 0 ? void 0 : options.enabledTranslations) !== null && _options$enabledTrans !== void 0 ? _options$enabledTrans : [true, true, true];
267
- const desc = new RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
268
- x: avx,
269
- y: avy,
270
- z: avz
271
- }).setLinearDamping(linearDamping).setAngularDamping(angularDamping).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).enabledRotations(erx, ery, erz).enabledTranslations(etx, ety, etz);
272
- if (options.lockRotations) desc.lockRotations();
273
- if (options.lockTranslations) desc.lockTranslations();
274
- return desc;
275
- };
276
52
 
277
53
  const createRigidBodyApi = ref => {
278
54
  return {
@@ -424,8 +200,8 @@ const Physics = ({
424
200
  gravity: _gravity = [0, -9.81, 0],
425
201
  children,
426
202
  timeStep: _timeStep = 1 / 60,
427
- maxSubSteps: _maxSubSteps = 10,
428
- paused: _paused = false
203
+ paused: _paused = false,
204
+ updatePriority
429
205
  }) => {
430
206
  const rapier = useAsset(importRapier);
431
207
  const [isPaused, setIsPaused] = useState(_paused);
@@ -442,7 +218,9 @@ const Physics = ({
442
218
  return worldRef.current;
443
219
  });
444
220
  const [rigidBodyStates] = useState(() => new Map());
221
+ const [colliderStates] = useState(() => new Map());
445
222
  const [rigidBodyEvents] = useState(() => new Map());
223
+ const [colliderEvents] = useState(() => new Map());
446
224
  const [eventQueue] = useState(() => new EventQueue(false)); // Init world
447
225
 
448
226
  useEffect(() => {
@@ -462,45 +240,29 @@ const Physics = ({
462
240
  }
463
241
  }, [_gravity]);
464
242
  const [steppingState] = useState({
465
- time: 0,
466
- lastTime: 0,
467
243
  accumulator: 0
468
244
  });
469
- useFrame((_, delta) => {
245
+ useFrame((_, dt) => {
470
246
  const world = worldRef.current;
471
247
  if (!world) return;
472
248
  world.timestep = _timeStep;
473
249
  /**
474
250
  * Fixed timeStep simulation progression
475
- * @see https://gafferongames.com/post/fix_your_timestep/
251
+ * @see https://gafferongames.com/post/fix_your_timestep/
476
252
  */
253
+ // don't step time forwards if paused
254
+ // Increase accumulator
477
255
 
478
- let previousTranslations = {}; // don't step time forwards if paused
479
-
480
- const nowTime = steppingState.time += _paused ? 0 : delta * 1000;
481
- const timeStepMs = _timeStep * 1000;
482
- const timeSinceLast = nowTime - steppingState.lastTime;
483
- steppingState.lastTime = nowTime;
484
- steppingState.accumulator += timeSinceLast;
256
+ steppingState.accumulator += _paused ? 0 : clamp(dt, 0, 0.2);
485
257
 
486
258
  if (!_paused) {
487
- let subSteps = 0;
488
-
489
- while (steppingState.accumulator >= timeStepMs && subSteps < _maxSubSteps) {
490
- // Collect previous state
491
- world.bodies.forEach(b => {
492
- previousTranslations[b.handle] = {
493
- rotation: rapierQuaternionToQuaternion(b.rotation()).normalize(),
494
- translation: rapierVector3ToVector3(b.translation())
495
- };
496
- });
259
+ while (steppingState.accumulator >= _timeStep) {
497
260
  world.step(eventQueue);
498
- subSteps++;
499
- steppingState.accumulator -= timeStepMs;
261
+ steppingState.accumulator -= _timeStep;
500
262
  }
501
263
  }
502
264
 
503
- const interpolationAlpha = steppingState.accumulator % timeStepMs / timeStepMs; // Update meshes
265
+ const interpolationAlpha = steppingState.accumulator % _timeStep / _timeStep; // Update meshes
504
266
 
505
267
  rigidBodyStates.forEach((state, handle) => {
506
268
  const rigidBody = world.getRigidBody(handle);
@@ -526,62 +288,156 @@ const Physics = ({
526
288
  return;
527
289
  }
528
290
 
529
- let oldState = previousTranslations[rigidBody.handle];
530
- let newTranslation = rapierVector3ToVector3(rigidBody.translation());
531
- let newRotation = rapierQuaternionToQuaternion(rigidBody.rotation());
532
- let interpolatedTranslation = oldState ? oldState.translation.lerp(newTranslation, 1) : newTranslation;
533
- let interpolatedRotation = oldState ? oldState.rotation.slerp(newRotation, interpolationAlpha) : newRotation;
534
- state.setMatrix(_matrix4.compose(interpolatedTranslation, interpolatedRotation, state.worldScale).premultiply(state.invertedMatrixWorld));
291
+ let t = rigidBody.translation();
292
+ let r = rigidBody.rotation(); // Get new position
535
293
 
536
- if (state.mesh instanceof InstancedMesh) {
537
- state.mesh.instanceMatrix.needsUpdate = true;
538
- }
539
- }); // Collision events
294
+ _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
540
295
 
296
+ if (state.object instanceof InstancedMesh) {
297
+ state.setMatrix(_matrix4);
298
+ state.object.instanceMatrix.needsUpdate = true;
299
+ } else {
300
+ // Interpolate from last position
301
+ state.object.position.lerp(_position, interpolationAlpha);
302
+ state.object.quaternion.slerp(_rotation, interpolationAlpha);
303
+ }
304
+ });
541
305
  eventQueue.drainCollisionEvents((handle1, handle2, started) => {
542
306
  var _collider1$parent, _collider2$parent;
543
307
 
544
308
  const collider1 = world.getCollider(handle1);
545
309
  const collider2 = world.getCollider(handle2);
546
310
  const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
547
- const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle;
311
+ const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle; // Collision Events
548
312
 
549
- if (!collider1 || !collider2 || rigidBodyHandle1 === undefined || rigidBodyHandle2 === undefined) {
313
+ if (!collider1 || !collider2) {
550
314
  return;
551
315
  }
552
316
 
553
- const rigidBody1 = world.getRigidBody(rigidBodyHandle1);
554
- const rigidBody2 = world.getRigidBody(rigidBodyHandle2);
555
- const events1 = rigidBodyEvents.get(rigidBodyHandle1);
556
- const events2 = rigidBodyEvents.get(rigidBodyHandle2);
317
+ const collider1Events = colliderEvents.get(collider1.handle);
318
+ const collider2Events = colliderEvents.get(collider2.handle);
319
+ const rigidBody1 = rigidBodyHandle1 ? world.getRigidBody(rigidBodyHandle1) : undefined;
320
+ const rigidBody2 = rigidBodyHandle2 ? world.getRigidBody(rigidBodyHandle2) : undefined;
321
+ const rigidBody1Events = rigidBodyHandle1 ? rigidBodyEvents.get(rigidBodyHandle1) : undefined;
322
+ const rigidBody2Events = rigidBodyHandle2 ? rigidBodyEvents.get(rigidBodyHandle2) : undefined;
323
+ const collider1State = colliderStates.get(collider1.handle);
324
+ const collider2State = colliderStates.get(collider2.handle);
325
+ const rigidBody1State = rigidBodyHandle1 ? rigidBodyStates.get(rigidBodyHandle1) : undefined;
326
+ const rigidBody2State = rigidBodyHandle2 ? rigidBodyStates.get(rigidBodyHandle2) : undefined;
557
327
 
558
328
  if (started) {
559
329
  world.contactPair(collider1, collider2, (manifold, flipped) => {
560
- var _events1$onCollisionE, _events2$onCollisionE;
330
+ var _rigidBody1Events$onC, _rigidBody2Events$onC, _collider1Events$onCo, _collider2Events$onCo;
331
+
332
+ /* RigidBody events */
333
+ rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onC = rigidBody1Events.onCollisionEnter) === null || _rigidBody1Events$onC === void 0 ? void 0 : _rigidBody1Events$onC.call(rigidBody1Events, {
334
+ rigidBody: rigidBody2,
335
+ collider: collider2,
336
+ colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
337
+ rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object,
338
+ manifold,
339
+ flipped
340
+ });
341
+ rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onC = rigidBody2Events.onCollisionEnter) === null || _rigidBody2Events$onC === void 0 ? void 0 : _rigidBody2Events$onC.call(rigidBody2Events, {
342
+ rigidBody: rigidBody1,
343
+ collider: collider1,
344
+ colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
345
+ rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object,
346
+ manifold,
347
+ flipped
348
+ });
349
+ /* Collider events */
561
350
 
562
- events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
563
- target: rigidBody2,
351
+ collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onCo = collider1Events.onCollisionEnter) === null || _collider1Events$onCo === void 0 ? void 0 : _collider1Events$onCo.call(collider1Events, {
352
+ rigidBody: rigidBody2,
353
+ collider: collider2,
354
+ colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
355
+ rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object,
564
356
  manifold,
565
357
  flipped
566
358
  });
567
- events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE = events2.onCollisionEnter) === null || _events2$onCollisionE === void 0 ? void 0 : _events2$onCollisionE.call(events2, {
568
- target: rigidBody1,
359
+ collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onCo = collider2Events.onCollisionEnter) === null || _collider2Events$onCo === void 0 ? void 0 : _collider2Events$onCo.call(collider2Events, {
360
+ rigidBody: rigidBody1,
361
+ collider: collider1,
362
+ colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
363
+ rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object,
569
364
  manifold,
570
365
  flipped
571
366
  });
572
367
  });
573
368
  } else {
574
- var _events1$onCollisionE2, _events2$onCollisionE2;
369
+ var _rigidBody1Events$onC2, _rigidBody2Events$onC2, _collider1Events$onCo2, _collider2Events$onCo2;
370
+
371
+ rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onC2 = rigidBody1Events.onCollisionExit) === null || _rigidBody1Events$onC2 === void 0 ? void 0 : _rigidBody1Events$onC2.call(rigidBody1Events, {
372
+ rigidBody: rigidBody2,
373
+ collider: collider2
374
+ });
375
+ rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onC2 = rigidBody2Events.onCollisionExit) === null || _rigidBody2Events$onC2 === void 0 ? void 0 : _rigidBody2Events$onC2.call(rigidBody2Events, {
376
+ rigidBody: rigidBody1,
377
+ collider: collider1
378
+ });
379
+ collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onCo2 = collider1Events.onCollisionExit) === null || _collider1Events$onCo2 === void 0 ? void 0 : _collider1Events$onCo2.call(collider1Events, {
380
+ rigidBody: rigidBody2,
381
+ collider: collider2
382
+ });
383
+ collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onCo2 = collider2Events.onCollisionExit) === null || _collider2Events$onCo2 === void 0 ? void 0 : _collider2Events$onCo2.call(collider2Events, {
384
+ rigidBody: rigidBody1,
385
+ collider: collider1
386
+ });
387
+ } // Sensor Intersections
388
+
389
+
390
+ if (started) {
391
+ if (world.intersectionPair(collider1, collider2)) {
392
+ var _rigidBody1Events$onI, _rigidBody2Events$onI, _collider1Events$onIn, _collider2Events$onIn;
393
+
394
+ rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onI = rigidBody1Events.onIntersectionEnter) === null || _rigidBody1Events$onI === void 0 ? void 0 : _rigidBody1Events$onI.call(rigidBody1Events, {
395
+ rigidBody: rigidBody2,
396
+ collider: collider2,
397
+ colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
398
+ rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object
399
+ });
400
+ rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onI = rigidBody2Events.onIntersectionEnter) === null || _rigidBody2Events$onI === void 0 ? void 0 : _rigidBody2Events$onI.call(rigidBody2Events, {
401
+ rigidBody: rigidBody1,
402
+ collider: collider1,
403
+ colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
404
+ rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object
405
+ });
406
+ collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onIn = collider1Events.onIntersectionEnter) === null || _collider1Events$onIn === void 0 ? void 0 : _collider1Events$onIn.call(collider1Events, {
407
+ rigidBody: rigidBody2,
408
+ collider: collider2,
409
+ colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
410
+ rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object
411
+ });
412
+ collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onIn = collider2Events.onIntersectionEnter) === null || _collider2Events$onIn === void 0 ? void 0 : _collider2Events$onIn.call(collider2Events, {
413
+ rigidBody: rigidBody1,
414
+ collider: collider1,
415
+ colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
416
+ rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object
417
+ });
418
+ }
419
+ } else {
420
+ var _rigidBody1Events$onI2, _rigidBody2Events$onI2, _collider1Events$onIn2, _collider2Events$onIn2;
575
421
 
576
- events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE2 = events1.onCollisionExit) === null || _events1$onCollisionE2 === void 0 ? void 0 : _events1$onCollisionE2.call(events1, {
577
- target: rigidBody2
422
+ rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onI2 = rigidBody1Events.onIntersectionExit) === null || _rigidBody1Events$onI2 === void 0 ? void 0 : _rigidBody1Events$onI2.call(rigidBody1Events, {
423
+ rigidBody: rigidBody2,
424
+ collider: collider2
425
+ });
426
+ rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onI2 = rigidBody2Events.onIntersectionExit) === null || _rigidBody2Events$onI2 === void 0 ? void 0 : _rigidBody2Events$onI2.call(rigidBody2Events, {
427
+ rigidBody: rigidBody1,
428
+ collider: collider1
578
429
  });
579
- events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE2 = events2.onCollisionExit) === null || _events2$onCollisionE2 === void 0 ? void 0 : _events2$onCollisionE2.call(events2, {
580
- target: rigidBody1
430
+ collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onIn2 = collider1Events.onIntersectionExit) === null || _collider1Events$onIn2 === void 0 ? void 0 : _collider1Events$onIn2.call(collider1Events, {
431
+ rigidBody: rigidBody2,
432
+ collider: collider2
433
+ });
434
+ collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onIn2 = collider2Events.onIntersectionExit) === null || _collider2Events$onIn2 === void 0 ? void 0 : _collider2Events$onIn2.call(collider2Events, {
435
+ rigidBody: rigidBody1,
436
+ collider: collider1
581
437
  });
582
438
  }
583
439
  });
584
- });
440
+ }, updatePriority);
585
441
  const api = useMemo(() => createWorldApi(getWorldRef), []);
586
442
  const context = useMemo(() => ({
587
443
  rapier,
@@ -591,7 +447,9 @@ const Physics = ({
591
447
  gravity: _gravity
592
448
  },
593
449
  rigidBodyStates,
450
+ colliderStates,
594
451
  rigidBodyEvents,
452
+ colliderEvents,
595
453
  isPaused
596
454
  }), [isPaused]);
597
455
  return /*#__PURE__*/React.createElement(RapierContext.Provider, {
@@ -692,155 +550,454 @@ function _objectSpread2(target) {
692
550
  return target;
693
551
  }
694
552
 
695
- const useRapier = () => {
696
- return useContext(RapierContext);
553
+ const rigidBodyDescFromOptions = options => {
554
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
555
+ const desc = new RigidBodyDesc(type);
556
+ return desc;
697
557
  };
698
- const useRigidBody = (options = {}) => {
699
- const {
700
- world,
701
- rigidBodyStates,
702
- physicsOptions,
703
- rigidBodyEvents
704
- } = useRapier();
705
- const ref = useRef(); // Create rigidbody
706
-
707
- const rigidBodyRef = useRef();
708
- const getRigidBodyRef = useRef(() => {
709
- if (!rigidBodyRef.current) {
710
- const desc = rigidBodyDescFromOptions(options);
711
- const rigidBody = world.createRigidBody(desc);
712
- rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
713
- }
714
-
715
- return rigidBodyRef.current;
716
- }); // Setup
717
-
718
- useEffect(() => {
719
- var _ref$current$parent, _ref, _options$colliders;
558
+ const createRigidBodyState = ({
559
+ rigidBody,
560
+ object,
561
+ setMatrix,
562
+ getMatrix,
563
+ worldScale
564
+ }) => {
565
+ object.updateWorldMatrix(true, false);
566
+ const invertedWorldMatrix = object.parent.matrixWorld.clone().invert();
567
+ return {
568
+ object,
569
+ rigidBody,
570
+ invertedWorldMatrix,
571
+ setMatrix: setMatrix ? setMatrix : matrix => {
572
+ object.matrix.copy(matrix);
573
+ },
574
+ getMatrix: getMatrix ? getMatrix : matrix => matrix.copy(object.matrix),
575
+ scale: worldScale || object.getWorldScale(_scale).clone(),
576
+ isSleeping: false
577
+ };
578
+ };
579
+ const mutableRigidBodyOptions = {
580
+ gravityScale: (rb, value) => {
581
+ rb.setGravityScale(value, true);
582
+ },
583
+ linearDamping: (rb, value) => {
584
+ rb.setLinearDamping(value);
585
+ },
586
+ angularDamping: (rb, value) => {
587
+ rb.setAngularDamping(value);
588
+ },
589
+ enabledRotations: (rb, [x, y, z]) => {
590
+ rb.setEnabledRotations(x, y, z, true);
591
+ },
592
+ enabledTranslations: (rb, [x, y, z]) => {
593
+ rb.setEnabledTranslations(x, y, z, true);
594
+ },
595
+ angularVelocity: (rb, [x, y, z]) => {
596
+ rb.setAngvel({
597
+ x,
598
+ y,
599
+ z
600
+ }, true);
601
+ },
602
+ linearVelocity: (rb, [x, y, z]) => {
603
+ rb.setLinvel({
604
+ x,
605
+ y,
606
+ z
607
+ }, true);
608
+ },
609
+ ccd: (rb, value) => {
610
+ rb.enableCcd(value);
611
+ }
612
+ };
613
+ const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
614
+ const setRigidBodyOptions = (rigidBody, options, states) => {
615
+ if (!rigidBody) {
616
+ return;
617
+ }
720
618
 
721
- const rigidBody = getRigidBodyRef.current();
722
- rigidBodyRef.current = rigidBody;
619
+ const state = states.get(rigidBody.handle);
723
620
 
724
- if (!ref.current) {
725
- ref.current = new Object3D();
726
- } // isSleeping used for onSleep and onWake events
621
+ if (state) {
622
+ state.object.updateWorldMatrix(true, false);
727
623
 
624
+ _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
728
625
 
729
- ref.current.userData.isSleeping = false; // Get intitial world transforms
730
-
731
- const worldPosition = ref.current.getWorldPosition(new Vector3());
732
- const worldRotation = ref.current.getWorldQuaternion(new Quaternion());
733
- const scale = ((_ref$current$parent = ref.current.parent) === null || _ref$current$parent === void 0 ? void 0 : _ref$current$parent.getWorldScale(new Vector3())) || {
734
- x: 1,
735
- y: 1,
736
- z: 1
737
- }; // Transforms from options
738
-
739
- const [x, y, z] = (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
740
- const [rx, ry, rz] = (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0]; // Set initial transforms based on world transforms
741
-
742
- rigidBody.setTranslation({
743
- x: worldPosition.x + x * scale.x,
744
- y: worldPosition.y + y * scale.y,
745
- z: worldPosition.z + z * scale.z
746
- }, false);
747
- const rotation = vector3ToQuaternion(new Vector3(rx, ry, rz)).multiply(worldRotation);
748
- rigidBody.setRotation({
749
- x: rotation.x,
750
- y: rotation.y,
751
- z: rotation.z,
752
- w: rotation.w
753
- }, false);
754
- rigidBody.resetForces(false);
755
- rigidBody.resetTorques(false);
756
- const colliderSetting = (_ref = (_options$colliders = options === null || options === void 0 ? void 0 : options.colliders) !== null && _options$colliders !== void 0 ? _options$colliders : physicsOptions.colliders) !== null && _ref !== void 0 ? _ref : false;
757
- const autoColliders = colliderSetting !== false ? createCollidersFromChildren({
758
- object: ref.current,
759
- rigidBody,
760
- options: _objectSpread2(_objectSpread2({}, options), {}, {
761
- colliders: colliderSetting
762
- }),
763
- world,
764
- ignoreMeshColliders: true
765
- }) : [];
766
- rigidBodyStates.set(rigidBody.handle, {
767
- mesh: ref.current,
768
- invertedMatrixWorld: ref.current.parent.matrixWorld.clone().invert(),
769
- isSleeping: false,
770
- worldScale: ref.current.getWorldScale(_vector3).clone(),
771
- setMatrix: mat => ref.current.matrix.copy(mat),
772
- getMatrix: () => ref.current.matrix
626
+ rigidBody.setTranslation(_position, false);
627
+ rigidBody.setRotation(_rotation, false);
628
+ mutableRigidBodyOptionKeys.forEach(key => {
629
+ if (key in options) {
630
+ mutableRigidBodyOptions[key](rigidBody, options[key]);
631
+ }
773
632
  });
774
- ref.current.matrixAutoUpdate = false;
775
- return () => {
776
- world.removeRigidBody(rigidBody);
777
- autoColliders.forEach(collider => world.removeCollider(collider));
778
- rigidBodyRef.current = undefined;
779
- rigidBodyStates.delete(rigidBody.handle);
780
- };
781
- }, []); // Events
782
-
633
+ }
634
+ };
635
+ const useUpdateRigidBodyOptions = (rigidBodyRef, props, states) => {
783
636
  useEffect(() => {
784
- const rigidBody = getRigidBodyRef.current();
785
- rigidBodyEvents.set(rigidBody.handle, {
786
- onCollisionEnter: options === null || options === void 0 ? void 0 : options.onCollisionEnter,
787
- onCollisionExit: options === null || options === void 0 ? void 0 : options.onCollisionExit,
788
- onSleep: options === null || options === void 0 ? void 0 : options.onSleep,
789
- onWake: options === null || options === void 0 ? void 0 : options.onWake
790
- });
791
- return () => {
792
- rigidBodyEvents.delete(rigidBody.handle);
793
- };
794
- }, [options.onCollisionEnter, options.onCollisionExit]);
795
- const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
796
- return [ref, api];
797
- }; // Joints
798
-
799
- const useImpulseJoint = (body1, body2, params) => {
637
+ setRigidBodyOptions(rigidBodyRef.current, props, states);
638
+ }, [props]);
639
+ };
640
+ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
800
641
  const {
801
- world
802
- } = useRapier();
803
- const jointRef = useRef();
804
- const getJointRef = useRef(() => {
805
- if (!jointRef.current) {
806
- let rb1;
807
- let rb2;
808
-
809
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
810
- rb1 = world.getRigidBody(body1.current.handle);
811
- rb2 = world.getRigidBody(body2.current.handle);
812
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
813
- jointRef.current = newJoint;
814
- }
815
- }
816
-
817
- return jointRef.current;
818
- });
642
+ onWake,
643
+ onSleep,
644
+ onCollisionEnter,
645
+ onCollisionExit,
646
+ onIntersectionEnter,
647
+ onIntersectionExit
648
+ } = props;
819
649
  useEffect(() => {
820
- const joint = getJointRef.current();
650
+ events.set(rigidBodyRef.current.handle, {
651
+ onWake,
652
+ onSleep,
653
+ onCollisionEnter,
654
+ onCollisionExit,
655
+ onIntersectionEnter,
656
+ onIntersectionExit
657
+ });
821
658
  return () => {
822
- if (joint) {
823
- world.removeImpulseJoint(joint);
824
- jointRef.current = undefined;
825
- }
659
+ events.delete(rigidBodyRef.current.handle);
826
660
  };
827
- }, []);
828
- const api = useMemo(() => createJointApi(getJointRef), []);
829
- return api;
661
+ }, [onWake, onSleep, onCollisionEnter, onCollisionExit]);
830
662
  };
831
- /**
832
- *
833
- * A fixed joint ensures that two rigid-bodies don't move relative to each other.
834
- * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
835
- * The fixed-joint makes these frames coincide in world-space.
836
- */
837
663
 
838
- const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
839
- const {
840
- rapier
841
- } = useRapier();
842
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
843
- w: 1
664
+ const scaleColliderArgs = (shape, args, scale) => {
665
+ const newArgs = args.slice(); // Heightfield uses a vector
666
+
667
+ if (shape === "heightfield") {
668
+ const s = newArgs[3];
669
+ s.x *= scale.x;
670
+ s.x *= scale.y;
671
+ s.x *= scale.z;
672
+ return newArgs;
673
+ } // Trimesh and convex scale the vertices
674
+
675
+
676
+ if (shape === "trimesh" || shape === "convexHull") {
677
+ newArgs[0] = scaleVertices(newArgs[0], scale);
678
+ return newArgs;
679
+ } // Prepfill with some extra
680
+
681
+
682
+ const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
683
+ return newArgs.map((arg, index) => scaleArray[index] * arg);
684
+ };
685
+ const createColliderFromOptions = (options, world, scale, rigidBody) => {
686
+ const scaledArgs = scaleColliderArgs(options.shape, options.args, scale); // @ts-ignore
687
+
688
+ const desc = ColliderDesc[options.shape](...scaledArgs);
689
+ return world.createCollider(desc, rigidBody);
690
+ };
691
+ const mutableColliderOptions = {
692
+ sensor: (collider, value) => {
693
+ collider.setSensor(value);
694
+ },
695
+ collisionGroups: (collider, value) => {
696
+ collider.setCollisionGroups(value);
697
+ },
698
+ solverGroups: (collider, value) => {
699
+ collider.setSolverGroups(value);
700
+ },
701
+ friction: (collider, value) => {
702
+ collider.setFriction(value);
703
+ },
704
+ restitution: (collider, value) => {
705
+ collider.setRestitution(value);
706
+ },
707
+ density: (collider, value) => {
708
+ collider.setDensity(value);
709
+ },
710
+ mass: (collider, value) => {
711
+ collider.setMass(value);
712
+ }
713
+ };
714
+ const mutableColliderOptionKeys = Object.keys(mutableColliderOptions);
715
+ const setColliderOptions = (collider, options, states) => {
716
+ const state = states.get(collider.handle);
717
+
718
+ if (state) {
719
+ // Update collider position based on the object's position
720
+ const parentWorldScale = state.object.parent.getWorldScale(_vector3);
721
+ state.object.updateWorldMatrix(true, false);
722
+
723
+ _matrix4.copy(state.object.matrixWorld).premultiply(state.worldParent.matrixWorld.clone().invert()).decompose(_position, _rotation, _scale);
724
+
725
+ collider.setTranslationWrtParent({
726
+ x: _position.x * parentWorldScale.x,
727
+ y: _position.y * parentWorldScale.y,
728
+ z: _position.z * parentWorldScale.z
729
+ });
730
+ collider.setRotationWrtParent(_rotation);
731
+ mutableColliderOptionKeys.forEach(key => {
732
+ if (key in options) {
733
+ mutableColliderOptions[key](collider, options[key]);
734
+ }
735
+ });
736
+ }
737
+ };
738
+ const useUpdateColliderOptions = (collidersRef, props, states) => {
739
+ useEffect(() => {
740
+ collidersRef.current.forEach(collider => {
741
+ setColliderOptions(collider, props, states);
742
+ });
743
+ }, [props]);
744
+ };
745
+
746
+ const isChildOfMeshCollider = child => {
747
+ let flag = false;
748
+ child.traverseAncestors(a => {
749
+ if (a.userData.r3RapierType === "MeshCollider") flag = true;
750
+ });
751
+ return flag;
752
+ };
753
+
754
+ const createColliderState = (collider, object, rigidBodyObject) => {
755
+ return {
756
+ collider,
757
+ worldParent: rigidBodyObject || object.parent,
758
+ object
759
+ };
760
+ };
761
+ const autoColliderMap = {
762
+ cuboid: "cuboid",
763
+ ball: "ball",
764
+ hull: "convexHull",
765
+ trimesh: "trimesh"
766
+ };
767
+ const createColliderPropsFromChildren = ({
768
+ object,
769
+ ignoreMeshColliders: _ignoreMeshColliders = true,
770
+ options
771
+ }) => {
772
+ const colliderProps = [];
773
+ object.updateWorldMatrix(true, false);
774
+ const invertedParentMatrixWorld = object.matrixWorld.clone().invert();
775
+ object.traverseVisible(child => {
776
+ if ("isMesh" in child) {
777
+ if (_ignoreMeshColliders && isChildOfMeshCollider(child)) return;
778
+ const worldScale = child.getWorldScale(_scale);
779
+ const shape = autoColliderMap[options.colliders || "cuboid"];
780
+ child.updateWorldMatrix(true, false);
781
+
782
+ _matrix4.copy(child.matrixWorld).premultiply(invertedParentMatrixWorld).decompose(_position, _rotation, _scale);
783
+
784
+ const rotationEuler = new Euler().setFromQuaternion(_rotation, "XYZ");
785
+ const {
786
+ geometry
787
+ } = child;
788
+ const {
789
+ args,
790
+ offset
791
+ } = getColliderArgsFromGeometry(geometry, options.colliders || "cuboid");
792
+ colliderProps.push(_objectSpread2(_objectSpread2({}, options), {}, {
793
+ args: args,
794
+ shape: shape,
795
+ rotation: [rotationEuler.x, rotationEuler.y, rotationEuler.z],
796
+ position: [_position.x + offset.x * worldScale.x, _position.y + offset.y * worldScale.y, _position.z + offset.z * worldScale.z],
797
+ scale: [worldScale.x, worldScale.y, worldScale.z]
798
+ }));
799
+ }
800
+ });
801
+ return colliderProps;
802
+ };
803
+ const getColliderArgsFromGeometry = (geometry, colliders) => {
804
+ switch (colliders) {
805
+ case "cuboid":
806
+ {
807
+ geometry.computeBoundingBox();
808
+ const {
809
+ boundingBox
810
+ } = geometry;
811
+ const size = boundingBox.getSize(new Vector3());
812
+ return {
813
+ args: [size.x / 2, size.y / 2, size.z / 2],
814
+ offset: boundingBox.getCenter(new Vector3())
815
+ };
816
+ }
817
+
818
+ case "ball":
819
+ {
820
+ geometry.computeBoundingSphere();
821
+ const {
822
+ boundingSphere
823
+ } = geometry;
824
+ const radius = boundingSphere.radius;
825
+ return {
826
+ args: [radius],
827
+ offset: boundingSphere.center
828
+ };
829
+ }
830
+
831
+ case "trimesh":
832
+ {
833
+ var _clonedGeometry$index;
834
+
835
+ const clonedGeometry = geometry.index ? geometry.clone() : mergeVertices(geometry);
836
+ return {
837
+ args: [clonedGeometry.attributes.position.array, (_clonedGeometry$index = clonedGeometry.index) === null || _clonedGeometry$index === void 0 ? void 0 : _clonedGeometry$index.array],
838
+ offset: new Vector3()
839
+ };
840
+ }
841
+
842
+ case "hull":
843
+ {
844
+ const g = geometry.clone();
845
+ return {
846
+ args: [g.attributes.position.array],
847
+ offset: new Vector3()
848
+ };
849
+ }
850
+ }
851
+
852
+ return {
853
+ args: [],
854
+ offset: new Vector3()
855
+ };
856
+ };
857
+ const useColliderEvents = (collidersRef, props, events) => {
858
+ const {
859
+ onCollisionEnter,
860
+ onCollisionExit,
861
+ onIntersectionEnter,
862
+ onIntersectionExit
863
+ } = props;
864
+ useEffect(() => {
865
+ var _collidersRef$current;
866
+
867
+ (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
868
+ if (onCollisionEnter || onCollisionExit || onIntersectionEnter || onIntersectionExit) {
869
+ collider.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
870
+ }
871
+
872
+ events.set(collider.handle, {
873
+ onCollisionEnter,
874
+ onCollisionExit,
875
+ onIntersectionEnter,
876
+ onIntersectionExit
877
+ });
878
+ });
879
+ return () => {
880
+ var _collidersRef$current2;
881
+
882
+ (_collidersRef$current2 = collidersRef.current) === null || _collidersRef$current2 === void 0 ? void 0 : _collidersRef$current2.forEach(collider => events.delete(collider.handle));
883
+ };
884
+ }, [onCollisionEnter, onCollisionExit]);
885
+ };
886
+
887
+ const useRapier = () => {
888
+ return useContext(RapierContext);
889
+ };
890
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
891
+ const [colliderProps, setColliderProps] = useState([]);
892
+ useEffect(() => {
893
+ const object = ref.current;
894
+
895
+ if (object && options.colliders !== false) {
896
+ setColliderProps(createColliderPropsFromChildren({
897
+ object: ref.current,
898
+ options,
899
+ ignoreMeshColliders
900
+ }));
901
+ }
902
+ }, [options]);
903
+ return colliderProps;
904
+ };
905
+ const useRigidBody = (options = {}) => {
906
+ const {
907
+ world,
908
+ rigidBodyStates,
909
+ physicsOptions,
910
+ rigidBodyEvents
911
+ } = useRapier();
912
+ const ref = useRef();
913
+ const mergedOptions = useMemo(() => {
914
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
915
+ children: undefined
916
+ });
917
+ }, [physicsOptions, options]);
918
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
919
+
920
+ const rigidBodyRef = useRef();
921
+ const getRigidBodyRef = useRef(() => {
922
+ if (!rigidBodyRef.current) {
923
+ const desc = rigidBodyDescFromOptions(options);
924
+ const rigidBody = world.createRigidBody(desc);
925
+ rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
926
+ }
927
+
928
+ return rigidBodyRef.current;
929
+ }); // Setup
930
+
931
+ useEffect(() => {
932
+ const rigidBody = getRigidBodyRef.current();
933
+ rigidBodyRef.current = rigidBody;
934
+
935
+ if (!ref.current) {
936
+ ref.current = new Object3D();
937
+ } // isSleeping used for onSleep and onWake events
938
+
939
+
940
+ ref.current.userData.isSleeping = false;
941
+ rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
942
+ rigidBody,
943
+ object: ref.current
944
+ }));
945
+ return () => {
946
+ world.removeRigidBody(rigidBody);
947
+ rigidBodyStates.delete(rigidBody.handle);
948
+ };
949
+ }, []);
950
+ useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
951
+ useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
952
+ const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
953
+ return [ref, api, childColliderProps];
954
+ }; // Joints
955
+
956
+ const useImpulseJoint = (body1, body2, params) => {
957
+ const {
958
+ world
959
+ } = useRapier();
960
+ const jointRef = useRef();
961
+ const getJointRef = useRef(() => {
962
+ if (!jointRef.current) {
963
+ let rb1;
964
+ let rb2;
965
+
966
+ if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
967
+ rb1 = world.getRigidBody(body1.current.handle);
968
+ rb2 = world.getRigidBody(body2.current.handle);
969
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
970
+ jointRef.current = newJoint;
971
+ }
972
+ }
973
+
974
+ return jointRef.current;
975
+ });
976
+ useEffect(() => {
977
+ const joint = getJointRef.current();
978
+ return () => {
979
+ if (joint) {
980
+ world.removeImpulseJoint(joint);
981
+ jointRef.current = undefined;
982
+ }
983
+ };
984
+ }, []);
985
+ const api = useMemo(() => createJointApi(getJointRef), []);
986
+ return api;
987
+ };
988
+ /**
989
+ *
990
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
991
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
992
+ * The fixed-joint makes these frames coincide in world-space.
993
+ */
994
+
995
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
996
+ const {
997
+ rapier
998
+ } = useRapier();
999
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
1000
+ w: 1
844
1001
  }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
845
1002
  w: 1
846
1003
  })));
@@ -883,80 +1040,173 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
883
1040
  return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
884
1041
  };
885
1042
 
886
- const _excluded$1 = ["children"],
887
- _excluded2 = ["type", "position", "rotation"];
888
- const RigidBodyContext = /*#__PURE__*/createContext(undefined);
889
- const useRigidBodyContext = () => useContext(RigidBodyContext); // RigidBody
1043
+ // Colliders
1044
+ const AnyCollider = /*#__PURE__*/memo(props => {
1045
+ const {
1046
+ children,
1047
+ position,
1048
+ rotation,
1049
+ quaternion,
1050
+ scale
1051
+ } = props;
1052
+ const {
1053
+ world,
1054
+ colliderEvents,
1055
+ colliderStates
1056
+ } = useRapier();
1057
+ const rigidBodyContext = useRigidBodyContext();
1058
+ const ref = useRef(null);
1059
+ const collidersRef = useRef([]);
1060
+ useEffect(() => {
1061
+ const object = ref.current;
1062
+ const worldScale = object.getWorldScale(new Vector3());
1063
+ const colliders = []; // If this is an InstancedRigidBody api
890
1064
 
891
- const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
892
- let {
893
- children
894
- } = _ref,
895
- props = _objectWithoutProperties(_ref, _excluded$1);
1065
+ if (rigidBodyContext && "at" in rigidBodyContext.api) {
1066
+ rigidBodyContext.api.forEach((body, index) => {
1067
+ var _rigidBodyContext$opt, _rigidBodyContext$opt2;
1068
+
1069
+ let instanceScale = worldScale;
1070
+
1071
+ 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]) {
1072
+ instanceScale = instanceScale.clone().multiply(vectorArrayToVector3(rigidBodyContext.options.scales[index]));
1073
+ }
1074
+
1075
+ const collider = createColliderFromOptions(props, world, instanceScale, body.raw());
1076
+ colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1077
+ colliders.push(collider);
1078
+ });
1079
+ } else {
1080
+ const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext && (rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.api).raw());
1081
+ colliderStates.set(collider.handle, createColliderState(collider, object, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1082
+ colliders.push(collider);
1083
+ }
896
1084
 
897
- const [object, api] = useRigidBody(props);
1085
+ collidersRef.current = colliders;
1086
+ return () => {
1087
+ colliders.forEach(collider => {
1088
+ world.removeCollider(collider);
1089
+ });
1090
+ };
1091
+ }, []);
1092
+ useUpdateColliderOptions(collidersRef, props, colliderStates);
1093
+ useColliderEvents(collidersRef, props, colliderEvents);
1094
+ return /*#__PURE__*/React.createElement("object3D", {
1095
+ position: position,
1096
+ rotation: rotation,
1097
+ quaternion: quaternion,
1098
+ scale: scale,
1099
+ ref: ref
1100
+ }, children);
1101
+ });
1102
+ const CuboidCollider = props => {
1103
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1104
+ shape: "cuboid"
1105
+ }));
1106
+ };
1107
+ const RoundCuboidCollider = props => {
1108
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1109
+ shape: "roundCuboid"
1110
+ }));
1111
+ };
1112
+ const BallCollider = props => {
1113
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1114
+ shape: "ball"
1115
+ }));
1116
+ };
1117
+ const CapsuleCollider = props => {
1118
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1119
+ shape: "capsule"
1120
+ }));
1121
+ };
1122
+ const HeightfieldCollider = props => {
1123
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1124
+ shape: "heightfield"
1125
+ }));
1126
+ };
1127
+ const TrimeshCollider = props => {
1128
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1129
+ shape: "trimesh"
1130
+ }));
1131
+ };
1132
+ const ConeCollider = props => {
1133
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1134
+ shape: "cone"
1135
+ }));
1136
+ };
1137
+ const CylinderCollider = props => {
1138
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1139
+ shape: "cylinder"
1140
+ }));
1141
+ };
1142
+ const ConvexHullCollider = props => {
1143
+ return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1144
+ shape: "convexHull"
1145
+ }));
1146
+ };
898
1147
 
899
- const objectProps = _objectWithoutProperties(props, _excluded2);
1148
+ const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1149
+ const RigidBodyContext = /*#__PURE__*/createContext(undefined);
1150
+ const useRigidBodyContext = () => useContext(RigidBodyContext);
1151
+ const RigidBody = /*#__PURE__*/forwardRef((props, ref) => {
1152
+ const {
1153
+ children,
1154
+ type,
1155
+ position,
1156
+ rotation,
1157
+ scale,
1158
+ quaternion
1159
+ } = props,
1160
+ objectProps = _objectWithoutProperties(props, _excluded$1);
900
1161
 
1162
+ const [object, api, childColliderProps] = useRigidBody(props);
901
1163
  useImperativeHandle(ref, () => api);
902
1164
  return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
903
1165
  value: {
904
1166
  ref: object,
905
1167
  api,
906
- hasCollisionEvents: !!(props.onCollisionEnter || props.onCollisionExit),
907
1168
  options: props
908
1169
  }
909
1170
  }, /*#__PURE__*/React.createElement("object3D", _extends({
910
1171
  ref: object
911
- }, objectProps), children));
1172
+ }, objectProps, {
1173
+ position: position,
1174
+ rotation: rotation,
1175
+ quaternion: quaternion,
1176
+ scale: scale
1177
+ }), children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1178
+ key: index
1179
+ }, colliderProps)))));
912
1180
  });
913
1181
 
914
- const MeshCollider = ({
915
- children,
916
- type
917
- }) => {
1182
+ const MeshCollider = props => {
1183
+ const {
1184
+ children,
1185
+ type
1186
+ } = props;
918
1187
  const {
919
1188
  physicsOptions,
920
1189
  world
921
1190
  } = useRapier();
922
1191
  const object = useRef(null);
923
1192
  const {
924
- api,
925
1193
  options
926
1194
  } = useRigidBodyContext();
927
- useEffect(() => {
928
- let autoColliders = [];
929
-
930
- if (object.current) {
931
- var _ref;
932
-
933
- const colliderSetting = (_ref = type !== null && type !== void 0 ? type : physicsOptions.colliders) !== null && _ref !== void 0 ? _ref : false;
934
-
935
- if ("raw" in api) {
936
- autoColliders = createCollidersFromChildren({
937
- object: object.current,
938
- rigidBody: api,
939
- options: _objectSpread2(_objectSpread2({}, options), {}, {
940
- colliders: colliderSetting
941
- }),
942
- world,
943
- ignoreMeshColliders: false
944
- });
945
- }
946
- }
947
-
948
- return () => {
949
- autoColliders.forEach(collider => {
950
- world.removeCollider(collider);
951
- });
952
- };
953
- }, []);
1195
+ const mergedOptions = useMemo(() => {
1196
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
1197
+ children: undefined,
1198
+ colliders: type
1199
+ });
1200
+ }, [physicsOptions, options]);
1201
+ const childColliderProps = useChildColliderProps(object, mergedOptions, false);
954
1202
  return /*#__PURE__*/React.createElement("object3D", {
955
1203
  ref: object,
956
1204
  userData: {
957
1205
  r3RapierType: "MeshCollider"
958
1206
  }
959
- }, children);
1207
+ }, children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1208
+ key: index
1209
+ }, colliderProps))));
960
1210
  };
961
1211
 
962
1212
  const geometryFromCollider = collider => {
@@ -1133,6 +1383,7 @@ const Debug = ({
1133
1383
  })));
1134
1384
  };
1135
1385
 
1386
+ const _excluded = ["positions", "rotations", "children"];
1136
1387
  const InstancedRigidBodies = /*#__PURE__*/forwardRef((props, ref) => {
1137
1388
  const {
1138
1389
  world,
@@ -1140,6 +1391,14 @@ const InstancedRigidBodies = /*#__PURE__*/forwardRef((props, ref) => {
1140
1391
  physicsOptions
1141
1392
  } = useRapier();
1142
1393
  const object = useRef(null);
1394
+
1395
+ const {
1396
+ positions,
1397
+ rotations,
1398
+ children
1399
+ } = props,
1400
+ options = _objectWithoutProperties(props, _excluded);
1401
+
1143
1402
  const instancesRef = useRef();
1144
1403
  const instancesRefGetter = useRef(() => {
1145
1404
  if (!instancesRef.current) {
@@ -1148,214 +1407,119 @@ const InstancedRigidBodies = /*#__PURE__*/forwardRef((props, ref) => {
1148
1407
 
1149
1408
  return instancesRef.current;
1150
1409
  });
1410
+ const mergedOptions = useMemo(() => {
1411
+ return _objectSpread2(_objectSpread2({}, physicsOptions), options);
1412
+ }, [physicsOptions, options]);
1413
+ const childColliderProps = useChildColliderProps(object, mergedOptions);
1151
1414
  useLayoutEffect(() => {
1152
- const colliders = [];
1415
+ object.current.updateWorldMatrix(true, false);
1153
1416
  const rigidBodies = instancesRefGetter.current();
1154
-
1155
- if (object.current) {
1156
- const worldScale = object.current.getWorldScale(new Vector3());
1157
- let hasOneMesh = false;
1158
- object.current.traverse(mesh => {
1159
- if (mesh instanceof InstancedMesh) {
1160
- if (hasOneMesh) {
1161
- console.warn("Can only use a single InstancedMesh inside <InstancedRigidBodies />, more InstancedMeshes will be ignored.");
1162
- return;
1163
- }
1164
-
1165
- hasOneMesh = true;
1166
- mesh.instanceMatrix.setUsage(DynamicDrawUsage);
1167
-
1168
- for (let index = 0; index < mesh.count; index++) {
1169
- const scale = worldScale.clone();
1170
- const rigidBodyDesc = rigidBodyDescFromOptions(props);
1171
-
1172
- if (props.scales && props.scales[index]) {
1173
- const s = vectorArrayToVector3(props.scales[index]);
1174
- scale.multiply(s);
1175
- }
1176
-
1177
- const rigidBody = world.createRigidBody(rigidBodyDesc);
1178
- const matrix = new Matrix4();
1179
- mesh.getMatrixAt(index, matrix);
1180
- const {
1181
- position,
1182
- rotation
1183
- } = decomposeMatrix4(matrix);
1184
-
1185
- if (props.colliders !== false) {
1186
- const colliderDesc = colliderDescFromGeometry(mesh.geometry, props.colliders !== undefined ? props.colliders : physicsOptions.colliders, scale, false // Collisions currently not enabled for instances
1187
- );
1188
- const collider = world.createCollider(colliderDesc, rigidBody);
1189
- colliders.push(collider);
1190
- } // Set positions
1191
-
1192
-
1193
- if (props.positions && props.positions[index]) {
1194
- rigidBody.setTranslation(vectorArrayToVector3(props.positions[index]), true);
1195
- } else {
1196
- rigidBody.setTranslation(position, true);
1197
- } // Set rotations
1198
-
1199
-
1200
- if (props.rotations && props.rotations[index]) {
1201
- const [x, y, z] = props.rotations[index];
1202
- rigidBody.setRotation(vector3ToQuaternion(new Vector3(x, y, z)), true);
1203
- } else {
1204
- rigidBody.setRotation(rotation, true);
1417
+ const invertedWorld = object.current.matrixWorld.clone().invert();
1418
+ object.current.traverseVisible(mesh => {
1419
+ if (mesh instanceof InstancedMesh) {
1420
+ mesh.instanceMatrix.setUsage(DynamicDrawUsage);
1421
+ const worldScale = mesh.getWorldScale(_scale);
1422
+
1423
+ for (let index = 0; index < mesh.count; index++) {
1424
+ var _options$scales;
1425
+
1426
+ const desc = rigidBodyDescFromOptions(props);
1427
+ const rigidBody = world.createRigidBody(desc);
1428
+ const scale = ((_options$scales = options.scales) === null || _options$scales === void 0 ? void 0 : _options$scales[index]) || [1, 1, 1];
1429
+ const instanceScale = worldScale.clone().multiply(vectorArrayToVector3(scale));
1430
+ rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
1431
+ rigidBody,
1432
+ object: mesh,
1433
+ setMatrix: matrix => mesh.setMatrixAt(index, matrix),
1434
+ getMatrix: matrix => {
1435
+ mesh.getMatrixAt(index, matrix);
1436
+ return matrix;
1437
+ },
1438
+ worldScale: instanceScale
1439
+ }));
1440
+ const [x, y, z] = (positions === null || positions === void 0 ? void 0 : positions[index]) || [0, 0, 0];
1441
+ const [rx, ry, rz] = (rotations === null || rotations === void 0 ? void 0 : rotations[index]) || [0, 0, 0];
1442
+
1443
+ _object3d.position.set(x, y, z);
1444
+
1445
+ _object3d.rotation.set(rx, ry, rz);
1446
+
1447
+ _object3d.applyMatrix4(invertedWorld); // Set initial transforms based on world transforms
1448
+ // will be replaced by the setRigidBodyOption below
1449
+
1450
+
1451
+ rigidBody.setTranslation(_object3d.position, false);
1452
+ rigidBody.setRotation(_object3d.quaternion, false);
1453
+ const api = createRigidBodyApi({
1454
+ current() {
1455
+ return rigidBody;
1205
1456
  }
1206
1457
 
1207
- rigidBodyStates.set(rigidBody.handle, {
1208
- mesh: mesh,
1209
- isSleeping: false,
1210
- invertedMatrixWorld: object.current.matrixWorld.clone().invert(),
1211
- setMatrix: matrix => mesh.setMatrixAt(index, matrix),
1212
- getMatrix: () => {
1213
- const m = new Matrix4();
1214
- mesh.getMatrixAt(index, m);
1215
- return m;
1216
- },
1217
- // Setting the world scale to the scale here, because
1218
- // we want the scales to be reflected by instance
1219
- worldScale: scale
1220
- });
1221
- const api = createRigidBodyApi({
1222
- current() {
1223
- return rigidBody;
1224
- }
1225
-
1226
- });
1227
- rigidBodies.push({
1228
- rigidBody,
1229
- api
1230
- });
1231
- }
1232
- }
1233
-
1234
- if (mesh.type === "Mesh" && !("isInstancedMesh" in mesh)) {
1235
- console.warn("Can only use InstancedMesh inside <InstancedRigidBodies />, Mesh will be ignored.");
1458
+ });
1459
+ rigidBodies.push({
1460
+ rigidBody,
1461
+ api
1462
+ });
1236
1463
  }
1464
+ }
1465
+ });
1466
+ return () => {
1467
+ rigidBodies.forEach(rb => {
1468
+ world.removeRigidBody(rb.rigidBody);
1469
+ rigidBodyStates.delete(rb.rigidBody.handle);
1237
1470
  });
1238
- return () => {
1239
- rigidBodies.forEach(rb => world.removeRigidBody(rb.rigidBody));
1240
- colliders.forEach(coll => world.removeCollider(coll));
1241
- instancesRef.current = undefined;
1242
- };
1243
- }
1471
+ instancesRef.current = undefined;
1472
+ };
1244
1473
  }, []);
1245
1474
  const api = useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1246
- useImperativeHandle(ref, () => api); // console.log(api);
1247
-
1475
+ useImperativeHandle(ref, () => api);
1248
1476
  return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
1249
1477
  value: {
1250
1478
  ref: object,
1251
1479
  api,
1252
- hasCollisionEvents: false,
1253
1480
  options: props
1254
1481
  }
1255
1482
  }, /*#__PURE__*/React.createElement("object3D", {
1256
1483
  ref: object
1257
- }, props.children));
1484
+ }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1485
+ key: index
1486
+ }, colliderProps)))));
1258
1487
  });
1259
1488
 
1260
- const _excluded = ["children"];
1261
-
1262
- const AnyCollider = _ref => {
1263
- let {
1264
- children
1265
- } = _ref,
1266
- props = _objectWithoutProperties(_ref, _excluded);
1267
-
1268
- const {
1269
- world
1270
- } = useRapier();
1271
- const rigidBodyContext = useRigidBodyContext();
1272
- const ref = useRef(null);
1273
- useEffect(() => {
1274
- const scale = ref.current.getWorldScale(new Vector3());
1275
- const colliders = []; // If this is an InstancedRigidBody api
1276
-
1277
- if (rigidBodyContext && "at" in rigidBodyContext.api) {
1278
- rigidBodyContext.api.forEach((body, index) => {
1279
- var _rigidBodyContext$opt, _rigidBodyContext$opt2;
1280
-
1281
- let instanceScale = scale.clone();
1282
-
1283
- 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]) {
1284
- instanceScale.multiply(vectorArrayToVector3(rigidBodyContext.options.scales[index]));
1285
- }
1286
-
1287
- colliders.push(createColliderFromOptions({
1288
- options: props,
1289
- world,
1290
- rigidBody: body.raw(),
1291
- scale: instanceScale,
1292
- hasCollisionEvents: rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.hasCollisionEvents
1293
- }));
1294
- });
1295
- } else {
1296
- colliders.push(createColliderFromOptions({
1297
- options: props,
1298
- world,
1299
- // Initiate with a rigidbody, or undefined, because colliders can exist without a rigid body
1300
- rigidBody: rigidBodyContext && "raw" in rigidBodyContext.api ? rigidBodyContext.api.raw() : undefined,
1301
- scale,
1302
- hasCollisionEvents: rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.hasCollisionEvents
1303
- }));
1304
- }
1305
-
1306
- return () => {
1307
- colliders.forEach(collider => world.removeCollider(collider));
1308
- };
1309
- }, []);
1310
- return /*#__PURE__*/React.createElement("object3D", {
1311
- ref: ref
1312
- }, children);
1313
- };
1489
+ /**
1490
+ * Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
1491
+ * properties of RigidBody or Collider components. The first argument represents a list of
1492
+ * groups the entity is in (expressed as numbers from 0 to 15). The second argument is a list
1493
+ * of groups that will be filtered against. When it is omitted, all groups are filtered against.
1494
+ *
1495
+ * @example
1496
+ * A RigidBody that is member of group 0 and will collide with everything from groups 0 and 1:
1497
+ *
1498
+ * ```tsx
1499
+ * <RigidBody collisionGroups={interactionGroups([0], [0, 1])} />
1500
+ * ```
1501
+ *
1502
+ * A RigidBody that is member of groups 0 and 1 and will collide with everything else:
1503
+ *
1504
+ * ```tsx
1505
+ * <RigidBody collisionGroups={interactionGroups([0, 1])} />
1506
+ * ```
1507
+ *
1508
+ * A RigidBody that is member of groups 0 and 1 and will not collide with anything:
1509
+ *
1510
+ * ```tsx
1511
+ * <RigidBody collisionGroups={interactionGroups([0, 1], [])} />
1512
+ * ```
1513
+ *
1514
+ * Please note that Rapier needs interaction filters to evaluate to true between _both_ colliding
1515
+ * entities for collision events to trigger.
1516
+ *
1517
+ * @param memberships Groups the collider is a member of. (Values can range from 0 to 15.)
1518
+ * @param filters Groups the interaction group should filter against. (Values can range from 0 to 15.)
1519
+ * @returns An InteractionGroup bitmask.
1520
+ */
1521
+ const interactionGroups = (memberships, filters) => (bitmask(memberships) << 16) + (filters !== undefined ? bitmask(filters) : 0b1111111111111111);
1314
1522
 
1315
- const CuboidCollider = props => {
1316
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1317
- shape: "cuboid"
1318
- }));
1319
- };
1320
- const RoundCuboidCollider = props => {
1321
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1322
- shape: "roundCuboid"
1323
- }));
1324
- };
1325
- const BallCollider = props => {
1326
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1327
- shape: "ball"
1328
- }));
1329
- };
1330
- const CapsuleCollider = props => {
1331
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1332
- shape: "capsule"
1333
- }));
1334
- };
1335
- const HeightfieldCollider = props => {
1336
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1337
- shape: "heightfield"
1338
- }));
1339
- };
1340
- const TrimeshCollider = props => {
1341
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1342
- shape: "trimesh"
1343
- }));
1344
- };
1345
- const ConeCollider = props => {
1346
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1347
- shape: "cone"
1348
- }));
1349
- };
1350
- const CylinderCollider = props => {
1351
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1352
- shape: "cylinder"
1353
- }));
1354
- };
1355
- const ConvexHullCollider = props => {
1356
- return /*#__PURE__*/React.createElement(AnyCollider, _extends({}, props, {
1357
- shape: "convexHull"
1358
- }));
1359
- };
1523
+ const bitmask = groups => [groups].flat().reduce((acc, layer) => acc | 1 << layer, 0);
1360
1524
 
1361
- export { BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, Debug, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundCuboidCollider, TrimeshCollider, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useRigidBody, useSphericalJoint };
1525
+ export { AnyCollider, BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, Debug, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundCuboidCollider, TrimeshCollider, interactionGroups, useChildColliderProps, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useRigidBody, useSphericalJoint };