@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.
- package/dist/declarations/src/Debug.d.ts +2 -0
- package/dist/declarations/src/Physics.d.ts +16 -0
- package/dist/declarations/src/components.d.ts +21 -0
- package/dist/declarations/src/hooks.d.ts +67 -0
- package/dist/declarations/src/index.d.ts +5 -0
- package/dist/declarations/src/types.d.ts +188 -0
- package/dist/declarations/src/utils.d.ts +17 -0
- package/dist/react-three-rapier.cjs.d.ts +1 -0
- package/dist/react-three-rapier.cjs.dev.js +914 -0
- package/dist/react-three-rapier.cjs.js +7 -0
- package/dist/react-three-rapier.cjs.prod.js +914 -0
- package/dist/react-three-rapier.esm.js +842 -0
- package/package.json +30 -0
@@ -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 };
|