@react-three/rapier 0.3.1 → 0.4.2
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/api.d.ts +114 -18
- package/dist/declarations/src/components.d.ts +1 -9
- package/dist/declarations/src/hooks.d.ts +21 -161
- package/dist/declarations/src/types.d.ts +10 -0
- package/dist/declarations/src/utils.d.ts +4 -4
- package/dist/react-three-rapier.cjs.dev.js +124 -99
- package/dist/react-three-rapier.cjs.prod.js +124 -99
- package/dist/react-three-rapier.esm.js +125 -100
- package/package.json +2 -2
- package/readme.md +182 -0
@@ -1,4 +1,4 @@
|
|
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
4
|
import { ColliderDesc, CoefficientCombineRule, ActiveEvents, EventQueue, ShapeType } from '@dimforge/rapier3d-compat';
|
@@ -38,7 +38,7 @@ 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
|
@@ -85,10 +85,11 @@ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
|
|
85
85
|
});
|
86
86
|
}
|
87
87
|
|
88
|
-
const collider = world.createCollider(colliderDesc,
|
88
|
+
const collider = world.createCollider(colliderDesc, rigidBody);
|
89
89
|
return collider;
|
90
90
|
};
|
91
|
-
const createCollidersFromChildren = (object, rigidBody,
|
91
|
+
const createCollidersFromChildren = (object, rigidBody, options, world) => {
|
92
|
+
const hasCollisionEvents = !!(options.onCollisionEnter || options.onCollisionExit);
|
92
93
|
const colliders = [];
|
93
94
|
let desc;
|
94
95
|
let offset = new Vector3();
|
@@ -110,7 +111,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisio
|
|
110
111
|
} = new Quaternion().setFromEuler(child.rotation);
|
111
112
|
const scale = child.getWorldScale(new Vector3());
|
112
113
|
|
113
|
-
switch (
|
114
|
+
switch (options.colliders) {
|
114
115
|
case "cuboid":
|
115
116
|
{
|
116
117
|
geometry.computeBoundingBox();
|
@@ -161,12 +162,10 @@ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisio
|
|
161
162
|
z: rz,
|
162
163
|
w: rw
|
163
164
|
});
|
164
|
-
|
165
|
-
if (
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
const collider = world.createCollider(desc, rigidBody.handle);
|
165
|
+
if (hasCollisionEvents) desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
166
|
+
if (Number.isFinite(options.friction)) desc.setFriction(options.friction);
|
167
|
+
if (Number.isFinite(options.restitution)) desc.setRestitution(options.restitution);
|
168
|
+
const collider = world.createCollider(desc, rigidBody);
|
170
169
|
colliders.push(collider);
|
171
170
|
}
|
172
171
|
});
|
@@ -184,7 +183,47 @@ const scaleVertices = (vertices, scale) => {
|
|
184
183
|
return scaledVerts;
|
185
184
|
};
|
186
185
|
|
187
|
-
|
186
|
+
function _defineProperty(obj, key, value) {
|
187
|
+
if (key in obj) {
|
188
|
+
Object.defineProperty(obj, key, {
|
189
|
+
value: value,
|
190
|
+
enumerable: true,
|
191
|
+
configurable: true,
|
192
|
+
writable: true
|
193
|
+
});
|
194
|
+
} else {
|
195
|
+
obj[key] = value;
|
196
|
+
}
|
197
|
+
|
198
|
+
return obj;
|
199
|
+
}
|
200
|
+
|
201
|
+
function ownKeys(object, enumerableOnly) {
|
202
|
+
var keys = Object.keys(object);
|
203
|
+
|
204
|
+
if (Object.getOwnPropertySymbols) {
|
205
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
206
|
+
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
207
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
208
|
+
})), keys.push.apply(keys, symbols);
|
209
|
+
}
|
210
|
+
|
211
|
+
return keys;
|
212
|
+
}
|
213
|
+
|
214
|
+
function _objectSpread2(target) {
|
215
|
+
for (var i = 1; i < arguments.length; i++) {
|
216
|
+
var source = null != arguments[i] ? arguments[i] : {};
|
217
|
+
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
218
|
+
_defineProperty(target, key, source[key]);
|
219
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
220
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
221
|
+
});
|
222
|
+
}
|
223
|
+
|
224
|
+
return target;
|
225
|
+
}
|
226
|
+
|
188
227
|
const createRigidBodyApi = ref => {
|
189
228
|
return {
|
190
229
|
raw: () => ref.current(),
|
@@ -193,30 +232,21 @@ const createRigidBodyApi = ref => {
|
|
193
232
|
return ref.current().handle;
|
194
233
|
},
|
195
234
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
}) {
|
201
|
-
ref.current().applyImpulse({
|
202
|
-
x,
|
203
|
-
y,
|
204
|
-
z
|
205
|
-
}, true);
|
235
|
+
mass: () => ref.current().mass(),
|
236
|
+
|
237
|
+
applyImpulse(impulseVector) {
|
238
|
+
ref.current().applyImpulse(impulseVector, true);
|
206
239
|
},
|
207
240
|
|
208
|
-
applyTorqueImpulse({
|
209
|
-
|
210
|
-
y,
|
211
|
-
z
|
212
|
-
}) {
|
213
|
-
ref.current().applyTorqueImpulse({
|
214
|
-
x,
|
215
|
-
y,
|
216
|
-
z
|
217
|
-
}, true);
|
241
|
+
applyTorqueImpulse(torqueVector) {
|
242
|
+
ref.current().applyTorqueImpulse(torqueVector, true);
|
218
243
|
},
|
219
244
|
|
245
|
+
applyImpulseAtPoint: (impulseVector, impulsePoint) => ref.current().applyImpulseAtPoint(impulseVector, impulsePoint, true),
|
246
|
+
addForce: force => ref.current().addForce(force, true),
|
247
|
+
addForceAtPoint: (force, point) => ref.current().addForceAtPoint(force, point, true),
|
248
|
+
addTorque: torque => ref.current().addTorque(torque, true),
|
249
|
+
|
220
250
|
translation() {
|
221
251
|
const {
|
222
252
|
x,
|
@@ -226,6 +256,8 @@ const createRigidBodyApi = ref => {
|
|
226
256
|
return new Vector3(x, y, z);
|
227
257
|
},
|
228
258
|
|
259
|
+
setTranslation: translation => ref.current().setTranslation(translation, true),
|
260
|
+
|
229
261
|
rotation() {
|
230
262
|
const {
|
231
263
|
x,
|
@@ -234,8 +266,39 @@ const createRigidBodyApi = ref => {
|
|
234
266
|
w
|
235
267
|
} = ref.current().rotation();
|
236
268
|
return new Quaternion(x, y, z, w);
|
237
|
-
}
|
269
|
+
},
|
270
|
+
|
271
|
+
setRotation: rotation => ref.current().setRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
|
272
|
+
w: 1
|
273
|
+
}), true),
|
274
|
+
|
275
|
+
linvel() {
|
276
|
+
const {
|
277
|
+
x,
|
278
|
+
y,
|
279
|
+
z
|
280
|
+
} = ref.current().linvel();
|
281
|
+
return new Vector3(x, y, z);
|
282
|
+
},
|
238
283
|
|
284
|
+
setLinvel: velocity => ref.current().setLinvel(velocity, true),
|
285
|
+
|
286
|
+
angvel() {
|
287
|
+
const {
|
288
|
+
x,
|
289
|
+
y,
|
290
|
+
z
|
291
|
+
} = ref.current().angvel();
|
292
|
+
return new Vector3(x, y, z);
|
293
|
+
},
|
294
|
+
|
295
|
+
setAngvel: velocity => ref.current().setAngvel(velocity, true),
|
296
|
+
setNextKinematicRotation: rotation => ref.current().setNextKinematicRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
|
297
|
+
w: 1
|
298
|
+
})),
|
299
|
+
setNextKinematicTranslation: translation => ref.current().setNextKinematicTranslation(translation),
|
300
|
+
resetForces: () => ref.current().resetForces(true),
|
301
|
+
resetTorques: () => ref.current().resetTorques(true)
|
239
302
|
};
|
240
303
|
}; // TODO: Flesh this out
|
241
304
|
|
@@ -255,10 +318,10 @@ const createWorldApi = ref => {
|
|
255
318
|
getCollider: handle => ref.current().getCollider(handle),
|
256
319
|
getRigidBody: handle => ref.current().getRigidBody(handle),
|
257
320
|
createRigidBody: desc => ref.current().createRigidBody(desc),
|
258
|
-
createCollider: (desc,
|
321
|
+
createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
|
259
322
|
removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
|
260
323
|
removeCollider: collider => ref.current().removeCollider(collider, true),
|
261
|
-
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
|
324
|
+
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, true),
|
262
325
|
removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
|
263
326
|
forEachCollider: callback => ref.current().forEachCollider(callback)
|
264
327
|
};
|
@@ -305,7 +368,7 @@ const Physics = ({
|
|
305
368
|
const [rigidBodyEvents] = useState(() => new Map());
|
306
369
|
const [eventQueue] = useState(() => new EventQueue(false)); // Init world
|
307
370
|
|
308
|
-
|
371
|
+
useEffect(() => {
|
309
372
|
const world = getWorldRef.current();
|
310
373
|
return () => {
|
311
374
|
if (world) {
|
@@ -374,10 +437,12 @@ const Physics = ({
|
|
374
437
|
}); // Collision events
|
375
438
|
|
376
439
|
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
440
|
+
var _collider1$parent, _collider2$parent;
|
441
|
+
|
377
442
|
const collider1 = world.getCollider(handle1);
|
378
443
|
const collider2 = world.getCollider(handle2);
|
379
|
-
const rigidBodyHandle1 = collider1.parent();
|
380
|
-
const rigidBodyHandle2 = collider2.parent();
|
444
|
+
const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
|
445
|
+
const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle;
|
381
446
|
|
382
447
|
if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
|
383
448
|
return;
|
@@ -389,7 +454,7 @@ const Physics = ({
|
|
389
454
|
const events2 = rigidBodyEvents.get(rigidBodyHandle2);
|
390
455
|
|
391
456
|
if (started) {
|
392
|
-
world.contactPair(
|
457
|
+
world.contactPair(collider1, collider2, (manifold, flipped) => {
|
393
458
|
var _events1$onCollisionE, _events2$onCollisionE;
|
394
459
|
|
395
460
|
events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
|
@@ -433,47 +498,6 @@ const Physics = ({
|
|
433
498
|
}, children);
|
434
499
|
};
|
435
500
|
|
436
|
-
function _defineProperty(obj, key, value) {
|
437
|
-
if (key in obj) {
|
438
|
-
Object.defineProperty(obj, key, {
|
439
|
-
value: value,
|
440
|
-
enumerable: true,
|
441
|
-
configurable: true,
|
442
|
-
writable: true
|
443
|
-
});
|
444
|
-
} else {
|
445
|
-
obj[key] = value;
|
446
|
-
}
|
447
|
-
|
448
|
-
return obj;
|
449
|
-
}
|
450
|
-
|
451
|
-
function ownKeys(object, enumerableOnly) {
|
452
|
-
var keys = Object.keys(object);
|
453
|
-
|
454
|
-
if (Object.getOwnPropertySymbols) {
|
455
|
-
var symbols = Object.getOwnPropertySymbols(object);
|
456
|
-
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
457
|
-
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
458
|
-
})), keys.push.apply(keys, symbols);
|
459
|
-
}
|
460
|
-
|
461
|
-
return keys;
|
462
|
-
}
|
463
|
-
|
464
|
-
function _objectSpread2(target) {
|
465
|
-
for (var i = 1; i < arguments.length; i++) {
|
466
|
-
var source = null != arguments[i] ? arguments[i] : {};
|
467
|
-
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
468
|
-
_defineProperty(target, key, source[key]);
|
469
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
470
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
471
|
-
});
|
472
|
-
}
|
473
|
-
|
474
|
-
return target;
|
475
|
-
}
|
476
|
-
|
477
501
|
const useRapier = () => {
|
478
502
|
return useContext(RapierContext);
|
479
503
|
};
|
@@ -504,7 +528,7 @@ const useRigidBody = (options = {}) => {
|
|
504
528
|
z: avz
|
505
529
|
}).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
|
506
530
|
const rigidBody = world.createRigidBody(desc);
|
507
|
-
rigidBodyRef.current = rigidBody;
|
531
|
+
rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
|
508
532
|
}
|
509
533
|
|
510
534
|
return rigidBodyRef.current;
|
@@ -550,13 +574,11 @@ const useRigidBody = (options = {}) => {
|
|
550
574
|
rigidBody.resetForces(false);
|
551
575
|
rigidBody.resetTorques(false);
|
552
576
|
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;
|
553
|
-
const
|
554
|
-
const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world, hasCollisionEvents) : [];
|
555
|
-
rigidBody.wakeUp();
|
577
|
+
const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, options, world) : [];
|
556
578
|
rigidBodyMeshes.set(rigidBody.handle, ref.current);
|
557
579
|
return () => {
|
558
|
-
autoColliders.forEach(collider => world.removeCollider(collider));
|
559
580
|
world.removeRigidBody(rigidBody);
|
581
|
+
autoColliders.forEach(collider => world.removeCollider(collider));
|
560
582
|
rigidBodyRef.current = undefined;
|
561
583
|
rigidBodyMeshes.delete(rigidBody.handle);
|
562
584
|
};
|
@@ -585,7 +607,7 @@ const useCollider = (body, options = {}) => {
|
|
585
607
|
const objectRef = useRef();
|
586
608
|
const getColliderRef = useRef(() => {
|
587
609
|
if (!colliderRef.current) {
|
588
|
-
colliderRef.current = createColliderFromOptions(options, world, body.handle);
|
610
|
+
colliderRef.current = createColliderFromOptions(options, world, world.getRigidBody(body.handle));
|
589
611
|
}
|
590
612
|
|
591
613
|
return colliderRef.current;
|
@@ -611,7 +633,7 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
|
|
611
633
|
}
|
612
634
|
|
613
635
|
const scale = ref.current.getWorldScale(new Vector3());
|
614
|
-
const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
|
636
|
+
const collider = createColliderFromOptions(colliderOptions, world, world.getRigidBody(rigidBody.handle), scale);
|
615
637
|
return () => {
|
616
638
|
world.removeCollider(collider);
|
617
639
|
};
|
@@ -767,7 +789,6 @@ const useImpulseJoint = (body1, body2, params) => {
|
|
767
789
|
const joint = getJointRef.current();
|
768
790
|
return () => {
|
769
791
|
if (joint) {
|
770
|
-
console.log('remove joint', joint);
|
771
792
|
world.removeImpulseJoint(joint);
|
772
793
|
jointRef.current = undefined;
|
773
794
|
}
|
@@ -918,7 +939,7 @@ const AnyCollider = _ref2 => {
|
|
918
939
|
const ref = useRef(null);
|
919
940
|
useEffect(() => {
|
920
941
|
const scale = ref.current.getWorldScale(new Vector3());
|
921
|
-
const collider = createColliderFromOptions(props, world, rigidBody.
|
942
|
+
const collider = createColliderFromOptions(props, world, rigidBody.raw(), scale, hasCollisionEvents);
|
922
943
|
return () => {
|
923
944
|
world.removeCollider(collider);
|
924
945
|
};
|
@@ -975,20 +996,20 @@ const ConvexHullCollider = props => {
|
|
975
996
|
};
|
976
997
|
|
977
998
|
const geometryFromCollider = collider => {
|
978
|
-
switch (collider.
|
999
|
+
switch (collider.shape.type) {
|
979
1000
|
case ShapeType.Cuboid:
|
980
1001
|
{
|
981
1002
|
const {
|
982
1003
|
x,
|
983
1004
|
y,
|
984
1005
|
z
|
985
|
-
} = collider.halfExtents
|
1006
|
+
} = collider.shape.halfExtents;
|
986
1007
|
return new BoxBufferGeometry(x * 2 + 0.01, y * 2 + 0.01, z * 2 + 0.01);
|
987
1008
|
}
|
988
1009
|
|
989
1010
|
case ShapeType.Ball:
|
990
1011
|
{
|
991
|
-
const r = collider.radius
|
1012
|
+
const r = collider.shape.radius;
|
992
1013
|
return new SphereBufferGeometry(r + +0.01, 8, 8);
|
993
1014
|
}
|
994
1015
|
|
@@ -996,10 +1017,12 @@ const geometryFromCollider = collider => {
|
|
996
1017
|
{
|
997
1018
|
var _g$index;
|
998
1019
|
|
999
|
-
const v = collider.vertices
|
1000
|
-
const i = collider.indices
|
1001
|
-
const g = new BufferGeometry();
|
1002
|
-
|
1020
|
+
const v = collider.shape.vertices;
|
1021
|
+
const i = collider.shape.indices;
|
1022
|
+
const g = new BufferGeometry(); // Vertices are not always a float3darray (???), so we need to convert them
|
1023
|
+
|
1024
|
+
const safeVerts = Float32Array.from(v);
|
1025
|
+
g.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
1003
1026
|
(_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.set(i);
|
1004
1027
|
g.setDrawRange(0, g.attributes.position.array.length / 3 - 1);
|
1005
1028
|
return g;
|
@@ -1007,16 +1030,18 @@ const geometryFromCollider = collider => {
|
|
1007
1030
|
|
1008
1031
|
case ShapeType.ConvexPolyhedron:
|
1009
1032
|
{
|
1010
|
-
const cv = collider.vertices()
|
1033
|
+
const cv = collider.shape.vertices; // Vertices are not always a float3darray (???), so we need to convert them
|
1034
|
+
|
1035
|
+
const safeVerts = Float32Array.from(cv);
|
1011
1036
|
const cg = new BufferGeometry();
|
1012
|
-
cg.setAttribute("position", new BufferAttribute(
|
1037
|
+
cg.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
1013
1038
|
return cg;
|
1014
1039
|
}
|
1015
1040
|
|
1016
1041
|
case ShapeType.Cylinder:
|
1017
1042
|
{
|
1018
|
-
const r = collider.radius
|
1019
|
-
const h = collider.halfHeight
|
1043
|
+
const r = collider.shape.radius;
|
1044
|
+
const h = collider.shape.halfHeight;
|
1020
1045
|
const g = new CylinderBufferGeometry(r, r, h);
|
1021
1046
|
return g;
|
1022
1047
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-three/rapier",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.2",
|
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": "0.8.
|
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,182 @@
|
|
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, Torus } 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
|
+
<Suspense>
|
16
|
+
<Physics>
|
17
|
+
<RigidBody colliders={"hull"} restitution={2}>
|
18
|
+
<Torus />
|
19
|
+
</RigidBody>
|
20
|
+
|
21
|
+
<RigidBody position={[0, -2, 0]} type="kinematicPosition">
|
22
|
+
<Box args={[20, 0.5, 20]} />
|
23
|
+
</RigidBody>
|
24
|
+
</Physics>
|
25
|
+
</Suspense>
|
26
|
+
</Canvas>
|
27
|
+
);
|
28
|
+
};
|
29
|
+
```
|
30
|
+
|
31
|
+
## Automatic colliders
|
32
|
+
|
33
|
+
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.
|
34
|
+
|
35
|
+
Supported values:
|
36
|
+
|
37
|
+
- `"cuboid"`, creates a CuboidCollider based on the bounding box of the mesh
|
38
|
+
- `"ball"`, creates a SphereCollider based on the bounding sphere of the mesh
|
39
|
+
- `"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)
|
40
|
+
- `"hull"`, creates a ConvexHullCollider based on the mesh's geometry
|
41
|
+
- `false`, disables auto-generation
|
42
|
+
|
43
|
+
Generate ConvexHull colliders for all meshes in a RigidBody by default:
|
44
|
+
|
45
|
+
```tsx
|
46
|
+
const Scene = () => (
|
47
|
+
<Physics colliders="hull">
|
48
|
+
<RigidBody>
|
49
|
+
<Box />
|
50
|
+
</RigidBody>
|
51
|
+
<RigidBody position={[0, 10, 0]}>
|
52
|
+
<Sphere />
|
53
|
+
</RigidBody>
|
54
|
+
</Physics>
|
55
|
+
);
|
56
|
+
```
|
57
|
+
|
58
|
+
Turn off automatic collider generation globally, but apply auto generation locally:
|
59
|
+
|
60
|
+
```tsx
|
61
|
+
const Scene = () => (
|
62
|
+
<Physics colliders={false}>
|
63
|
+
<RigidBody colliders="cuboid">
|
64
|
+
<Box />
|
65
|
+
</RigidBody>
|
66
|
+
|
67
|
+
<RigidBody position={[0, 10, 0]} colliders="ball">
|
68
|
+
<Sphere />
|
69
|
+
</RigidBody>
|
70
|
+
|
71
|
+
<RigidBody position={[0, 10, 0]}>
|
72
|
+
<Sphere />
|
73
|
+
<BallCollider args={0.5} />
|
74
|
+
<BallCollider args={0.5} position={[1, 0, 0]} />
|
75
|
+
</RigidBody>
|
76
|
+
</Physics>
|
77
|
+
);
|
78
|
+
```
|
79
|
+
|
80
|
+
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.
|
81
|
+
|
82
|
+
```tsx
|
83
|
+
import { Box } from "@react-three/drei";
|
84
|
+
import { RigidBody, CuboidCollider } from "@react-three/rapier";
|
85
|
+
|
86
|
+
const Scene = () => {
|
87
|
+
return (
|
88
|
+
<group position={[2, 5, 0]} rotation={[0, 0.3, 2]}>
|
89
|
+
<RigidBody>
|
90
|
+
<Box />
|
91
|
+
<CuboidCollider args={[0.5, 0.5, 0.5]} />
|
92
|
+
</RigidBody>
|
93
|
+
</group>
|
94
|
+
);
|
95
|
+
};
|
96
|
+
```
|
97
|
+
|
98
|
+
## Debug
|
99
|
+
|
100
|
+
Use the Debug component to see live representations of all colliders in a scene.
|
101
|
+
|
102
|
+
> Note: Experimental. Not all shapes are supported. Unsupported shapes are always represented by cubes.
|
103
|
+
|
104
|
+
```tsx
|
105
|
+
import { Box, Sphere } from "@react-three/drei";
|
106
|
+
import { RigidBody, Debug } from "@react-three/rapier";
|
107
|
+
|
108
|
+
const Scene = () => {
|
109
|
+
return (
|
110
|
+
<Physics>
|
111
|
+
<Debug />
|
112
|
+
|
113
|
+
<RigidBody>
|
114
|
+
<Box />
|
115
|
+
</RigidBody>
|
116
|
+
<RigidBody>
|
117
|
+
<Sphere />
|
118
|
+
</RigidBody>
|
119
|
+
</Physics>
|
120
|
+
);
|
121
|
+
};
|
122
|
+
```
|
123
|
+
|
124
|
+
## Events
|
125
|
+
|
126
|
+
You can subscribe collision and state events on the RigidBody.
|
127
|
+
|
128
|
+
```tsx
|
129
|
+
const RigidBottle = () => {
|
130
|
+
const [isAsleep, setIsAsleep] = useState(false);
|
131
|
+
|
132
|
+
return (
|
133
|
+
<RigidBody
|
134
|
+
colliders="hull"
|
135
|
+
onSleep={() => setIsAsleep(true)}
|
136
|
+
onWake={() => setIsAsleep(false)}
|
137
|
+
onCollision={({manifold}) => {
|
138
|
+
console.log('Collision at world position ', manifold.solverContactPoint(0))
|
139
|
+
}}
|
140
|
+
>
|
141
|
+
<Sphere>
|
142
|
+
<meshPhysicalMaterial color={isAsleep ? 'white' : 'blue'}>
|
143
|
+
</Sphere>
|
144
|
+
</RigidBody>
|
145
|
+
)
|
146
|
+
}
|
147
|
+
```
|
148
|
+
|
149
|
+
## Hooks
|
150
|
+
|
151
|
+
You can also use hooks to generate rigid bodies and colliders, but it's not encouraged.
|
152
|
+
|
153
|
+
```tsx
|
154
|
+
import { Box } from "@react-three/drei";
|
155
|
+
import { useCuboid } from "@react-three/rapier";
|
156
|
+
|
157
|
+
const RigidBox = () => {
|
158
|
+
// Generates a RigidBody and attaches a BoxCollider to it, returns a ref
|
159
|
+
const [box, rigidBody, collider] = useCuboid(
|
160
|
+
{ position: [1, 1, 1] },
|
161
|
+
{ args: [0.5, 0.5, 0.5] }
|
162
|
+
);
|
163
|
+
|
164
|
+
return <Box ref={box} />;
|
165
|
+
};
|
166
|
+
```
|
167
|
+
|
168
|
+
## Roadmap?
|
169
|
+
|
170
|
+
In order, but also not necessarily:
|
171
|
+
|
172
|
+
- [x] Draft of all base shapes
|
173
|
+
- [x] Draft of all base joints
|
174
|
+
- [x] Nested objects retain world transforms
|
175
|
+
- [x] Nested objects retain correct collider scale
|
176
|
+
- [x] Automatic colliders based on rigidbody children
|
177
|
+
- [ ] Translation and rotational constraints
|
178
|
+
- [x] Collision events
|
179
|
+
- [ ] InstancedMesh support
|
180
|
+
- [ ] Docs
|
181
|
+
- [ ] CodeSandbox examples
|
182
|
+
- [ ] Helpers, for things like Vehicle, Rope, Player, etc
|