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