@react-three/rapier 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import React, { useRef, useState, useLayoutEffect, useMemo, createContext, useContext, useEffect, forwardRef, useImperativeHandle, memo } from 'react';
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, rigidBodyHandle, scale = {
41
+ const createColliderFromOptions = (options, world, rigidBody, scale = {
42
42
  x: 1,
43
43
  y: 1,
44
44
  z: 1
@@ -85,7 +85,7 @@ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
85
85
  });
86
86
  }
87
87
 
88
- const collider = world.createCollider(colliderDesc, rigidBodyHandle);
88
+ const collider = world.createCollider(colliderDesc, rigidBody);
89
89
  return collider;
90
90
  };
91
91
  const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisionEvents = false) => {
@@ -166,7 +166,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisio
166
166
  desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
167
167
  }
168
168
 
169
- const collider = world.createCollider(desc, rigidBody.handle);
169
+ const collider = world.createCollider(desc, rigidBody);
170
170
  colliders.push(collider);
171
171
  }
172
172
  });
@@ -184,7 +184,47 @@ const scaleVertices = (vertices, scale) => {
184
184
  return scaledVerts;
185
185
  };
186
186
 
187
- // TODO: Flesh this out
187
+ function _defineProperty(obj, key, value) {
188
+ if (key in obj) {
189
+ Object.defineProperty(obj, key, {
190
+ value: value,
191
+ enumerable: true,
192
+ configurable: true,
193
+ writable: true
194
+ });
195
+ } else {
196
+ obj[key] = value;
197
+ }
198
+
199
+ return obj;
200
+ }
201
+
202
+ function ownKeys(object, enumerableOnly) {
203
+ var keys = Object.keys(object);
204
+
205
+ if (Object.getOwnPropertySymbols) {
206
+ var symbols = Object.getOwnPropertySymbols(object);
207
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
208
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
209
+ })), keys.push.apply(keys, symbols);
210
+ }
211
+
212
+ return keys;
213
+ }
214
+
215
+ function _objectSpread2(target) {
216
+ for (var i = 1; i < arguments.length; i++) {
217
+ var source = null != arguments[i] ? arguments[i] : {};
218
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
219
+ _defineProperty(target, key, source[key]);
220
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
221
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
222
+ });
223
+ }
224
+
225
+ return target;
226
+ }
227
+
188
228
  const createRigidBodyApi = ref => {
189
229
  return {
190
230
  raw: () => ref.current(),
@@ -193,30 +233,21 @@ const createRigidBodyApi = ref => {
193
233
  return ref.current().handle;
194
234
  },
195
235
 
196
- applyImpulse({
197
- x,
198
- y,
199
- z
200
- }) {
201
- ref.current().applyImpulse({
202
- x,
203
- y,
204
- z
205
- }, true);
236
+ mass: () => ref.current().mass(),
237
+
238
+ applyImpulse(impulseVector) {
239
+ ref.current().applyImpulse(impulseVector, true);
206
240
  },
207
241
 
208
- applyTorqueImpulse({
209
- x,
210
- y,
211
- z
212
- }) {
213
- ref.current().applyTorqueImpulse({
214
- x,
215
- y,
216
- z
217
- }, true);
242
+ applyTorqueImpulse(torqueVector) {
243
+ ref.current().applyTorqueImpulse(torqueVector, true);
218
244
  },
219
245
 
246
+ applyImpulseAtPoint: (impulseVector, impulsePoint) => ref.current().applyImpulseAtPoint(impulseVector, impulsePoint, true),
247
+ addForce: force => ref.current().addForce(force, true),
248
+ addForceAtPoint: (force, point) => ref.current().addForceAtPoint(force, point, true),
249
+ addTorque: torque => ref.current().addTorque(torque, true),
250
+
220
251
  translation() {
221
252
  const {
222
253
  x,
@@ -226,6 +257,8 @@ const createRigidBodyApi = ref => {
226
257
  return new Vector3(x, y, z);
227
258
  },
228
259
 
260
+ setTranslation: translation => ref.current().setTranslation(translation, true),
261
+
229
262
  rotation() {
230
263
  const {
231
264
  x,
@@ -234,8 +267,39 @@ const createRigidBodyApi = ref => {
234
267
  w
235
268
  } = ref.current().rotation();
236
269
  return new Quaternion(x, y, z, w);
237
- }
270
+ },
238
271
 
272
+ setRotation: rotation => ref.current().setRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
273
+ w: 1
274
+ }), true),
275
+
276
+ linvel() {
277
+ const {
278
+ x,
279
+ y,
280
+ z
281
+ } = ref.current().linvel();
282
+ return new Vector3(x, y, z);
283
+ },
284
+
285
+ setLinvel: velocity => ref.current().setLinvel(velocity, true),
286
+
287
+ angvel() {
288
+ const {
289
+ x,
290
+ y,
291
+ z
292
+ } = ref.current().angvel();
293
+ return new Vector3(x, y, z);
294
+ },
295
+
296
+ setAngvel: velocity => ref.current().setAngvel(velocity, true),
297
+ setNextKinematicRotation: rotation => ref.current().setNextKinematicRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
298
+ w: 1
299
+ })),
300
+ setNextKinematicTranslation: translation => ref.current().setNextKinematicTranslation(translation),
301
+ resetForces: () => ref.current().resetForces(true),
302
+ resetTorques: () => ref.current().resetTorques(true)
239
303
  };
240
304
  }; // TODO: Flesh this out
241
305
 
@@ -255,10 +319,10 @@ const createWorldApi = ref => {
255
319
  getCollider: handle => ref.current().getCollider(handle),
256
320
  getRigidBody: handle => ref.current().getRigidBody(handle),
257
321
  createRigidBody: desc => ref.current().createRigidBody(desc),
258
- createCollider: (desc, rigidBodyHandle) => ref.current().createCollider(desc, rigidBodyHandle),
322
+ createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
259
323
  removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
260
324
  removeCollider: collider => ref.current().removeCollider(collider, true),
261
- createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
325
+ createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, true),
262
326
  removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
263
327
  forEachCollider: callback => ref.current().forEachCollider(callback)
264
328
  };
@@ -305,7 +369,7 @@ const Physics = ({
305
369
  const [rigidBodyEvents] = useState(() => new Map());
306
370
  const [eventQueue] = useState(() => new EventQueue(false)); // Init world
307
371
 
308
- useLayoutEffect(() => {
372
+ useEffect(() => {
309
373
  const world = getWorldRef.current();
310
374
  return () => {
311
375
  if (world) {
@@ -374,10 +438,12 @@ const Physics = ({
374
438
  }); // Collision events
375
439
 
376
440
  eventQueue.drainCollisionEvents((handle1, handle2, started) => {
441
+ var _collider1$parent, _collider2$parent;
442
+
377
443
  const collider1 = world.getCollider(handle1);
378
444
  const collider2 = world.getCollider(handle2);
379
- const rigidBodyHandle1 = collider1.parent();
380
- const rigidBodyHandle2 = collider2.parent();
445
+ const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
446
+ const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle;
381
447
 
382
448
  if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
383
449
  return;
@@ -389,7 +455,7 @@ const Physics = ({
389
455
  const events2 = rigidBodyEvents.get(rigidBodyHandle2);
390
456
 
391
457
  if (started) {
392
- world.contactPair(handle1, handle2, (manifold, flipped) => {
458
+ world.contactPair(collider1, collider2, (manifold, flipped) => {
393
459
  var _events1$onCollisionE, _events2$onCollisionE;
394
460
 
395
461
  events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
@@ -433,47 +499,6 @@ const Physics = ({
433
499
  }, children);
434
500
  };
435
501
 
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
502
  const useRapier = () => {
478
503
  return useContext(RapierContext);
479
504
  };
@@ -504,7 +529,7 @@ const useRigidBody = (options = {}) => {
504
529
  z: avz
505
530
  }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
506
531
  const rigidBody = world.createRigidBody(desc);
507
- rigidBodyRef.current = rigidBody;
532
+ rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
508
533
  }
509
534
 
510
535
  return rigidBodyRef.current;
@@ -555,8 +580,8 @@ const useRigidBody = (options = {}) => {
555
580
  rigidBody.wakeUp();
556
581
  rigidBodyMeshes.set(rigidBody.handle, ref.current);
557
582
  return () => {
558
- autoColliders.forEach(collider => world.removeCollider(collider));
559
583
  world.removeRigidBody(rigidBody);
584
+ autoColliders.forEach(collider => world.removeCollider(collider));
560
585
  rigidBodyRef.current = undefined;
561
586
  rigidBodyMeshes.delete(rigidBody.handle);
562
587
  };
@@ -585,7 +610,7 @@ const useCollider = (body, options = {}) => {
585
610
  const objectRef = useRef();
586
611
  const getColliderRef = useRef(() => {
587
612
  if (!colliderRef.current) {
588
- colliderRef.current = createColliderFromOptions(options, world, body.handle);
613
+ colliderRef.current = createColliderFromOptions(options, world, world.getRigidBody(body.handle));
589
614
  }
590
615
 
591
616
  return colliderRef.current;
@@ -611,7 +636,7 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
611
636
  }
612
637
 
613
638
  const scale = ref.current.getWorldScale(new Vector3());
614
- const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
639
+ const collider = createColliderFromOptions(colliderOptions, world, world.getRigidBody(rigidBody.handle), scale);
615
640
  return () => {
616
641
  world.removeCollider(collider);
617
642
  };
@@ -767,7 +792,6 @@ const useImpulseJoint = (body1, body2, params) => {
767
792
  const joint = getJointRef.current();
768
793
  return () => {
769
794
  if (joint) {
770
- console.log('remove joint', joint);
771
795
  world.removeImpulseJoint(joint);
772
796
  jointRef.current = undefined;
773
797
  }
@@ -918,7 +942,7 @@ const AnyCollider = _ref2 => {
918
942
  const ref = useRef(null);
919
943
  useEffect(() => {
920
944
  const scale = ref.current.getWorldScale(new Vector3());
921
- const collider = createColliderFromOptions(props, world, rigidBody.handle, scale, hasCollisionEvents);
945
+ const collider = createColliderFromOptions(props, world, rigidBody.raw(), scale, hasCollisionEvents);
922
946
  return () => {
923
947
  world.removeCollider(collider);
924
948
  };
@@ -975,20 +999,20 @@ const ConvexHullCollider = props => {
975
999
  };
976
1000
 
977
1001
  const geometryFromCollider = collider => {
978
- switch (collider.shapeType()) {
1002
+ switch (collider.shape.type) {
979
1003
  case ShapeType.Cuboid:
980
1004
  {
981
1005
  const {
982
1006
  x,
983
1007
  y,
984
1008
  z
985
- } = collider.halfExtents();
1009
+ } = collider.shape.halfExtents;
986
1010
  return new BoxBufferGeometry(x * 2 + 0.01, y * 2 + 0.01, z * 2 + 0.01);
987
1011
  }
988
1012
 
989
1013
  case ShapeType.Ball:
990
1014
  {
991
- const r = collider.radius();
1015
+ const r = collider.shape.radius;
992
1016
  return new SphereBufferGeometry(r + +0.01, 8, 8);
993
1017
  }
994
1018
 
@@ -996,10 +1020,12 @@ const geometryFromCollider = collider => {
996
1020
  {
997
1021
  var _g$index;
998
1022
 
999
- const v = collider.vertices();
1000
- const i = collider.indices();
1001
- const g = new BufferGeometry();
1002
- g.setAttribute("position", new BufferAttribute(v, 3));
1023
+ const v = collider.shape.vertices;
1024
+ const i = collider.shape.indices;
1025
+ const g = new BufferGeometry(); // Vertices are not always a float3darray (???), so we need to convert them
1026
+
1027
+ const safeVerts = Float32Array.from(v);
1028
+ g.setAttribute("position", new BufferAttribute(safeVerts, 3));
1003
1029
  (_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.set(i);
1004
1030
  g.setDrawRange(0, g.attributes.position.array.length / 3 - 1);
1005
1031
  return g;
@@ -1007,16 +1033,18 @@ const geometryFromCollider = collider => {
1007
1033
 
1008
1034
  case ShapeType.ConvexPolyhedron:
1009
1035
  {
1010
- const cv = collider.vertices();
1036
+ const cv = collider.shape.vertices; // Vertices are not always a float3darray (???), so we need to convert them
1037
+
1038
+ const safeVerts = Float32Array.from(cv);
1011
1039
  const cg = new BufferGeometry();
1012
- cg.setAttribute("position", new BufferAttribute(cv, 3));
1040
+ cg.setAttribute("position", new BufferAttribute(safeVerts, 3));
1013
1041
  return cg;
1014
1042
  }
1015
1043
 
1016
1044
  case ShapeType.Cylinder:
1017
1045
  {
1018
- const r = collider.radius();
1019
- const h = collider.halfHeight();
1046
+ const r = collider.shape.radius;
1047
+ const h = collider.shape.halfHeight;
1020
1048
  const g = new CylinderBufferGeometry(r, r, h);
1021
1049
  return g;
1022
1050
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
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.0-alpha.2",
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