@react-three/rapier 0.2.0 → 0.4.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.
- package/CHANGELOG.md +22 -0
- package/dist/declarations/src/Physics.d.ts +14 -1
- package/dist/declarations/src/api.d.ts +3 -1
- package/dist/declarations/src/components.d.ts +3 -2
- package/dist/declarations/src/hooks.d.ts +40 -0
- package/dist/declarations/src/types.d.ts +17 -1
- package/dist/declarations/src/utils.d.ts +5 -5
- package/dist/react-three-rapier.cjs.dev.js +158 -37
- package/dist/react-three-rapier.cjs.prod.js +158 -37
- package/dist/react-three-rapier.esm.js +160 -39
- package/package.json +2 -2
- package/readme.md +176 -0
@@ -1,9 +1,9 @@
|
|
1
|
-
import React, { useRef, useState,
|
1
|
+
import React, { useRef, useState, useEffect, useMemo, createContext, useContext, forwardRef, useImperativeHandle, memo } from 'react';
|
2
2
|
import { useAsset } from 'use-asset';
|
3
3
|
import { useFrame } from '@react-three/fiber';
|
4
|
-
import {
|
5
|
-
import { ColliderDesc, CoefficientCombineRule, ShapeType } from '@dimforge/rapier3d-compat';
|
4
|
+
import { ColliderDesc, CoefficientCombineRule, ActiveEvents, EventQueue, ShapeType } from '@dimforge/rapier3d-compat';
|
6
5
|
export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
|
6
|
+
import { Vector3, Quaternion, Object3D, Euler, CylinderBufferGeometry, BufferGeometry, BufferAttribute, SphereBufferGeometry, BoxBufferGeometry } from 'three';
|
7
7
|
|
8
8
|
const vectorArrayToObject = arr => {
|
9
9
|
const [x, y, z] = arr;
|
@@ -38,11 +38,11 @@ const scaleColliderArgs = (shape, args, scale) => {
|
|
38
38
|
const scaleArray = [scale.x, scale.y, scale.z];
|
39
39
|
return newArgs.map((arg, index) => scaleArray[index] * arg);
|
40
40
|
};
|
41
|
-
const createColliderFromOptions = (options, world,
|
41
|
+
const createColliderFromOptions = (options, world, rigidBody, scale = {
|
42
42
|
x: 1,
|
43
43
|
y: 1,
|
44
44
|
z: 1
|
45
|
-
}) => {
|
45
|
+
}, hasCollisionEvents = false) => {
|
46
46
|
var _options$shape, _options$args, _options$restitution, _options$restitutionC, _options$friction, _options$frictionComb;
|
47
47
|
|
48
48
|
const mass = (options === null || options === void 0 ? void 0 : options.mass) || 1;
|
@@ -60,7 +60,12 @@ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
|
|
60
60
|
y: ry,
|
61
61
|
z: rz,
|
62
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);
|
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);
|
64
|
+
|
65
|
+
if (hasCollisionEvents) {
|
66
|
+
colliderDesc = colliderDesc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
67
|
+
} // If any of the mass properties are specified, add mass properties
|
68
|
+
|
64
69
|
|
65
70
|
if (options !== null && options !== void 0 && options.mass || options !== null && options !== void 0 && options.centerOfMass || options !== null && options !== void 0 && options.principalAngularInertia) {
|
66
71
|
colliderDesc.setDensity(0);
|
@@ -80,10 +85,10 @@ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
|
|
80
85
|
});
|
81
86
|
}
|
82
87
|
|
83
|
-
const collider = world.createCollider(colliderDesc,
|
88
|
+
const collider = world.createCollider(colliderDesc, rigidBody);
|
84
89
|
return collider;
|
85
90
|
};
|
86
|
-
const createCollidersFromChildren = (object, rigidBody, type, world) => {
|
91
|
+
const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisionEvents = false) => {
|
87
92
|
const colliders = [];
|
88
93
|
let desc;
|
89
94
|
let offset = new Vector3();
|
@@ -156,7 +161,12 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
|
|
156
161
|
z: rz,
|
157
162
|
w: rw
|
158
163
|
});
|
159
|
-
|
164
|
+
|
165
|
+
if (hasCollisionEvents) {
|
166
|
+
desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
167
|
+
}
|
168
|
+
|
169
|
+
const collider = world.createCollider(desc, rigidBody);
|
160
170
|
colliders.push(collider);
|
161
171
|
}
|
162
172
|
});
|
@@ -224,6 +234,31 @@ const createRigidBodyApi = ref => {
|
|
224
234
|
w
|
225
235
|
} = ref.current().rotation();
|
226
236
|
return new Quaternion(x, y, z, w);
|
237
|
+
},
|
238
|
+
|
239
|
+
setNextKinematicRotation({
|
240
|
+
x,
|
241
|
+
y,
|
242
|
+
z
|
243
|
+
}) {
|
244
|
+
ref.current().setNextKinematicRotation({
|
245
|
+
x,
|
246
|
+
y,
|
247
|
+
z,
|
248
|
+
w: 1
|
249
|
+
});
|
250
|
+
},
|
251
|
+
|
252
|
+
setNextKinematicTranslation({
|
253
|
+
x,
|
254
|
+
y,
|
255
|
+
z
|
256
|
+
}) {
|
257
|
+
ref.current().setNextKinematicTranslation({
|
258
|
+
x,
|
259
|
+
y,
|
260
|
+
z
|
261
|
+
});
|
227
262
|
}
|
228
263
|
|
229
264
|
};
|
@@ -245,10 +280,10 @@ const createWorldApi = ref => {
|
|
245
280
|
getCollider: handle => ref.current().getCollider(handle),
|
246
281
|
getRigidBody: handle => ref.current().getRigidBody(handle),
|
247
282
|
createRigidBody: desc => ref.current().createRigidBody(desc),
|
248
|
-
createCollider: (desc,
|
283
|
+
createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
|
249
284
|
removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
|
250
285
|
removeCollider: collider => ref.current().removeCollider(collider, true),
|
251
|
-
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
|
286
|
+
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, true),
|
252
287
|
removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
|
253
288
|
forEachCollider: callback => ref.current().forEachCollider(callback)
|
254
289
|
};
|
@@ -291,9 +326,11 @@ const Physics = ({
|
|
291
326
|
return worldRef.current;
|
292
327
|
});
|
293
328
|
const [colliderMeshes] = useState(() => new Map());
|
294
|
-
const [rigidBodyMeshes] = useState(() => new Map());
|
329
|
+
const [rigidBodyMeshes] = useState(() => new Map());
|
330
|
+
const [rigidBodyEvents] = useState(() => new Map());
|
331
|
+
const [eventQueue] = useState(() => new EventQueue(false)); // Init world
|
295
332
|
|
296
|
-
|
333
|
+
useEffect(() => {
|
297
334
|
const world = getWorldRef.current();
|
298
335
|
return () => {
|
299
336
|
if (world) {
|
@@ -311,10 +348,27 @@ const Physics = ({
|
|
311
348
|
const now = performance.now();
|
312
349
|
const delta = Math.min(100, now - time.current);
|
313
350
|
world.timestep = delta / 1000;
|
314
|
-
world.step(); // Update meshes
|
351
|
+
world.step(eventQueue); // Update meshes
|
315
352
|
|
316
353
|
rigidBodyMeshes.forEach((mesh, handle) => {
|
317
354
|
const rigidBody = world.getRigidBody(handle);
|
355
|
+
const events = rigidBodyEvents.get(handle);
|
356
|
+
|
357
|
+
if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
|
358
|
+
if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
|
359
|
+
var _events$onSleep;
|
360
|
+
|
361
|
+
events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
|
362
|
+
}
|
363
|
+
|
364
|
+
if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
|
365
|
+
var _events$onWake;
|
366
|
+
|
367
|
+
events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
|
368
|
+
}
|
369
|
+
|
370
|
+
mesh.userData.isSleeping = rigidBody.isSleeping();
|
371
|
+
}
|
318
372
|
|
319
373
|
if (!rigidBody || rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
|
320
374
|
return;
|
@@ -342,6 +396,50 @@ const Physics = ({
|
|
342
396
|
o.updateMatrix();
|
343
397
|
mesh.position.setFromMatrixPosition(o.matrix);
|
344
398
|
mesh.rotation.setFromRotationMatrix(o.matrix);
|
399
|
+
}); // Collision events
|
400
|
+
|
401
|
+
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
402
|
+
var _collider1$parent, _collider2$parent;
|
403
|
+
|
404
|
+
const collider1 = world.getCollider(handle1);
|
405
|
+
const collider2 = world.getCollider(handle2);
|
406
|
+
const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
|
407
|
+
const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle;
|
408
|
+
|
409
|
+
if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
|
410
|
+
return;
|
411
|
+
}
|
412
|
+
|
413
|
+
const rigidBody1 = world.getRigidBody(rigidBodyHandle1);
|
414
|
+
const rigidBody2 = world.getRigidBody(rigidBodyHandle2);
|
415
|
+
const events1 = rigidBodyEvents.get(rigidBodyHandle1);
|
416
|
+
const events2 = rigidBodyEvents.get(rigidBodyHandle2);
|
417
|
+
|
418
|
+
if (started) {
|
419
|
+
world.contactPair(collider1, collider2, (manifold, flipped) => {
|
420
|
+
var _events1$onCollisionE, _events2$onCollisionE;
|
421
|
+
|
422
|
+
events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
|
423
|
+
target: rigidBody2,
|
424
|
+
manifold,
|
425
|
+
flipped
|
426
|
+
});
|
427
|
+
events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE = events2.onCollisionEnter) === null || _events2$onCollisionE === void 0 ? void 0 : _events2$onCollisionE.call(events2, {
|
428
|
+
target: rigidBody1,
|
429
|
+
manifold,
|
430
|
+
flipped
|
431
|
+
});
|
432
|
+
});
|
433
|
+
} else {
|
434
|
+
var _events1$onCollisionE2, _events2$onCollisionE2;
|
435
|
+
|
436
|
+
events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE2 = events1.onCollisionExit) === null || _events1$onCollisionE2 === void 0 ? void 0 : _events1$onCollisionE2.call(events1, {
|
437
|
+
target: rigidBody2
|
438
|
+
});
|
439
|
+
events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE2 = events2.onCollisionExit) === null || _events2$onCollisionE2 === void 0 ? void 0 : _events2$onCollisionE2.call(events2, {
|
440
|
+
target: rigidBody1
|
441
|
+
});
|
442
|
+
}
|
345
443
|
});
|
346
444
|
time.current = now;
|
347
445
|
});
|
@@ -354,7 +452,8 @@ const Physics = ({
|
|
354
452
|
gravity: _gravity
|
355
453
|
},
|
356
454
|
colliderMeshes,
|
357
|
-
rigidBodyMeshes
|
455
|
+
rigidBodyMeshes,
|
456
|
+
rigidBodyEvents
|
358
457
|
}), []);
|
359
458
|
return /*#__PURE__*/React.createElement(RapierContext.Provider, {
|
360
459
|
value: context
|
@@ -410,7 +509,8 @@ const useRigidBody = (options = {}) => {
|
|
410
509
|
rapier,
|
411
510
|
world,
|
412
511
|
rigidBodyMeshes,
|
413
|
-
physicsOptions
|
512
|
+
physicsOptions,
|
513
|
+
rigidBodyEvents
|
414
514
|
} = useRapier();
|
415
515
|
const ref = useRef(); // Create rigidbody
|
416
516
|
|
@@ -431,7 +531,7 @@ const useRigidBody = (options = {}) => {
|
|
431
531
|
z: avz
|
432
532
|
}).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
|
433
533
|
const rigidBody = world.createRigidBody(desc);
|
434
|
-
rigidBodyRef.current = rigidBody;
|
534
|
+
rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
|
435
535
|
}
|
436
536
|
|
437
537
|
return rigidBodyRef.current;
|
@@ -445,8 +545,10 @@ const useRigidBody = (options = {}) => {
|
|
445
545
|
|
446
546
|
if (!ref.current) {
|
447
547
|
ref.current = new Object3D();
|
448
|
-
} //
|
548
|
+
} // isSleeping used for onSleep and onWake events
|
549
|
+
|
449
550
|
|
551
|
+
ref.current.userData.isSleeping = false; // Get intitial world transforms
|
450
552
|
|
451
553
|
const worldPosition = ref.current.getWorldPosition(new Vector3());
|
452
554
|
const worldRotation = ref.current.getWorldQuaternion(new Quaternion());
|
@@ -464,6 +566,7 @@ const useRigidBody = (options = {}) => {
|
|
464
566
|
y: worldPosition.y + y * scale.y,
|
465
567
|
z: worldPosition.z + z * scale.z
|
466
568
|
}, false);
|
569
|
+
console.log(rigidBody.isKinematic());
|
467
570
|
const eulerAngles = new Euler(rx, ry, rz, 'XYZ');
|
468
571
|
const rotation = new Quaternion().setFromEuler(eulerAngles).multiply(worldRotation);
|
469
572
|
rigidBody.setRotation({
|
@@ -475,16 +578,31 @@ const useRigidBody = (options = {}) => {
|
|
475
578
|
rigidBody.resetForces(false);
|
476
579
|
rigidBody.resetTorques(false);
|
477
580
|
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;
|
478
|
-
const
|
581
|
+
const hasCollisionEvents = !!(options.onCollisionEnter || options.onCollisionExit);
|
582
|
+
const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world, hasCollisionEvents) : [];
|
479
583
|
rigidBody.wakeUp();
|
480
584
|
rigidBodyMeshes.set(rigidBody.handle, ref.current);
|
481
585
|
return () => {
|
586
|
+
const actualBody = world.getRigidBody(rigidBody.handle);
|
587
|
+
world.removeRigidBody(actualBody);
|
482
588
|
autoColliders.forEach(collider => world.removeCollider(collider));
|
483
|
-
world.removeRigidBody(rigidBody);
|
484
589
|
rigidBodyRef.current = undefined;
|
485
590
|
rigidBodyMeshes.delete(rigidBody.handle);
|
486
591
|
};
|
487
|
-
}, []);
|
592
|
+
}, []); // Events
|
593
|
+
|
594
|
+
useEffect(() => {
|
595
|
+
const rigidBody = getRigidBodyRef.current();
|
596
|
+
rigidBodyEvents.set(rigidBody.handle, {
|
597
|
+
onCollisionEnter: options === null || options === void 0 ? void 0 : options.onCollisionEnter,
|
598
|
+
onCollisionExit: options === null || options === void 0 ? void 0 : options.onCollisionExit,
|
599
|
+
onSleep: options === null || options === void 0 ? void 0 : options.onSleep,
|
600
|
+
onWake: options === null || options === void 0 ? void 0 : options.onWake
|
601
|
+
});
|
602
|
+
return () => {
|
603
|
+
rigidBodyEvents.delete(rigidBody.handle);
|
604
|
+
};
|
605
|
+
}, [options.onCollisionEnter, options.onCollisionExit]);
|
488
606
|
const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
|
489
607
|
return [ref, api];
|
490
608
|
};
|
@@ -496,7 +614,7 @@ const useCollider = (body, options = {}) => {
|
|
496
614
|
const objectRef = useRef();
|
497
615
|
const getColliderRef = useRef(() => {
|
498
616
|
if (!colliderRef.current) {
|
499
|
-
colliderRef.current = createColliderFromOptions(options, world, body.handle);
|
617
|
+
colliderRef.current = createColliderFromOptions(options, world, world.getRigidBody(body.handle));
|
500
618
|
}
|
501
619
|
|
502
620
|
return colliderRef.current;
|
@@ -522,7 +640,7 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
|
|
522
640
|
}
|
523
641
|
|
524
642
|
const scale = ref.current.getWorldScale(new Vector3());
|
525
|
-
const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
|
643
|
+
const collider = createColliderFromOptions(colliderOptions, world, world.getRigidBody(rigidBody.handle), scale);
|
526
644
|
return () => {
|
527
645
|
world.removeCollider(collider);
|
528
646
|
};
|
@@ -678,7 +796,6 @@ const useImpulseJoint = (body1, body2, params) => {
|
|
678
796
|
const joint = getJointRef.current();
|
679
797
|
return () => {
|
680
798
|
if (joint) {
|
681
|
-
console.log('remove joint', joint);
|
682
799
|
world.removeImpulseJoint(joint);
|
683
800
|
jointRef.current = undefined;
|
684
801
|
}
|
@@ -798,7 +915,7 @@ const _excluded = ["children"],
|
|
798
915
|
_excluded2 = ["children"];
|
799
916
|
const RigidBodyContext = /*#__PURE__*/createContext(undefined);
|
800
917
|
|
801
|
-
const
|
918
|
+
const useRigidBodyContext = () => useContext(RigidBodyContext); // RigidBody
|
802
919
|
|
803
920
|
|
804
921
|
const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
|
@@ -810,7 +927,7 @@ const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
810
927
|
const [object, rigidBody] = useRigidBody(props);
|
811
928
|
useImperativeHandle(ref, () => rigidBody);
|
812
929
|
return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
|
813
|
-
value: [object, rigidBody]
|
930
|
+
value: [object, rigidBody, !!(props.onCollisionEnter || props.onCollisionExit)]
|
814
931
|
}, /*#__PURE__*/React.createElement("object3D", {
|
815
932
|
ref: object
|
816
933
|
}, children));
|
@@ -825,11 +942,11 @@ const AnyCollider = _ref2 => {
|
|
825
942
|
const {
|
826
943
|
world
|
827
944
|
} = useRapier();
|
828
|
-
const [, rigidBody] =
|
945
|
+
const [, rigidBody, hasCollisionEvents] = useRigidBodyContext();
|
829
946
|
const ref = useRef(null);
|
830
947
|
useEffect(() => {
|
831
948
|
const scale = ref.current.getWorldScale(new Vector3());
|
832
|
-
const collider = createColliderFromOptions(props, world, rigidBody.handle, scale);
|
949
|
+
const collider = createColliderFromOptions(props, world, world.getRigidBody(rigidBody.handle), scale, hasCollisionEvents);
|
833
950
|
return () => {
|
834
951
|
world.removeCollider(collider);
|
835
952
|
};
|
@@ -886,20 +1003,20 @@ const ConvexHullCollider = props => {
|
|
886
1003
|
};
|
887
1004
|
|
888
1005
|
const geometryFromCollider = collider => {
|
889
|
-
switch (collider.
|
1006
|
+
switch (collider.shape.type) {
|
890
1007
|
case ShapeType.Cuboid:
|
891
1008
|
{
|
892
1009
|
const {
|
893
1010
|
x,
|
894
1011
|
y,
|
895
1012
|
z
|
896
|
-
} = collider.halfExtents
|
1013
|
+
} = collider.shape.halfExtents;
|
897
1014
|
return new BoxBufferGeometry(x * 2 + 0.01, y * 2 + 0.01, z * 2 + 0.01);
|
898
1015
|
}
|
899
1016
|
|
900
1017
|
case ShapeType.Ball:
|
901
1018
|
{
|
902
|
-
const r = collider.radius
|
1019
|
+
const r = collider.shape.radius;
|
903
1020
|
return new SphereBufferGeometry(r + +0.01, 8, 8);
|
904
1021
|
}
|
905
1022
|
|
@@ -907,10 +1024,12 @@ const geometryFromCollider = collider => {
|
|
907
1024
|
{
|
908
1025
|
var _g$index;
|
909
1026
|
|
910
|
-
const v = collider.vertices
|
911
|
-
const i = collider.indices
|
912
|
-
const g = new BufferGeometry();
|
913
|
-
|
1027
|
+
const v = collider.shape.vertices;
|
1028
|
+
const i = collider.shape.indices;
|
1029
|
+
const g = new BufferGeometry(); // Vertices are not always a float3darray (???), so we need to convert them
|
1030
|
+
|
1031
|
+
const safeVerts = Float32Array.from(v);
|
1032
|
+
g.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
914
1033
|
(_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.set(i);
|
915
1034
|
g.setDrawRange(0, g.attributes.position.array.length / 3 - 1);
|
916
1035
|
return g;
|
@@ -918,16 +1037,18 @@ const geometryFromCollider = collider => {
|
|
918
1037
|
|
919
1038
|
case ShapeType.ConvexPolyhedron:
|
920
1039
|
{
|
921
|
-
const cv = collider.vertices()
|
1040
|
+
const cv = collider.shape.vertices; // Vertices are not always a float3darray (???), so we need to convert them
|
1041
|
+
|
1042
|
+
const safeVerts = Float32Array.from(cv);
|
922
1043
|
const cg = new BufferGeometry();
|
923
|
-
cg.setAttribute("position", new BufferAttribute(
|
1044
|
+
cg.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
924
1045
|
return cg;
|
925
1046
|
}
|
926
1047
|
|
927
1048
|
case ShapeType.Cylinder:
|
928
1049
|
{
|
929
|
-
const r = collider.radius
|
930
|
-
const h = collider.halfHeight
|
1050
|
+
const r = collider.shape.radius;
|
1051
|
+
const h = collider.shape.halfHeight;
|
931
1052
|
const g = new CylinderBufferGeometry(r, r, h);
|
932
1053
|
return g;
|
933
1054
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-three/rapier",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"source": "src/index.ts",
|
5
5
|
"main": "dist/react-three-rapier.cjs.js",
|
6
6
|
"module": "dist/react-three-rapier.esm.js",
|
@@ -23,7 +23,7 @@
|
|
23
23
|
"three": "^0.139.2"
|
24
24
|
},
|
25
25
|
"dependencies": {
|
26
|
-
"@dimforge/rapier3d-compat": "
|
26
|
+
"@dimforge/rapier3d-compat": "0.8.1",
|
27
27
|
"use-asset": "^1.0.4"
|
28
28
|
},
|
29
29
|
"repository": "https://github.com/pmndrs/react-three-rapier/tree/master/packages/react-three-rapier"
|
package/readme.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
<h1 align="center">@react-three/rapier 🗡</h1>
|
2
|
+
|
3
|
+
<p align="center">⚠️ Under heavy development. All APIs are subject to change. ⚠️</p>
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```tsx
|
8
|
+
import { Box } from "@react-three/drei";
|
9
|
+
import { Canvas } from "@react-three/fiber";
|
10
|
+
import { Physics, RigidBody } from "@react-three/rapier";
|
11
|
+
|
12
|
+
const App = () => {
|
13
|
+
return (
|
14
|
+
<Canvas>
|
15
|
+
<Physics>
|
16
|
+
<RigidBody>
|
17
|
+
<Box />
|
18
|
+
</RigidBody>
|
19
|
+
</Physics>
|
20
|
+
</Canvas>
|
21
|
+
);
|
22
|
+
};
|
23
|
+
```
|
24
|
+
|
25
|
+
## Automatic colliders
|
26
|
+
|
27
|
+
RigidBodies generate automatic colliders by default for all meshes that it contains. You can control the default collider by setting the `colliders` prop on a `<RigidBody />`, or change it globally by setting `colliders` on `<Physics />`. Setting `colliders={false}` disables auto-generation.
|
28
|
+
|
29
|
+
Supported values:
|
30
|
+
|
31
|
+
- `"cuboid"`, creates a CuboidCollider based on the bounding box of the mesh
|
32
|
+
- `"ball"`, creates a SphereCollider based on the bounding sphere of the mesh
|
33
|
+
- `"trimesh"`, creates a TrimeshCollider based on the mesh's geometry -- note trimeshes are massless by default (https://rapier.rs/docs/user_guides/javascript/common_mistakes#rigid-body-isnt-affected-by-gravity)
|
34
|
+
- `"hull"`, creates a ConvexHullCollider based on the mesh's geometry
|
35
|
+
- `false`, disables auto-generation
|
36
|
+
|
37
|
+
Generate ConvexHull colliders for all meshes in a RigidBody by default:
|
38
|
+
|
39
|
+
```tsx
|
40
|
+
const Scene = () => (
|
41
|
+
<Physics colliders="hull">
|
42
|
+
<RigidBody>
|
43
|
+
<Box />
|
44
|
+
</RigidBody>
|
45
|
+
<RigidBody position={[0, 10, 0]}>
|
46
|
+
<Sphere />
|
47
|
+
</RigidBody>
|
48
|
+
</Physics>
|
49
|
+
);
|
50
|
+
```
|
51
|
+
|
52
|
+
Turn off automatic collider generation globally, but apply auto generation locally:
|
53
|
+
|
54
|
+
```tsx
|
55
|
+
const Scene = () => (
|
56
|
+
<Physics colliders={false}>
|
57
|
+
<RigidBody colliders="cuboid">
|
58
|
+
<Box />
|
59
|
+
</RigidBody>
|
60
|
+
|
61
|
+
<RigidBody position={[0, 10, 0]} colliders="ball">
|
62
|
+
<Sphere />
|
63
|
+
</RigidBody>
|
64
|
+
|
65
|
+
<RigidBody position={[0, 10, 0]}>
|
66
|
+
<Sphere />
|
67
|
+
<BallCollider args={0.5} />
|
68
|
+
<BallCollider args={0.5} position={[1, 0, 0]} />
|
69
|
+
</RigidBody>
|
70
|
+
</Physics>
|
71
|
+
);
|
72
|
+
```
|
73
|
+
|
74
|
+
Objects work inside other transformed objects as well. Simulation runs in world space and is transformed to the objects local space, so that things act as you'd expect.
|
75
|
+
|
76
|
+
```tsx
|
77
|
+
import { Box } from "@react-three/drei";
|
78
|
+
import { RigidBody, CuboidCollider } from "@react-three/rapier";
|
79
|
+
|
80
|
+
const Scene = () => {
|
81
|
+
return (
|
82
|
+
<group position={[2, 5, 0]} rotation={[0, 0.3, 2]}>
|
83
|
+
<RigidBody>
|
84
|
+
<Box />
|
85
|
+
<CuboidCollider args={[0.5, 0.5, 0.5]} />
|
86
|
+
</RigidBody>
|
87
|
+
</group>
|
88
|
+
);
|
89
|
+
};
|
90
|
+
```
|
91
|
+
|
92
|
+
## Debug
|
93
|
+
|
94
|
+
Use the Debug component to see live representations of all colliders in a scene.
|
95
|
+
|
96
|
+
> Note: Experimental. Not all shapes are supported. Unsupported shapes are always represented by cubes.
|
97
|
+
|
98
|
+
```tsx
|
99
|
+
import { Box, Sphere } from "@react-three/drei";
|
100
|
+
import { RigidBody, Debug } from "@react-three/rapier";
|
101
|
+
|
102
|
+
const Scene = () => {
|
103
|
+
return (
|
104
|
+
<Physics>
|
105
|
+
<Debug />
|
106
|
+
|
107
|
+
<RigidBody>
|
108
|
+
<Box />
|
109
|
+
</RigidBody>
|
110
|
+
<RigidBody>
|
111
|
+
<Sphere />
|
112
|
+
</RigidBody>
|
113
|
+
</Physics>
|
114
|
+
);
|
115
|
+
};
|
116
|
+
```
|
117
|
+
|
118
|
+
## Events
|
119
|
+
|
120
|
+
You can subscribe collision and state events on the RigidBody.
|
121
|
+
|
122
|
+
```tsx
|
123
|
+
const RigidBottle = () => {
|
124
|
+
const [isAsleep, setIsAsleep] = useState(false);
|
125
|
+
|
126
|
+
return (
|
127
|
+
<RigidBody
|
128
|
+
colliders="hull"
|
129
|
+
onSleep={() => setIsAsleep(true)}
|
130
|
+
onWake={() => setIsAsleep(false)}
|
131
|
+
onCollision={({manifold}) => {
|
132
|
+
console.log('Collision at world position ', manifold.solverContactPoint(0))
|
133
|
+
}}
|
134
|
+
>
|
135
|
+
<Sphere>
|
136
|
+
<meshPhysicalMaterial color={isAsleep ? 'white' : 'blue'}>
|
137
|
+
</Sphere>
|
138
|
+
</RigidBody>
|
139
|
+
)
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
## Hooks
|
144
|
+
|
145
|
+
You can also use hooks to generate rigid bodies and colliders, but it's not encouraged.
|
146
|
+
|
147
|
+
```tsx
|
148
|
+
import { Box } from "@react-three/drei";
|
149
|
+
import { useCuboid } from "@react-three/rapier";
|
150
|
+
|
151
|
+
const RigidBox = () => {
|
152
|
+
// Generates a RigidBody and attaches a BoxCollider to it, returns a ref
|
153
|
+
const [box, rigidBody, collider] = useCuboid(
|
154
|
+
{ position: [1, 1, 1] },
|
155
|
+
{ args: [0.5, 0.5, 0.5] }
|
156
|
+
);
|
157
|
+
|
158
|
+
return <Box ref={box} />;
|
159
|
+
};
|
160
|
+
```
|
161
|
+
|
162
|
+
## Roadmap?
|
163
|
+
|
164
|
+
In order, but also not necessarily:
|
165
|
+
|
166
|
+
- [x] Draft of all base shapes
|
167
|
+
- [x] Draft of all base joints
|
168
|
+
- [x] Nested objects retain world transforms
|
169
|
+
- [x] Nested objects retain correct collider scale
|
170
|
+
- [x] Automatic colliders based on rigidbody children
|
171
|
+
- [ ] Translation and rotational constraints
|
172
|
+
- [x] Collision events
|
173
|
+
- [ ] InstancedMesh support
|
174
|
+
- [ ] Docs
|
175
|
+
- [ ] CodeSandbox examples
|
176
|
+
- [ ] Helpers, for things like Vehicle, Rope, Player, etc
|