@react-three/rapier 0.1.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.
@@ -0,0 +1,914 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var useAsset = require('use-asset');
7
+ var fiber = require('@react-three/fiber');
8
+ var rapier3dCompat = require('@dimforge/rapier3d-compat');
9
+ var three = require('three');
10
+
11
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
12
+
13
+ function _interopNamespace(e) {
14
+ if (e && e.__esModule) return e;
15
+ var n = Object.create(null);
16
+ if (e) {
17
+ Object.keys(e).forEach(function (k) {
18
+ if (k !== 'default') {
19
+ var d = Object.getOwnPropertyDescriptor(e, k);
20
+ Object.defineProperty(n, k, d.get ? d : {
21
+ enumerable: true,
22
+ get: function () { return e[k]; }
23
+ });
24
+ }
25
+ });
26
+ }
27
+ n["default"] = e;
28
+ return Object.freeze(n);
29
+ }
30
+
31
+ var React__default = /*#__PURE__*/_interopDefault(React);
32
+
33
+ const vectorArrayToObject = arr => {
34
+ const [x, y, z] = arr;
35
+ return {
36
+ x,
37
+ y,
38
+ z
39
+ };
40
+ };
41
+ const rigidBodyTypeMap = {
42
+ fixed: 1,
43
+ dynamic: 0,
44
+ kinematicPosition: 2,
45
+ kinematicVelocity: 3
46
+ };
47
+ const rigidBodyTypeFromString = type => rigidBodyTypeMap[type];
48
+ const scaleColliderArgs = (shape, args, scale) => {
49
+ // Heightfield only scales the last arg
50
+ const newArgs = args.slice();
51
+
52
+ if (shape === "heightfield") {
53
+ newArgs[3] *= scale.x;
54
+ return newArgs;
55
+ } // Trimesh and convex scale the vertices
56
+
57
+
58
+ if (shape === "trimesh" || shape === "convexHull") {
59
+ newArgs[0] = scaleVertices(newArgs[0], scale);
60
+ return newArgs;
61
+ }
62
+
63
+ const scaleArray = [scale.x, scale.y, scale.z];
64
+ return newArgs.map((arg, index) => scaleArray[index] * arg);
65
+ };
66
+ const createColliderFromOptions = (options, world, body, scale = {
67
+ x: 1,
68
+ y: 1,
69
+ z: 1
70
+ }) => {
71
+ var _options$shape, _options$args, _options$restitution, _options$restitutionC, _options$friction, _options$frictionComb;
72
+
73
+ const mass = (options === null || options === void 0 ? void 0 : options.mass) || 1;
74
+ const colliderShape = (_options$shape = options === null || options === void 0 ? void 0 : options.shape) !== null && _options$shape !== void 0 ? _options$shape : "cuboid";
75
+ const colliderArgs = (_options$args = options === null || options === void 0 ? void 0 : options.args) !== null && _options$args !== void 0 ? _options$args : [];
76
+ const [cmx, cmy, cmz] = (options === null || options === void 0 ? void 0 : options.centerOfMass) || [0, 0, 0];
77
+ const [pix, piy, piz] = (options === null || options === void 0 ? void 0 : options.principalAngularInertia) || [mass * 0.2, mass * 0.2, mass * 0.2];
78
+ const [x, y, z] = (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
79
+ const [rx, ry, rz] = (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0]; // @ts-ignore
80
+
81
+ const scaledArgs = scaleColliderArgs(options.shape, colliderArgs, scale);
82
+ let colliderDesc = rapier3dCompat.ColliderDesc[colliderShape]( // @ts-ignore
83
+ ...scaledArgs).setTranslation(x * scale.x, y * scale.y, z * scale.z).setRotation({
84
+ x: rx,
85
+ y: ry,
86
+ z: rz,
87
+ w: 1
88
+ }).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 : rapier3dCompat.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 : rapier3dCompat.CoefficientCombineRule.Average); // If any of the mass properties are specified, add mass properties
89
+
90
+ if (options !== null && options !== void 0 && options.mass || options !== null && options !== void 0 && options.centerOfMass || options !== null && options !== void 0 && options.principalAngularInertia) {
91
+ colliderDesc.setDensity(0);
92
+ colliderDesc.setMassProperties(mass, {
93
+ x: cmx,
94
+ y: cmy,
95
+ z: cmz
96
+ }, {
97
+ x: pix,
98
+ y: piy,
99
+ z: piz
100
+ }, {
101
+ x: 0,
102
+ y: 0,
103
+ z: 0,
104
+ w: 1
105
+ });
106
+ }
107
+
108
+ const collider = world.createCollider(colliderDesc, body.handle);
109
+ return collider;
110
+ };
111
+ const createCollidersFromChildren = (object, rigidBody, type, world) => {
112
+ const colliders = [];
113
+ let desc;
114
+ object.traverse(child => {
115
+ if ("isMesh" in child) {
116
+ const {
117
+ geometry
118
+ } = child;
119
+ const {
120
+ x,
121
+ y,
122
+ z
123
+ } = child.position;
124
+ const {
125
+ x: rx,
126
+ y: ry,
127
+ z: rz,
128
+ w: rw
129
+ } = new three.Quaternion().setFromEuler(child.rotation);
130
+ const scale = child.getWorldScale(new three.Vector3());
131
+
132
+ switch (type) {
133
+ case "cuboid":
134
+ {
135
+ geometry.computeBoundingBox();
136
+ const {
137
+ boundingBox
138
+ } = geometry;
139
+ const size = boundingBox.getSize(new three.Vector3());
140
+ desc = rapier3dCompat.ColliderDesc.cuboid(size.x / 2 * scale.x, size.y / 2 * scale.y, size.z / 2 * scale.z);
141
+ }
142
+ break;
143
+
144
+ case "ball":
145
+ {
146
+ geometry.computeBoundingSphere();
147
+ const {
148
+ boundingSphere
149
+ } = geometry;
150
+ const radius = boundingSphere.radius * scale.x;
151
+ desc = rapier3dCompat.ColliderDesc.ball(radius);
152
+ }
153
+ break;
154
+
155
+ case "trimesh":
156
+ {
157
+ var _g$index;
158
+
159
+ const _g = geometry.clone().scale(scale.x, scale.y, scale.z);
160
+
161
+ desc = rapier3dCompat.ColliderDesc.trimesh(_g.attributes.position.array, (_g$index = _g.index) === null || _g$index === void 0 ? void 0 : _g$index.array);
162
+ }
163
+ break;
164
+
165
+ case "hull":
166
+ const g = geometry.clone().scale(scale.x, scale.y, scale.z);
167
+ {
168
+ desc = rapier3dCompat.ColliderDesc.convexHull(g.attributes.position.array);
169
+ }
170
+ break;
171
+ } // We translate the colliders based on the parent's world scale
172
+
173
+
174
+ const parentWorldScale = child.parent.getWorldScale(new three.Vector3());
175
+ desc.setTranslation(x * parentWorldScale.x, y * parentWorldScale.y, z * parentWorldScale.z).setRotation({
176
+ x: rx,
177
+ y: ry,
178
+ z: rz,
179
+ w: rw
180
+ });
181
+ const collider = world.createCollider(desc, rigidBody.handle);
182
+ colliders.push(collider);
183
+ }
184
+ });
185
+ return colliders;
186
+ };
187
+ const scaleVertices = (vertices, scale) => {
188
+ const scaledVerts = Array.from(vertices);
189
+
190
+ for (let i = 0; i < vertices.length / 3; i++) {
191
+ scaledVerts[i * 3] *= scale.x;
192
+ scaledVerts[i * 3 + 1] *= scale.y;
193
+ scaledVerts[i * 3 + 2] *= scale.z;
194
+ }
195
+
196
+ return scaledVerts;
197
+ };
198
+
199
+ const RapierContext = /*#__PURE__*/React.createContext(undefined);
200
+
201
+ const importRapier = async () => {
202
+ let r = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('@dimforge/rapier3d-compat')); });
203
+ await r.init();
204
+ return r;
205
+ };
206
+
207
+ const Physics = ({
208
+ colliders: _colliders = 'cuboid',
209
+ gravity: _gravity = [0, -9.81, 0],
210
+ children
211
+ }) => {
212
+ const rapier = useAsset.useAsset(importRapier);
213
+ const stepFuncs = React.useRef([]);
214
+ const world = React.useMemo(() => {
215
+ if (!rapier.World) return null;
216
+ let world = new rapier.World(vectorArrayToObject(_gravity));
217
+ return world;
218
+ }, [rapier]);
219
+ const time = React.useRef(performance.now());
220
+ fiber.useFrame(context => {
221
+ // Set timestep to current delta, to allow for variable frame rates
222
+ // We cap the delta at 100, so that the physics simulation doesn't get wild
223
+ const now = performance.now();
224
+ const delta = Math.min(100, now - time.current);
225
+ world.timestep = delta / 1000;
226
+ world.step(); // Run all step funcs
227
+
228
+ stepFuncs.current.forEach(func => func());
229
+ time.current = now;
230
+ });
231
+ const context = React.useMemo(() => ({
232
+ RAPIER: rapier,
233
+ world,
234
+ colliders: _colliders,
235
+ stepFuncs: stepFuncs.current
236
+ }), [rapier]);
237
+ return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
238
+ value: context
239
+ }, children);
240
+ };
241
+
242
+ function _defineProperty(obj, key, value) {
243
+ if (key in obj) {
244
+ Object.defineProperty(obj, key, {
245
+ value: value,
246
+ enumerable: true,
247
+ configurable: true,
248
+ writable: true
249
+ });
250
+ } else {
251
+ obj[key] = value;
252
+ }
253
+
254
+ return obj;
255
+ }
256
+
257
+ function ownKeys(object, enumerableOnly) {
258
+ var keys = Object.keys(object);
259
+
260
+ if (Object.getOwnPropertySymbols) {
261
+ var symbols = Object.getOwnPropertySymbols(object);
262
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
263
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
264
+ })), keys.push.apply(keys, symbols);
265
+ }
266
+
267
+ return keys;
268
+ }
269
+
270
+ function _objectSpread2(target) {
271
+ for (var i = 1; i < arguments.length; i++) {
272
+ var source = null != arguments[i] ? arguments[i] : {};
273
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
274
+ _defineProperty(target, key, source[key]);
275
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
276
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
277
+ });
278
+ }
279
+
280
+ return target;
281
+ }
282
+
283
+ const useRapier = () => {
284
+ return React.useContext(RapierContext);
285
+ }; // Private hook for updating the simulations on objects
286
+
287
+ const useRapierStep = callback => {
288
+ const {
289
+ stepFuncs
290
+ } = useRapier();
291
+ React.useEffect(() => {
292
+ stepFuncs.push(callback);
293
+ return () => {
294
+ const index = stepFuncs.indexOf(callback);
295
+ stepFuncs.splice(index, 1);
296
+ };
297
+ }, [callback]);
298
+ };
299
+ const useCollider = (body, options = {}) => {
300
+ const {
301
+ RAPIER,
302
+ world
303
+ } = useRapier();
304
+ const collider = React.useMemo(() => {
305
+ return createColliderFromOptions(options, world, body);
306
+ }, []);
307
+ React.useEffect(() => {
308
+ return () => {
309
+ world.removeCollider(collider, false);
310
+ };
311
+ }, []);
312
+ return [collider];
313
+ };
314
+ const useRigidBody = options => {
315
+ const {
316
+ RAPIER,
317
+ world
318
+ } = useRapier();
319
+ const ref = React.useRef(); // Create rigidbody
320
+
321
+ const rigidBody = React.useMemo(() => {
322
+ var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
323
+
324
+ 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];
325
+ 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];
326
+ const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
327
+ const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
328
+ const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
329
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
330
+ (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
331
+ (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
332
+ const rigidBodyDesc = new RAPIER.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
333
+ x: avx,
334
+ y: avy,
335
+ z: avz
336
+ }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).setTranslation(0, 0, 0);
337
+ const body = world.createRigidBody(rigidBodyDesc);
338
+ return body;
339
+ }, []); // Setup
340
+
341
+ React.useEffect(() => {
342
+ var _ref$current$parent, _options$colliders;
343
+
344
+ if (!ref.current) {
345
+ ref.current = new three.Object3D();
346
+ } // Get intitial world transforms
347
+
348
+
349
+ const worldPosition = ref.current.getWorldPosition(new three.Vector3());
350
+ const worldRotation = ref.current.getWorldQuaternion(new three.Quaternion());
351
+ const scale = ((_ref$current$parent = ref.current.parent) === null || _ref$current$parent === void 0 ? void 0 : _ref$current$parent.getWorldScale(new three.Vector3())) || {
352
+ x: 1,
353
+ y: 1,
354
+ z: 1
355
+ }; // Transforms from options
356
+
357
+ const [x, y, z] = (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
358
+ const [rx, ry, rz] = (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0]; // Set initial transforms based on world transforms
359
+
360
+ rigidBody.setTranslation({
361
+ x: worldPosition.x + x * scale.x,
362
+ y: worldPosition.y + y * scale.y,
363
+ z: worldPosition.z + z * scale.z
364
+ }, false);
365
+ const eulerAngles = new three.Euler(rx, ry, rz, 'XYZ');
366
+ const rotation = new three.Quaternion().setFromEuler(eulerAngles).multiply(worldRotation);
367
+ rigidBody.setRotation({
368
+ x: rotation.x,
369
+ y: rotation.y,
370
+ z: rotation.z,
371
+ w: rotation.w
372
+ }, false);
373
+ rigidBody.resetForces(false);
374
+ rigidBody.resetTorques(false);
375
+ const colliderSetting = (_options$colliders = options === null || options === void 0 ? void 0 : options.colliders) !== null && _options$colliders !== void 0 ? _options$colliders : false;
376
+ const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world) : [];
377
+ return () => {
378
+ world.removeRigidBody(rigidBody);
379
+ autoColliders.forEach(collider => world.removeCollider(collider, false));
380
+ };
381
+ }, []);
382
+ useRapierStep(() => {
383
+ if (rigidBody && ref.current) {
384
+ const {
385
+ x,
386
+ y,
387
+ z
388
+ } = rigidBody.translation();
389
+ const {
390
+ x: rx,
391
+ y: ry,
392
+ z: rz,
393
+ w: rw
394
+ } = rigidBody.rotation();
395
+ const scale = ref.current.getWorldScale(new three.Vector3());
396
+
397
+ if (ref.current.parent) {
398
+ // haha matrixes I have no idea what I'm doing :)
399
+ const o = new three.Object3D();
400
+ o.position.set(x, y, z);
401
+ o.rotation.setFromQuaternion(new three.Quaternion(rx, ry, rz, rw));
402
+ o.scale.set(scale.x, scale.y, scale.z);
403
+ o.updateMatrix();
404
+ o.applyMatrix4(ref.current.parent.matrixWorld.clone().invert());
405
+ o.updateMatrix();
406
+ ref.current.position.setFromMatrixPosition(o.matrix);
407
+ ref.current.rotation.setFromRotationMatrix(o.matrix);
408
+ }
409
+ }
410
+ });
411
+ return [ref, rigidBody];
412
+ };
413
+ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
414
+ const {
415
+ world
416
+ } = useRapier();
417
+ const [ref, rigidBody] = useRigidBody(rigidBodyOptions);
418
+ React.useEffect(() => {
419
+ if (!colliderOptions) {
420
+ return;
421
+ }
422
+
423
+ const scale = ref.current.getWorldScale(new three.Vector3());
424
+ const collider = createColliderFromOptions(colliderOptions, world, rigidBody, scale);
425
+ return () => {
426
+ world.removeCollider(collider, false);
427
+ };
428
+ }, []);
429
+ return [ref, rigidBody];
430
+ };
431
+ const useCuboid = (rigidBodyOptions = {}, colliderOptions = {}) => {
432
+ var _colliderOptions$args;
433
+
434
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
435
+ shape: "cuboid",
436
+ args: (_colliderOptions$args = colliderOptions.args) !== null && _colliderOptions$args !== void 0 ? _colliderOptions$args : [0.5, 0.5, 0.5]
437
+ }, colliderOptions));
438
+ };
439
+ const useBall = (rigidBodyOptions = {}, colliderOptions = {}) => {
440
+ var _colliderOptions$args2;
441
+
442
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
443
+ shape: "ball",
444
+ args: (_colliderOptions$args2 = colliderOptions.args) !== null && _colliderOptions$args2 !== void 0 ? _colliderOptions$args2 : [0.5]
445
+ }, colliderOptions));
446
+ };
447
+ const useCapsule = (rigidBodyOptions = {}, colliderOptions = {}) => {
448
+ var _colliderOptions$args3;
449
+
450
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
451
+ shape: "capsule",
452
+ args: (_colliderOptions$args3 = colliderOptions.args) !== null && _colliderOptions$args3 !== void 0 ? _colliderOptions$args3 : [0.5, 0.5]
453
+ }, colliderOptions));
454
+ };
455
+ const useHeightfield = (rigidBodyOptions = {}, colliderOptions = {}) => {
456
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
457
+ shape: "heightfield"
458
+ }, colliderOptions));
459
+ };
460
+ /**
461
+ * Create a trimesh collider and rigid body.
462
+ * Note that Trimeshes don't have mass unless provided.
463
+ * See https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
464
+ * for available properties.
465
+ */
466
+
467
+ const useTrimesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
468
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
469
+ shape: "trimesh"
470
+ }, colliderOptions));
471
+ };
472
+
473
+ useTrimesh.fromMesh = (mesh, rigidBodyOptions = {}, colliderOptions = {}) => {
474
+ var _mesh$geometry, _mesh$geometry$index;
475
+
476
+ return useTrimesh(rigidBodyOptions, _objectSpread2({
477
+ args: [mesh.geometry.attributes.position.array, ((_mesh$geometry = mesh.geometry) === null || _mesh$geometry === void 0 ? void 0 : (_mesh$geometry$index = _mesh$geometry.index) === null || _mesh$geometry$index === void 0 ? void 0 : _mesh$geometry$index.array) || []]
478
+ }, colliderOptions));
479
+ };
480
+
481
+ const usePolyline = (rigidBodyOptions = {}, colliderOptions = {}) => {
482
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
483
+ shape: "polyline"
484
+ }, colliderOptions));
485
+ };
486
+ const useRoundCuboid = (rigidBodyOptions = {}, colliderOptions = {}) => {
487
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
488
+ shape: "roundCuboid"
489
+ }, colliderOptions));
490
+ };
491
+ const useCylinder = (rigidBodyOptions = {}, colliderOptions = {}) => {
492
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
493
+ shape: "cylinder"
494
+ }, colliderOptions));
495
+ };
496
+ const useRoundCylinder = (rigidBodyOptions = {}, colliderOptions = {}) => {
497
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
498
+ shape: "roundCylinder"
499
+ }, colliderOptions));
500
+ };
501
+ const useCone = (rigidBodyOptions = {}, colliderOptions = {}) => {
502
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
503
+ shape: "cone"
504
+ }, colliderOptions));
505
+ };
506
+ const useRoundCone = (rigidBodyOptions = {}, colliderOptions = {}) => {
507
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
508
+ shape: "roundCone"
509
+ }, colliderOptions));
510
+ };
511
+ const useConvexHull = (rigidBodyOptions = {}, colliderOptions = {}) => {
512
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
513
+ shape: "convexHull"
514
+ }, colliderOptions));
515
+ };
516
+
517
+ useConvexHull.fromMesh = (mesh, rigidBodyOptions = {}, colliderOptions = {}) => {
518
+ var _mesh$geometry2, _mesh$geometry2$attri, _mesh$geometry2$attri2;
519
+
520
+ return useConvexHull(rigidBodyOptions, _objectSpread2({
521
+ args: [(mesh === null || mesh === void 0 ? void 0 : (_mesh$geometry2 = mesh.geometry) === null || _mesh$geometry2 === void 0 ? void 0 : (_mesh$geometry2$attri = _mesh$geometry2.attributes) === null || _mesh$geometry2$attri === void 0 ? void 0 : (_mesh$geometry2$attri2 = _mesh$geometry2$attri.position) === null || _mesh$geometry2$attri2 === void 0 ? void 0 : _mesh$geometry2$attri2.array) || []]
522
+ }, colliderOptions));
523
+ };
524
+
525
+ const useRoundConvexHull = (rigidBodyOptions = {}, colliderOptions = {}) => {
526
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
527
+ shape: "roundConvexHull"
528
+ }, colliderOptions));
529
+ };
530
+ const useConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
531
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
532
+ shape: "convexMesh"
533
+ }, colliderOptions));
534
+ };
535
+
536
+ useConvexMesh.fromMesh = (mesh, rigidBodyOptions = {}, colliderOptions = {}) => {
537
+ var _mesh$geometry3, _mesh$geometry3$attri, _mesh$geometry3$attri2, _mesh$geometry4, _mesh$geometry4$index;
538
+
539
+ return useConvexMesh(rigidBodyOptions, _objectSpread2({
540
+ args: [mesh === null || mesh === void 0 ? void 0 : (_mesh$geometry3 = mesh.geometry) === null || _mesh$geometry3 === void 0 ? void 0 : (_mesh$geometry3$attri = _mesh$geometry3.attributes) === null || _mesh$geometry3$attri === void 0 ? void 0 : (_mesh$geometry3$attri2 = _mesh$geometry3$attri.position) === null || _mesh$geometry3$attri2 === void 0 ? void 0 : _mesh$geometry3$attri2.array, ((_mesh$geometry4 = mesh.geometry) === null || _mesh$geometry4 === void 0 ? void 0 : (_mesh$geometry4$index = _mesh$geometry4.index) === null || _mesh$geometry4$index === void 0 ? void 0 : _mesh$geometry4$index.array) || []]
541
+ }, colliderOptions));
542
+ };
543
+
544
+ const useRoundConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
545
+ return useRigidBodyWithCollider(rigidBodyOptions, _objectSpread2({
546
+ shape: "convexMesh"
547
+ }, colliderOptions));
548
+ }; // Joints
549
+
550
+ const useImpulseJoint = (body1, body2, params) => {
551
+ const {
552
+ world,
553
+ RAPIER
554
+ } = useRapier();
555
+ React.useLayoutEffect(() => {
556
+ let joint;
557
+
558
+ if (body1 && body2 && params) {
559
+ joint = world.createImpulseJoint(params, body1.current, body2.current);
560
+ }
561
+
562
+ return () => {
563
+ if (joint) world.removeImpulseJoint(joint, true);
564
+ };
565
+ }, [body1, body2]);
566
+ };
567
+ /**
568
+ *
569
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
570
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
571
+ * The fixed-joint makes these frames coincide in world-space.
572
+ */
573
+
574
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
575
+ const {
576
+ RAPIER
577
+ } = useRapier();
578
+ return useImpulseJoint(body1, body2, RAPIER.JointData.fixed(vectorArrayToObject(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body1LocalFrame)), {}, {
579
+ w: 1
580
+ }), vectorArrayToObject(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body2LocalFrame)), {}, {
581
+ w: 1
582
+ })));
583
+ };
584
+ /**
585
+ * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
586
+ * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
587
+ * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
588
+ * points that need to coincide on the local-space of each rigid-body.
589
+ */
590
+
591
+ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
592
+ const {
593
+ RAPIER
594
+ } = useRapier();
595
+ return useImpulseJoint(body1, body2, RAPIER.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
596
+ };
597
+ /**
598
+ * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
599
+ * rotations along one axis. This is typically used to simulate wheels, fans, etc.
600
+ * They are characterized by one local anchor as well as one local axis on each rigid-body.
601
+ */
602
+
603
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
604
+ const {
605
+ RAPIER
606
+ } = useRapier();
607
+ return useImpulseJoint(body1, body2, RAPIER.JointData.revolute(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
608
+ };
609
+ /**
610
+ * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
611
+ * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
612
+ * local tangent axis can be specified for each rigid-body.
613
+ */
614
+
615
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
616
+ const {
617
+ RAPIER
618
+ } = useRapier();
619
+ return useImpulseJoint(body1, body2, RAPIER.JointData.prismatic(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
620
+ };
621
+
622
+ function _extends() {
623
+ _extends = Object.assign || function (target) {
624
+ for (var i = 1; i < arguments.length; i++) {
625
+ var source = arguments[i];
626
+
627
+ for (var key in source) {
628
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
629
+ target[key] = source[key];
630
+ }
631
+ }
632
+ }
633
+
634
+ return target;
635
+ };
636
+
637
+ return _extends.apply(this, arguments);
638
+ }
639
+
640
+ function _objectWithoutPropertiesLoose(source, excluded) {
641
+ if (source == null) return {};
642
+ var target = {};
643
+ var sourceKeys = Object.keys(source);
644
+ var key, i;
645
+
646
+ for (i = 0; i < sourceKeys.length; i++) {
647
+ key = sourceKeys[i];
648
+ if (excluded.indexOf(key) >= 0) continue;
649
+ target[key] = source[key];
650
+ }
651
+
652
+ return target;
653
+ }
654
+
655
+ function _objectWithoutProperties(source, excluded) {
656
+ if (source == null) return {};
657
+ var target = _objectWithoutPropertiesLoose(source, excluded);
658
+ var key, i;
659
+
660
+ if (Object.getOwnPropertySymbols) {
661
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
662
+
663
+ for (i = 0; i < sourceSymbolKeys.length; i++) {
664
+ key = sourceSymbolKeys[i];
665
+ if (excluded.indexOf(key) >= 0) continue;
666
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
667
+ target[key] = source[key];
668
+ }
669
+ }
670
+
671
+ return target;
672
+ }
673
+
674
+ const _excluded = ["children"];
675
+ const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
676
+
677
+ const useParentRigidBody = () => React.useContext(RigidBodyContext); // RigidBody
678
+
679
+
680
+ const RigidBody = /*#__PURE__*/React.forwardRef((_ref, ref) => {
681
+ let {
682
+ children
683
+ } = _ref,
684
+ props = _objectWithoutProperties(_ref, _excluded);
685
+
686
+ const [group, rigidBody] = useRigidBody(props);
687
+ React.useImperativeHandle(ref, () => rigidBody);
688
+ return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
689
+ value: [group, rigidBody]
690
+ }, /*#__PURE__*/React__default["default"].createElement("group", {
691
+ ref: group
692
+ }, children));
693
+ }); // Colliders
694
+
695
+ const AnyCollider = props => {
696
+ const {
697
+ world
698
+ } = useRapier();
699
+ const [object, rigidBody] = useParentRigidBody();
700
+ React.useEffect(() => {
701
+ const scale = object.current.getWorldScale(new three.Vector3());
702
+ const collider = createColliderFromOptions(props, world, rigidBody, scale);
703
+ return () => {
704
+ world.removeCollider(collider, false);
705
+ };
706
+ }, []);
707
+ return null;
708
+ };
709
+
710
+ const CuboidCollider = props => {
711
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
712
+ shape: "cuboid"
713
+ }));
714
+ };
715
+ const RoundCuboidCollider = props => {
716
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
717
+ shape: "roundCuboid"
718
+ }));
719
+ };
720
+ const BallCollider = props => {
721
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
722
+ shape: "ball"
723
+ }));
724
+ };
725
+ const CapsuleCollider = props => {
726
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
727
+ shape: "capsule"
728
+ }));
729
+ };
730
+ const HeightfieldCollider = props => {
731
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
732
+ shape: "heightfield"
733
+ }));
734
+ };
735
+ const TrimeshCollider = props => {
736
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
737
+ shape: "trimesh"
738
+ }));
739
+ };
740
+ const ConeCollider = props => {
741
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
742
+ shape: "cone"
743
+ }));
744
+ };
745
+ const CylinderCollider = props => {
746
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
747
+ shape: "cylinder"
748
+ }));
749
+ };
750
+ const ConvexHullCollider = props => {
751
+ return /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({}, props, {
752
+ shape: "convexHull"
753
+ }));
754
+ };
755
+
756
+ const geometryFromCollider = collider => {
757
+ switch (collider.shapeType()) {
758
+ case rapier3dCompat.ShapeType.Cuboid:
759
+ {
760
+ const {
761
+ x,
762
+ y,
763
+ z
764
+ } = collider.halfExtents();
765
+ return new three.BoxBufferGeometry(x * 2 + 0.01, y * 2 + 0.01, z * 2 + 0.01);
766
+ }
767
+
768
+ case rapier3dCompat.ShapeType.Ball:
769
+ {
770
+ const r = collider.radius();
771
+ return new three.SphereBufferGeometry(r + +0.01, 8, 8);
772
+ }
773
+
774
+ case rapier3dCompat.ShapeType.TriMesh:
775
+ {
776
+ var _g$index;
777
+
778
+ const v = collider.vertices();
779
+ const i = collider.indices();
780
+ const g = new three.BufferGeometry();
781
+ g.setAttribute("position", new three.BufferAttribute(v, 3));
782
+ (_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.set(i);
783
+ g.setDrawRange(0, g.attributes.position.array.length / 3 - 1);
784
+ return g;
785
+ }
786
+
787
+ case rapier3dCompat.ShapeType.ConvexPolyhedron:
788
+ {
789
+ const cv = collider.vertices();
790
+ const cg = new three.BufferGeometry();
791
+ cg.setAttribute("position", new three.BufferAttribute(cv, 3));
792
+ return cg;
793
+ }
794
+
795
+ case rapier3dCompat.ShapeType.Cylinder:
796
+ {
797
+ const r = collider.radius();
798
+ const h = collider.halfHeight();
799
+ const g = new three.CylinderBufferGeometry(r, r, h);
800
+ return g;
801
+ }
802
+ }
803
+
804
+ return new three.BoxBufferGeometry(1, 1, 1);
805
+ };
806
+
807
+ const DebugShape = /*#__PURE__*/React.memo(({
808
+ colliderHandle
809
+ }) => {
810
+ const {
811
+ world
812
+ } = useRapier();
813
+ const ref = React.useRef(null);
814
+ fiber.useFrame(() => {
815
+ const collider = world.getCollider(colliderHandle);
816
+
817
+ if (ref.current && collider) {
818
+ const {
819
+ x: rx,
820
+ y: ry,
821
+ z: rz,
822
+ w: rw
823
+ } = collider.rotation();
824
+ const {
825
+ x,
826
+ y,
827
+ z
828
+ } = collider.translation();
829
+ ref.current.position.set(x, y, z);
830
+ ref.current.rotation.setFromQuaternion(new three.Quaternion(rx, ry, rz, rw));
831
+ }
832
+ });
833
+ const geometry = React.useMemo(() => {
834
+ const collider = world.getCollider(colliderHandle);
835
+ return geometryFromCollider(collider);
836
+ }, [colliderHandle]);
837
+ return /*#__PURE__*/React__default["default"].createElement("mesh", {
838
+ ref: ref
839
+ }, /*#__PURE__*/React__default["default"].createElement("primitive", {
840
+ object: geometry,
841
+ attach: "geometry"
842
+ }), /*#__PURE__*/React__default["default"].createElement("meshBasicMaterial", {
843
+ color: "red",
844
+ wireframe: true
845
+ }));
846
+ });
847
+ const Debug = () => {
848
+ const {
849
+ world
850
+ } = useRapier();
851
+ const [colliders, setColliders] = React.useState([]);
852
+ React.useRef({});
853
+
854
+ fiber.useFrame(() => {
855
+ const newColliders = [];
856
+ world.colliders.forEachCollider(collider => {
857
+ newColliders.push(collider.handle);
858
+ });
859
+ setColliders(newColliders);
860
+ });
861
+ return /*#__PURE__*/React__default["default"].createElement("group", null, colliders.map(handle => /*#__PURE__*/React__default["default"].createElement(DebugShape, {
862
+ key: handle,
863
+ colliderHandle: handle
864
+ })));
865
+ };
866
+
867
+ Object.defineProperty(exports, 'CoefficientCombineRule', {
868
+ enumerable: true,
869
+ get: function () { return rapier3dCompat.CoefficientCombineRule; }
870
+ });
871
+ Object.defineProperty(exports, 'RapierCollider', {
872
+ enumerable: true,
873
+ get: function () { return rapier3dCompat.Collider; }
874
+ });
875
+ Object.defineProperty(exports, 'RapierRigidBody', {
876
+ enumerable: true,
877
+ get: function () { return rapier3dCompat.RigidBody; }
878
+ });
879
+ exports.BallCollider = BallCollider;
880
+ exports.CapsuleCollider = CapsuleCollider;
881
+ exports.ConeCollider = ConeCollider;
882
+ exports.ConvexHullCollider = ConvexHullCollider;
883
+ exports.CuboidCollider = CuboidCollider;
884
+ exports.CylinderCollider = CylinderCollider;
885
+ exports.Debug = Debug;
886
+ exports.HeightfieldCollider = HeightfieldCollider;
887
+ exports.Physics = Physics;
888
+ exports.RigidBody = RigidBody;
889
+ exports.RoundCuboidCollider = RoundCuboidCollider;
890
+ exports.TrimeshCollider = TrimeshCollider;
891
+ exports.useBall = useBall;
892
+ exports.useCapsule = useCapsule;
893
+ exports.useCollider = useCollider;
894
+ exports.useCone = useCone;
895
+ exports.useConvexHull = useConvexHull;
896
+ exports.useConvexMesh = useConvexMesh;
897
+ exports.useCuboid = useCuboid;
898
+ exports.useCylinder = useCylinder;
899
+ exports.useFixedJoint = useFixedJoint;
900
+ exports.useHeightfield = useHeightfield;
901
+ exports.useImpulseJoint = useImpulseJoint;
902
+ exports.usePolyline = usePolyline;
903
+ exports.usePrismaticJoint = usePrismaticJoint;
904
+ exports.useRapier = useRapier;
905
+ exports.useRevoluteJoint = useRevoluteJoint;
906
+ exports.useRigidBody = useRigidBody;
907
+ exports.useRigidBodyWithCollider = useRigidBodyWithCollider;
908
+ exports.useRoundCone = useRoundCone;
909
+ exports.useRoundConvexHull = useRoundConvexHull;
910
+ exports.useRoundConvexMesh = useRoundConvexMesh;
911
+ exports.useRoundCuboid = useRoundCuboid;
912
+ exports.useRoundCylinder = useRoundCylinder;
913
+ exports.useSphericalJoint = useSphericalJoint;
914
+ exports.useTrimesh = useTrimesh;