@react-three/rapier 1.2.1 → 1.3.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/components/Physics.d.ts +32 -15
- package/dist/declarations/src/hooks/joints.d.ts +14 -4
- package/dist/declarations/src/types.d.ts +35 -13
- package/dist/declarations/src/utils/utils-collider.d.ts +1 -0
- package/dist/declarations/src/utils/utils.d.ts +3 -1
- package/dist/react-three-rapier.cjs.dev.js +70 -18
- package/dist/react-three-rapier.cjs.prod.js +70 -18
- package/dist/react-three-rapier.esm.js +70 -20
- package/package.json +2 -2
- package/readme.md +94 -1
@@ -149,30 +149,34 @@ export interface PhysicsProps {
|
|
149
149
|
*/
|
150
150
|
gravity?: Vector3Tuple;
|
151
151
|
/**
|
152
|
-
*
|
153
|
-
*
|
154
|
-
*
|
155
|
-
* @defaultValue 1
|
152
|
+
* Amount of penetration the engine wont attempt to correct
|
153
|
+
* @defaultValue 0.001
|
156
154
|
*/
|
157
|
-
|
155
|
+
allowedLinearError?: number;
|
158
156
|
/**
|
159
|
-
* The
|
160
|
-
*
|
161
|
-
* The greater this value is, the most realistic friction will be.
|
157
|
+
* The number of solver iterations run by the constraints solver for calculating forces.
|
158
|
+
* The greater this value is, the most rigid and realistic the physics simulation will be.
|
162
159
|
* However a greater number of iterations is more computationally intensive.
|
163
160
|
*
|
164
|
-
* @defaultValue
|
161
|
+
* @defaultValue 4
|
165
162
|
*/
|
166
|
-
|
163
|
+
numSolverIterations?: number;
|
167
164
|
/**
|
168
|
-
*
|
169
|
-
*
|
170
|
-
* The greater this value is, the most rigid and realistic the physics simulation will be.
|
165
|
+
* Number of addition friction resolution iteration run during the last solver sub-step.
|
166
|
+
* The greater this value is, the most realistic friction will be.
|
171
167
|
* However a greater number of iterations is more computationally intensive.
|
172
168
|
*
|
173
169
|
* @defaultValue 4
|
174
170
|
*/
|
175
|
-
|
171
|
+
numAdditionalFrictionIterations?: number;
|
172
|
+
/**
|
173
|
+
* Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration.
|
174
|
+
* Increasing this parameter will improve stability of the simulation. It will have a lesser effect than
|
175
|
+
* increasing `numSolverIterations` but is also less computationally expensive.
|
176
|
+
*
|
177
|
+
* @defaultValue 1
|
178
|
+
*/
|
179
|
+
numInternalPgsIterations?: number;
|
176
180
|
/**
|
177
181
|
* The maximal distance separating two objects that will generate predictive contacts
|
178
182
|
*
|
@@ -181,7 +185,20 @@ export interface PhysicsProps {
|
|
181
185
|
*/
|
182
186
|
predictionDistance?: number;
|
183
187
|
/**
|
184
|
-
*
|
188
|
+
* Minimum number of dynamic bodies in each active island
|
189
|
+
*
|
190
|
+
* @defaultValue 128
|
191
|
+
*/
|
192
|
+
minIslandSize?: number;
|
193
|
+
/**
|
194
|
+
* Maximum number of substeps performed by the solver
|
195
|
+
*
|
196
|
+
* @defaultValue 1
|
197
|
+
*/
|
198
|
+
maxCcdSubsteps?: number;
|
199
|
+
/**
|
200
|
+
* The Error Reduction Parameter in between 0 and 1, is the proportion of the positional error to be corrected at each time step.
|
201
|
+
*
|
185
202
|
* @defaultValue 0.8
|
186
203
|
*/
|
187
204
|
erp?: number;
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import {
|
2
|
-
import
|
3
|
-
import { RapierRigidBody,
|
1
|
+
import { FixedImpulseJoint, ImpulseJoint, PrismaticImpulseJoint, RevoluteImpulseJoint, RopeImpulseJoint, SphericalImpulseJoint, SpringImpulseJoint } from "@dimforge/rapier3d-compat";
|
2
|
+
import { RefObject } from "react";
|
3
|
+
import { FixedJointParams, PrismaticJointParams, RapierRigidBody, RevoluteJointParams, RopeJointParams, SphericalJointParams, SpringJointParams, UseImpulseJoint } from "..";
|
4
4
|
import type Rapier from "@dimforge/rapier3d-compat";
|
5
5
|
/**
|
6
6
|
* @internal
|
7
7
|
*/
|
8
|
-
export declare const useImpulseJoint: <JointType extends ImpulseJoint>(body1: RefObject<RapierRigidBody>, body2: RefObject<RapierRigidBody>, params: Rapier.JointData) =>
|
8
|
+
export declare const useImpulseJoint: <JointType extends ImpulseJoint>(body1: RefObject<RapierRigidBody>, body2: RefObject<RapierRigidBody>, params: Rapier.JointData) => import("react").MutableRefObject<JointType | undefined>;
|
9
9
|
/**
|
10
10
|
* A fixed joint ensures that two rigid-bodies don't move relative to each other.
|
11
11
|
* Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
|
@@ -39,3 +39,13 @@ export declare const useRevoluteJoint: UseImpulseJoint<RevoluteJointParams, Revo
|
|
39
39
|
* @category Hooks - Joints
|
40
40
|
*/
|
41
41
|
export declare const usePrismaticJoint: UseImpulseJoint<PrismaticJointParams, PrismaticImpulseJoint>;
|
42
|
+
/**
|
43
|
+
* The rope joint limits the max distance between two bodies.
|
44
|
+
* @category Hooks - Joints
|
45
|
+
*/
|
46
|
+
export declare const useRopeJoint: UseImpulseJoint<RopeJointParams, RopeImpulseJoint>;
|
47
|
+
/**
|
48
|
+
* The spring joint applies a force proportional to the distance between two objects.
|
49
|
+
* @category Hooks - Joints
|
50
|
+
*/
|
51
|
+
export declare const useSpringJoint: UseImpulseJoint<SpringJointParams, SpringImpulseJoint>;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { MutableRefObject, RefObject } from "react";
|
2
2
|
import { CoefficientCombineRule, Collider as RapierCollider, ImpulseJoint, InteractionGroups, RigidBody as RapierRigidBody, TempContactManifold } from "@dimforge/rapier3d-compat";
|
3
3
|
import { Rotation, Vector } from "@dimforge/rapier3d-compat/math";
|
4
|
-
import { Object3DProps } from "@react-three/fiber";
|
4
|
+
import { Object3DProps, Vector3, Quaternion } from "@react-three/fiber";
|
5
5
|
import { Object3D } from "three";
|
6
6
|
import { ColliderProps } from ".";
|
7
7
|
import { RigidBodyState } from "./components/Physics";
|
@@ -305,6 +305,16 @@ export interface RigidBodyOptions extends ColliderProps {
|
|
305
305
|
* This does not affect any non-automatic child collider-components.
|
306
306
|
*/
|
307
307
|
restitution?: number;
|
308
|
+
/**
|
309
|
+
* Sets the number of additional solver iterations that will be run for this
|
310
|
+
* rigid-body and everything that interacts with it directly or indirectly
|
311
|
+
* through contacts or joints.
|
312
|
+
*
|
313
|
+
* Compared to increasing the global `World.numSolverIteration`, setting this
|
314
|
+
* value lets you increase accuracy on only a subset of the scene, resulting in reduced
|
315
|
+
* performance loss.
|
316
|
+
*/
|
317
|
+
additionalSolverIterations?: number;
|
308
318
|
/**
|
309
319
|
* The default collision groups bitmask for all colliders in this rigid body.
|
310
320
|
* Can be customized per-collider.
|
@@ -348,27 +358,39 @@ export interface RigidBodyOptions extends ColliderProps {
|
|
348
358
|
transformState?: (state: RigidBodyState) => RigidBodyState;
|
349
359
|
}
|
350
360
|
export declare type SphericalJointParams = [
|
351
|
-
body1Anchor:
|
352
|
-
body2Anchor:
|
361
|
+
body1Anchor: Vector3,
|
362
|
+
body2Anchor: Vector3
|
353
363
|
];
|
354
364
|
export declare type FixedJointParams = [
|
355
|
-
body1Anchor:
|
356
|
-
body1LocalFrame:
|
357
|
-
body2Anchor:
|
358
|
-
body2LocalFrame:
|
365
|
+
body1Anchor: Vector3,
|
366
|
+
body1LocalFrame: Quaternion,
|
367
|
+
body2Anchor: Vector3,
|
368
|
+
body2LocalFrame: Quaternion
|
359
369
|
];
|
360
370
|
export declare type PrismaticJointParams = [
|
361
|
-
body1Anchor:
|
362
|
-
body2Anchor:
|
363
|
-
axis:
|
371
|
+
body1Anchor: Vector3,
|
372
|
+
body2Anchor: Vector3,
|
373
|
+
axis: Vector3,
|
364
374
|
limits?: [min: number, max: number]
|
365
375
|
];
|
366
376
|
export declare type RevoluteJointParams = [
|
367
|
-
body1Anchor:
|
368
|
-
body2Anchor:
|
369
|
-
axis:
|
377
|
+
body1Anchor: Vector3,
|
378
|
+
body2Anchor: Vector3,
|
379
|
+
axis: Vector3,
|
370
380
|
limits?: [min: number, max: number]
|
371
381
|
];
|
382
|
+
export declare type RopeJointParams = [
|
383
|
+
body1Anchor: Vector3,
|
384
|
+
body2Anchor: Vector3,
|
385
|
+
length: number
|
386
|
+
];
|
387
|
+
export declare type SpringJointParams = [
|
388
|
+
body1Anchor: Vector3,
|
389
|
+
body2Anchor: Vector3,
|
390
|
+
restLength: number,
|
391
|
+
stiffness: number,
|
392
|
+
damping: number
|
393
|
+
];
|
372
394
|
export interface UseImpulseJoint<JointParams, JointType extends ImpulseJoint> {
|
373
395
|
(body1: RefObject<RapierRigidBody>, body2: RefObject<RapierRigidBody>, params: JointParams): RefObject<JointType | undefined>;
|
374
396
|
}
|
@@ -47,6 +47,7 @@ export declare const cleanRigidBodyPropsForCollider: (props?: RigidBodyProps) =>
|
|
47
47
|
colliders?: RigidBodyAutoCollider | undefined;
|
48
48
|
friction?: number | undefined;
|
49
49
|
restitution?: number | undefined;
|
50
|
+
additionalSolverIterations?: number | undefined;
|
50
51
|
collisionGroups?: number | undefined;
|
51
52
|
solverGroups?: number | undefined;
|
52
53
|
onSleep?(): void;
|
@@ -1,11 +1,13 @@
|
|
1
1
|
import { Quaternion as RapierQuaternion, Vector3 as RapierVector3 } from "@dimforge/rapier3d-compat";
|
2
2
|
import { Euler, Quaternion, Vector3 } from "three";
|
3
3
|
import { RigidBodyTypeString, Vector3Tuple } from "../types";
|
4
|
+
import { Vector3 as Vector3Like, Quaternion as QuaternionLike } from "@react-three/fiber";
|
4
5
|
export declare const vectorArrayToVector3: (arr: Vector3Tuple) => Vector3;
|
5
|
-
export declare const tupleToObject: <T extends readonly any[], K extends readonly string[]>(tuple: T, keys: K) => { [Key in K[number]]: T[number]; };
|
6
6
|
export declare const vector3ToQuaternion: (v: Vector3) => Quaternion;
|
7
7
|
export declare const rapierVector3ToVector3: ({ x, y, z }: RapierVector3) => Vector3;
|
8
8
|
export declare const rapierQuaternionToQuaternion: ({ x, y, z, w }: RapierQuaternion) => Quaternion;
|
9
|
+
export declare const vector3ToRapierVector: (v: Vector3Like) => RapierVector3;
|
10
|
+
export declare const quaternionToRapierQuaternion: (v: QuaternionLike) => RapierQuaternion;
|
9
11
|
export declare const rigidBodyTypeFromString: (type: RigidBodyTypeString) => 0 | 3 | 1 | 2;
|
10
12
|
export declare const scaleVertices: (vertices: ArrayLike<number>, scale: Vector3) => number[];
|
11
13
|
export declare const vectorToTuple: (v: Vector3 | Quaternion | any[] | undefined | number | Euler) => any[];
|
@@ -85,18 +85,29 @@ const vectorArrayToVector3 = arr => {
|
|
85
85
|
const [x, y, z] = arr;
|
86
86
|
return new three.Vector3(x, y, z);
|
87
87
|
};
|
88
|
-
const tupleToObject = (tuple, keys) => {
|
89
|
-
return keys.reduce((obj, key, i) => {
|
90
|
-
obj[key] = tuple[i];
|
91
|
-
return obj;
|
92
|
-
}, {});
|
93
|
-
};
|
94
88
|
const rapierQuaternionToQuaternion = ({
|
95
89
|
x,
|
96
90
|
y,
|
97
91
|
z,
|
98
92
|
w
|
99
93
|
}) => _quaternion.set(x, y, z, w);
|
94
|
+
const vector3ToRapierVector = v => {
|
95
|
+
if (Array.isArray(v)) {
|
96
|
+
return new rapier3dCompat.Vector3(v[0], v[1], v[2]);
|
97
|
+
} else if (typeof v === "number") {
|
98
|
+
return new rapier3dCompat.Vector3(v, v, v);
|
99
|
+
} else {
|
100
|
+
const threeVector3 = v;
|
101
|
+
return new rapier3dCompat.Vector3(threeVector3.x, threeVector3.y, threeVector3.z);
|
102
|
+
}
|
103
|
+
};
|
104
|
+
const quaternionToRapierQuaternion = v => {
|
105
|
+
if (Array.isArray(v)) {
|
106
|
+
return new rapier3dCompat.Quaternion(v[0], v[1], v[2], v[3]);
|
107
|
+
} else {
|
108
|
+
return new rapier3dCompat.Quaternion(v.x, v.y, v.z, v.w);
|
109
|
+
}
|
110
|
+
};
|
100
111
|
const rigidBodyTypeMap = {
|
101
112
|
fixed: 1,
|
102
113
|
dynamic: 0,
|
@@ -744,10 +755,13 @@ const Physics = props => {
|
|
744
755
|
updateLoop = "follow",
|
745
756
|
debug = false,
|
746
757
|
gravity = [0, -9.81, 0],
|
747
|
-
|
748
|
-
maxVelocityFrictionIterations = 8,
|
749
|
-
maxVelocityIterations = 4,
|
758
|
+
allowedLinearError = 0.001,
|
750
759
|
predictionDistance = 0.002,
|
760
|
+
numSolverIterations = 4,
|
761
|
+
numAdditionalFrictionIterations = 4,
|
762
|
+
numInternalPgsIterations = 1,
|
763
|
+
minIslandSize = 128,
|
764
|
+
maxCcdSubsteps = 1,
|
751
765
|
erp = 0.8
|
752
766
|
} = props;
|
753
767
|
const rapier = useAsset.useAsset(importRapier);
|
@@ -780,13 +794,16 @@ const Physics = props => {
|
|
780
794
|
}, []); // Update mutable props
|
781
795
|
|
782
796
|
React.useEffect(() => {
|
783
|
-
worldProxy.gravity =
|
784
|
-
worldProxy.integrationParameters.
|
785
|
-
worldProxy.integrationParameters.
|
786
|
-
worldProxy.integrationParameters.
|
797
|
+
worldProxy.gravity = vector3ToRapierVector(gravity);
|
798
|
+
worldProxy.integrationParameters.numSolverIterations = numSolverIterations;
|
799
|
+
worldProxy.integrationParameters.numAdditionalFrictionIterations = numAdditionalFrictionIterations;
|
800
|
+
worldProxy.integrationParameters.numInternalPgsIterations = numInternalPgsIterations;
|
801
|
+
worldProxy.integrationParameters.allowedLinearError = allowedLinearError;
|
802
|
+
worldProxy.integrationParameters.minIslandSize = minIslandSize;
|
803
|
+
worldProxy.integrationParameters.maxCcdSubsteps = maxCcdSubsteps;
|
787
804
|
worldProxy.integrationParameters.predictionDistance = predictionDistance;
|
788
805
|
worldProxy.integrationParameters.erp = erp;
|
789
|
-
}, [worldProxy, ...gravity,
|
806
|
+
}, [worldProxy, ...gravity, numSolverIterations, numAdditionalFrictionIterations, numInternalPgsIterations, allowedLinearError, minIslandSize, maxCcdSubsteps, predictionDistance, erp]);
|
790
807
|
const getSourceFromColliderHandle = React.useCallback(handle => {
|
791
808
|
var _collider$parent;
|
792
809
|
|
@@ -1375,6 +1392,11 @@ const mutableRigidBodyOptions = {
|
|
1375
1392
|
gravityScale: (rb, value) => {
|
1376
1393
|
rb.setGravityScale(value, true);
|
1377
1394
|
},
|
1395
|
+
|
1396
|
+
additionalSolverIterations(rb, value) {
|
1397
|
+
rb.setAdditionalSolverIterations(value);
|
1398
|
+
},
|
1399
|
+
|
1378
1400
|
linearDamping: (rb, value) => {
|
1379
1401
|
rb.setLinearDamping(value);
|
1380
1402
|
},
|
@@ -1733,7 +1755,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
|
|
1733
1755
|
const {
|
1734
1756
|
rapier
|
1735
1757
|
} = useRapier();
|
1736
|
-
return useImpulseJoint(body1, body2, rapier.JointData.fixed(
|
1758
|
+
return useImpulseJoint(body1, body2, rapier.JointData.fixed(vector3ToRapierVector(body1Anchor), quaternionToRapierQuaternion(body1LocalFrame), vector3ToRapierVector(body2Anchor), quaternionToRapierQuaternion(body2LocalFrame)));
|
1737
1759
|
};
|
1738
1760
|
/**
|
1739
1761
|
* The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
|
@@ -1748,7 +1770,7 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
|
|
1748
1770
|
const {
|
1749
1771
|
rapier
|
1750
1772
|
} = useRapier();
|
1751
|
-
return useImpulseJoint(body1, body2, rapier.JointData.spherical(
|
1773
|
+
return useImpulseJoint(body1, body2, rapier.JointData.spherical(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor)));
|
1752
1774
|
};
|
1753
1775
|
/**
|
1754
1776
|
* The revolute joint prevents any relative movement between two rigid-bodies, except for relative
|
@@ -1762,7 +1784,7 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
|
|
1762
1784
|
const {
|
1763
1785
|
rapier
|
1764
1786
|
} = useRapier();
|
1765
|
-
const params = rapier.JointData.revolute(
|
1787
|
+
const params = rapier.JointData.revolute(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1766
1788
|
|
1767
1789
|
if (limits) {
|
1768
1790
|
params.limitsEnabled = true;
|
@@ -1783,7 +1805,7 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1783
1805
|
const {
|
1784
1806
|
rapier
|
1785
1807
|
} = useRapier();
|
1786
|
-
const params = rapier.JointData.prismatic(
|
1808
|
+
const params = rapier.JointData.prismatic(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1787
1809
|
|
1788
1810
|
if (limits) {
|
1789
1811
|
params.limitsEnabled = true;
|
@@ -1792,6 +1814,34 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1792
1814
|
|
1793
1815
|
return useImpulseJoint(body1, body2, params);
|
1794
1816
|
};
|
1817
|
+
/**
|
1818
|
+
* The rope joint limits the max distance between two bodies.
|
1819
|
+
* @category Hooks - Joints
|
1820
|
+
*/
|
1821
|
+
|
1822
|
+
const useRopeJoint = (body1, body2, [body1Anchor, body2Anchor, length]) => {
|
1823
|
+
const {
|
1824
|
+
rapier
|
1825
|
+
} = useRapier();
|
1826
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1827
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1828
|
+
const params = rapier.JointData.rope(length, vBody1Anchor, vBody2Anchor);
|
1829
|
+
return useImpulseJoint(body1, body2, params);
|
1830
|
+
};
|
1831
|
+
/**
|
1832
|
+
* The spring joint applies a force proportional to the distance between two objects.
|
1833
|
+
* @category Hooks - Joints
|
1834
|
+
*/
|
1835
|
+
|
1836
|
+
const useSpringJoint = (body1, body2, [body1Anchor, body2Anchor, restLength, stiffness, damping]) => {
|
1837
|
+
const {
|
1838
|
+
rapier
|
1839
|
+
} = useRapier();
|
1840
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1841
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1842
|
+
const params = rapier.JointData.spring(restLength, stiffness, damping, vBody1Anchor, vBody2Anchor);
|
1843
|
+
return useImpulseJoint(body1, body2, params);
|
1844
|
+
};
|
1795
1845
|
|
1796
1846
|
/**
|
1797
1847
|
* Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
|
@@ -1867,5 +1917,7 @@ exports.useImpulseJoint = useImpulseJoint;
|
|
1867
1917
|
exports.usePrismaticJoint = usePrismaticJoint;
|
1868
1918
|
exports.useRapier = useRapier;
|
1869
1919
|
exports.useRevoluteJoint = useRevoluteJoint;
|
1920
|
+
exports.useRopeJoint = useRopeJoint;
|
1870
1921
|
exports.useSphericalJoint = useSphericalJoint;
|
1922
|
+
exports.useSpringJoint = useSpringJoint;
|
1871
1923
|
exports.vec3 = vec3;
|
@@ -85,18 +85,29 @@ const vectorArrayToVector3 = arr => {
|
|
85
85
|
const [x, y, z] = arr;
|
86
86
|
return new three.Vector3(x, y, z);
|
87
87
|
};
|
88
|
-
const tupleToObject = (tuple, keys) => {
|
89
|
-
return keys.reduce((obj, key, i) => {
|
90
|
-
obj[key] = tuple[i];
|
91
|
-
return obj;
|
92
|
-
}, {});
|
93
|
-
};
|
94
88
|
const rapierQuaternionToQuaternion = ({
|
95
89
|
x,
|
96
90
|
y,
|
97
91
|
z,
|
98
92
|
w
|
99
93
|
}) => _quaternion.set(x, y, z, w);
|
94
|
+
const vector3ToRapierVector = v => {
|
95
|
+
if (Array.isArray(v)) {
|
96
|
+
return new rapier3dCompat.Vector3(v[0], v[1], v[2]);
|
97
|
+
} else if (typeof v === "number") {
|
98
|
+
return new rapier3dCompat.Vector3(v, v, v);
|
99
|
+
} else {
|
100
|
+
const threeVector3 = v;
|
101
|
+
return new rapier3dCompat.Vector3(threeVector3.x, threeVector3.y, threeVector3.z);
|
102
|
+
}
|
103
|
+
};
|
104
|
+
const quaternionToRapierQuaternion = v => {
|
105
|
+
if (Array.isArray(v)) {
|
106
|
+
return new rapier3dCompat.Quaternion(v[0], v[1], v[2], v[3]);
|
107
|
+
} else {
|
108
|
+
return new rapier3dCompat.Quaternion(v.x, v.y, v.z, v.w);
|
109
|
+
}
|
110
|
+
};
|
100
111
|
const rigidBodyTypeMap = {
|
101
112
|
fixed: 1,
|
102
113
|
dynamic: 0,
|
@@ -744,10 +755,13 @@ const Physics = props => {
|
|
744
755
|
updateLoop = "follow",
|
745
756
|
debug = false,
|
746
757
|
gravity = [0, -9.81, 0],
|
747
|
-
|
748
|
-
maxVelocityFrictionIterations = 8,
|
749
|
-
maxVelocityIterations = 4,
|
758
|
+
allowedLinearError = 0.001,
|
750
759
|
predictionDistance = 0.002,
|
760
|
+
numSolverIterations = 4,
|
761
|
+
numAdditionalFrictionIterations = 4,
|
762
|
+
numInternalPgsIterations = 1,
|
763
|
+
minIslandSize = 128,
|
764
|
+
maxCcdSubsteps = 1,
|
751
765
|
erp = 0.8
|
752
766
|
} = props;
|
753
767
|
const rapier = useAsset.useAsset(importRapier);
|
@@ -780,13 +794,16 @@ const Physics = props => {
|
|
780
794
|
}, []); // Update mutable props
|
781
795
|
|
782
796
|
React.useEffect(() => {
|
783
|
-
worldProxy.gravity =
|
784
|
-
worldProxy.integrationParameters.
|
785
|
-
worldProxy.integrationParameters.
|
786
|
-
worldProxy.integrationParameters.
|
797
|
+
worldProxy.gravity = vector3ToRapierVector(gravity);
|
798
|
+
worldProxy.integrationParameters.numSolverIterations = numSolverIterations;
|
799
|
+
worldProxy.integrationParameters.numAdditionalFrictionIterations = numAdditionalFrictionIterations;
|
800
|
+
worldProxy.integrationParameters.numInternalPgsIterations = numInternalPgsIterations;
|
801
|
+
worldProxy.integrationParameters.allowedLinearError = allowedLinearError;
|
802
|
+
worldProxy.integrationParameters.minIslandSize = minIslandSize;
|
803
|
+
worldProxy.integrationParameters.maxCcdSubsteps = maxCcdSubsteps;
|
787
804
|
worldProxy.integrationParameters.predictionDistance = predictionDistance;
|
788
805
|
worldProxy.integrationParameters.erp = erp;
|
789
|
-
}, [worldProxy, ...gravity,
|
806
|
+
}, [worldProxy, ...gravity, numSolverIterations, numAdditionalFrictionIterations, numInternalPgsIterations, allowedLinearError, minIslandSize, maxCcdSubsteps, predictionDistance, erp]);
|
790
807
|
const getSourceFromColliderHandle = React.useCallback(handle => {
|
791
808
|
var _collider$parent;
|
792
809
|
|
@@ -1375,6 +1392,11 @@ const mutableRigidBodyOptions = {
|
|
1375
1392
|
gravityScale: (rb, value) => {
|
1376
1393
|
rb.setGravityScale(value, true);
|
1377
1394
|
},
|
1395
|
+
|
1396
|
+
additionalSolverIterations(rb, value) {
|
1397
|
+
rb.setAdditionalSolverIterations(value);
|
1398
|
+
},
|
1399
|
+
|
1378
1400
|
linearDamping: (rb, value) => {
|
1379
1401
|
rb.setLinearDamping(value);
|
1380
1402
|
},
|
@@ -1733,7 +1755,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
|
|
1733
1755
|
const {
|
1734
1756
|
rapier
|
1735
1757
|
} = useRapier();
|
1736
|
-
return useImpulseJoint(body1, body2, rapier.JointData.fixed(
|
1758
|
+
return useImpulseJoint(body1, body2, rapier.JointData.fixed(vector3ToRapierVector(body1Anchor), quaternionToRapierQuaternion(body1LocalFrame), vector3ToRapierVector(body2Anchor), quaternionToRapierQuaternion(body2LocalFrame)));
|
1737
1759
|
};
|
1738
1760
|
/**
|
1739
1761
|
* The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
|
@@ -1748,7 +1770,7 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
|
|
1748
1770
|
const {
|
1749
1771
|
rapier
|
1750
1772
|
} = useRapier();
|
1751
|
-
return useImpulseJoint(body1, body2, rapier.JointData.spherical(
|
1773
|
+
return useImpulseJoint(body1, body2, rapier.JointData.spherical(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor)));
|
1752
1774
|
};
|
1753
1775
|
/**
|
1754
1776
|
* The revolute joint prevents any relative movement between two rigid-bodies, except for relative
|
@@ -1762,7 +1784,7 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
|
|
1762
1784
|
const {
|
1763
1785
|
rapier
|
1764
1786
|
} = useRapier();
|
1765
|
-
const params = rapier.JointData.revolute(
|
1787
|
+
const params = rapier.JointData.revolute(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1766
1788
|
|
1767
1789
|
if (limits) {
|
1768
1790
|
params.limitsEnabled = true;
|
@@ -1783,7 +1805,7 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1783
1805
|
const {
|
1784
1806
|
rapier
|
1785
1807
|
} = useRapier();
|
1786
|
-
const params = rapier.JointData.prismatic(
|
1808
|
+
const params = rapier.JointData.prismatic(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1787
1809
|
|
1788
1810
|
if (limits) {
|
1789
1811
|
params.limitsEnabled = true;
|
@@ -1792,6 +1814,34 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1792
1814
|
|
1793
1815
|
return useImpulseJoint(body1, body2, params);
|
1794
1816
|
};
|
1817
|
+
/**
|
1818
|
+
* The rope joint limits the max distance between two bodies.
|
1819
|
+
* @category Hooks - Joints
|
1820
|
+
*/
|
1821
|
+
|
1822
|
+
const useRopeJoint = (body1, body2, [body1Anchor, body2Anchor, length]) => {
|
1823
|
+
const {
|
1824
|
+
rapier
|
1825
|
+
} = useRapier();
|
1826
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1827
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1828
|
+
const params = rapier.JointData.rope(length, vBody1Anchor, vBody2Anchor);
|
1829
|
+
return useImpulseJoint(body1, body2, params);
|
1830
|
+
};
|
1831
|
+
/**
|
1832
|
+
* The spring joint applies a force proportional to the distance between two objects.
|
1833
|
+
* @category Hooks - Joints
|
1834
|
+
*/
|
1835
|
+
|
1836
|
+
const useSpringJoint = (body1, body2, [body1Anchor, body2Anchor, restLength, stiffness, damping]) => {
|
1837
|
+
const {
|
1838
|
+
rapier
|
1839
|
+
} = useRapier();
|
1840
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1841
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1842
|
+
const params = rapier.JointData.spring(restLength, stiffness, damping, vBody1Anchor, vBody2Anchor);
|
1843
|
+
return useImpulseJoint(body1, body2, params);
|
1844
|
+
};
|
1795
1845
|
|
1796
1846
|
/**
|
1797
1847
|
* Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
|
@@ -1867,5 +1917,7 @@ exports.useImpulseJoint = useImpulseJoint;
|
|
1867
1917
|
exports.usePrismaticJoint = usePrismaticJoint;
|
1868
1918
|
exports.useRapier = useRapier;
|
1869
1919
|
exports.useRevoluteJoint = useRevoluteJoint;
|
1920
|
+
exports.useRopeJoint = useRopeJoint;
|
1870
1921
|
exports.useSphericalJoint = useSphericalJoint;
|
1922
|
+
exports.useSpringJoint = useSpringJoint;
|
1871
1923
|
exports.vec3 = vec3;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ActiveEvents, ColliderDesc, EventQueue, RigidBodyDesc } from '@dimforge/rapier3d-compat';
|
1
|
+
import { Vector3 as Vector3$1, Quaternion as Quaternion$1, ActiveEvents, ColliderDesc, EventQueue, RigidBodyDesc } from '@dimforge/rapier3d-compat';
|
2
2
|
export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
|
3
3
|
import { useFrame, useThree } from '@react-three/fiber';
|
4
4
|
import React, { useRef, useEffect, memo, useMemo, useContext, useState, createContext, useCallback, forwardRef, Fragment } from 'react';
|
@@ -60,18 +60,29 @@ const vectorArrayToVector3 = arr => {
|
|
60
60
|
const [x, y, z] = arr;
|
61
61
|
return new Vector3(x, y, z);
|
62
62
|
};
|
63
|
-
const tupleToObject = (tuple, keys) => {
|
64
|
-
return keys.reduce((obj, key, i) => {
|
65
|
-
obj[key] = tuple[i];
|
66
|
-
return obj;
|
67
|
-
}, {});
|
68
|
-
};
|
69
63
|
const rapierQuaternionToQuaternion = ({
|
70
64
|
x,
|
71
65
|
y,
|
72
66
|
z,
|
73
67
|
w
|
74
68
|
}) => _quaternion.set(x, y, z, w);
|
69
|
+
const vector3ToRapierVector = v => {
|
70
|
+
if (Array.isArray(v)) {
|
71
|
+
return new Vector3$1(v[0], v[1], v[2]);
|
72
|
+
} else if (typeof v === "number") {
|
73
|
+
return new Vector3$1(v, v, v);
|
74
|
+
} else {
|
75
|
+
const threeVector3 = v;
|
76
|
+
return new Vector3$1(threeVector3.x, threeVector3.y, threeVector3.z);
|
77
|
+
}
|
78
|
+
};
|
79
|
+
const quaternionToRapierQuaternion = v => {
|
80
|
+
if (Array.isArray(v)) {
|
81
|
+
return new Quaternion$1(v[0], v[1], v[2], v[3]);
|
82
|
+
} else {
|
83
|
+
return new Quaternion$1(v.x, v.y, v.z, v.w);
|
84
|
+
}
|
85
|
+
};
|
75
86
|
const rigidBodyTypeMap = {
|
76
87
|
fixed: 1,
|
77
88
|
dynamic: 0,
|
@@ -719,10 +730,13 @@ const Physics = props => {
|
|
719
730
|
updateLoop = "follow",
|
720
731
|
debug = false,
|
721
732
|
gravity = [0, -9.81, 0],
|
722
|
-
|
723
|
-
maxVelocityFrictionIterations = 8,
|
724
|
-
maxVelocityIterations = 4,
|
733
|
+
allowedLinearError = 0.001,
|
725
734
|
predictionDistance = 0.002,
|
735
|
+
numSolverIterations = 4,
|
736
|
+
numAdditionalFrictionIterations = 4,
|
737
|
+
numInternalPgsIterations = 1,
|
738
|
+
minIslandSize = 128,
|
739
|
+
maxCcdSubsteps = 1,
|
726
740
|
erp = 0.8
|
727
741
|
} = props;
|
728
742
|
const rapier = useAsset(importRapier);
|
@@ -755,13 +769,16 @@ const Physics = props => {
|
|
755
769
|
}, []); // Update mutable props
|
756
770
|
|
757
771
|
useEffect(() => {
|
758
|
-
worldProxy.gravity =
|
759
|
-
worldProxy.integrationParameters.
|
760
|
-
worldProxy.integrationParameters.
|
761
|
-
worldProxy.integrationParameters.
|
772
|
+
worldProxy.gravity = vector3ToRapierVector(gravity);
|
773
|
+
worldProxy.integrationParameters.numSolverIterations = numSolverIterations;
|
774
|
+
worldProxy.integrationParameters.numAdditionalFrictionIterations = numAdditionalFrictionIterations;
|
775
|
+
worldProxy.integrationParameters.numInternalPgsIterations = numInternalPgsIterations;
|
776
|
+
worldProxy.integrationParameters.allowedLinearError = allowedLinearError;
|
777
|
+
worldProxy.integrationParameters.minIslandSize = minIslandSize;
|
778
|
+
worldProxy.integrationParameters.maxCcdSubsteps = maxCcdSubsteps;
|
762
779
|
worldProxy.integrationParameters.predictionDistance = predictionDistance;
|
763
780
|
worldProxy.integrationParameters.erp = erp;
|
764
|
-
}, [worldProxy, ...gravity,
|
781
|
+
}, [worldProxy, ...gravity, numSolverIterations, numAdditionalFrictionIterations, numInternalPgsIterations, allowedLinearError, minIslandSize, maxCcdSubsteps, predictionDistance, erp]);
|
765
782
|
const getSourceFromColliderHandle = useCallback(handle => {
|
766
783
|
var _collider$parent;
|
767
784
|
|
@@ -1350,6 +1367,11 @@ const mutableRigidBodyOptions = {
|
|
1350
1367
|
gravityScale: (rb, value) => {
|
1351
1368
|
rb.setGravityScale(value, true);
|
1352
1369
|
},
|
1370
|
+
|
1371
|
+
additionalSolverIterations(rb, value) {
|
1372
|
+
rb.setAdditionalSolverIterations(value);
|
1373
|
+
},
|
1374
|
+
|
1353
1375
|
linearDamping: (rb, value) => {
|
1354
1376
|
rb.setLinearDamping(value);
|
1355
1377
|
},
|
@@ -1708,7 +1730,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
|
|
1708
1730
|
const {
|
1709
1731
|
rapier
|
1710
1732
|
} = useRapier();
|
1711
|
-
return useImpulseJoint(body1, body2, rapier.JointData.fixed(
|
1733
|
+
return useImpulseJoint(body1, body2, rapier.JointData.fixed(vector3ToRapierVector(body1Anchor), quaternionToRapierQuaternion(body1LocalFrame), vector3ToRapierVector(body2Anchor), quaternionToRapierQuaternion(body2LocalFrame)));
|
1712
1734
|
};
|
1713
1735
|
/**
|
1714
1736
|
* The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
|
@@ -1723,7 +1745,7 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
|
|
1723
1745
|
const {
|
1724
1746
|
rapier
|
1725
1747
|
} = useRapier();
|
1726
|
-
return useImpulseJoint(body1, body2, rapier.JointData.spherical(
|
1748
|
+
return useImpulseJoint(body1, body2, rapier.JointData.spherical(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor)));
|
1727
1749
|
};
|
1728
1750
|
/**
|
1729
1751
|
* The revolute joint prevents any relative movement between two rigid-bodies, except for relative
|
@@ -1737,7 +1759,7 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]
|
|
1737
1759
|
const {
|
1738
1760
|
rapier
|
1739
1761
|
} = useRapier();
|
1740
|
-
const params = rapier.JointData.revolute(
|
1762
|
+
const params = rapier.JointData.revolute(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1741
1763
|
|
1742
1764
|
if (limits) {
|
1743
1765
|
params.limitsEnabled = true;
|
@@ -1758,7 +1780,7 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1758
1780
|
const {
|
1759
1781
|
rapier
|
1760
1782
|
} = useRapier();
|
1761
|
-
const params = rapier.JointData.prismatic(
|
1783
|
+
const params = rapier.JointData.prismatic(vector3ToRapierVector(body1Anchor), vector3ToRapierVector(body2Anchor), vector3ToRapierVector(axis));
|
1762
1784
|
|
1763
1785
|
if (limits) {
|
1764
1786
|
params.limitsEnabled = true;
|
@@ -1767,6 +1789,34 @@ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits
|
|
1767
1789
|
|
1768
1790
|
return useImpulseJoint(body1, body2, params);
|
1769
1791
|
};
|
1792
|
+
/**
|
1793
|
+
* The rope joint limits the max distance between two bodies.
|
1794
|
+
* @category Hooks - Joints
|
1795
|
+
*/
|
1796
|
+
|
1797
|
+
const useRopeJoint = (body1, body2, [body1Anchor, body2Anchor, length]) => {
|
1798
|
+
const {
|
1799
|
+
rapier
|
1800
|
+
} = useRapier();
|
1801
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1802
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1803
|
+
const params = rapier.JointData.rope(length, vBody1Anchor, vBody2Anchor);
|
1804
|
+
return useImpulseJoint(body1, body2, params);
|
1805
|
+
};
|
1806
|
+
/**
|
1807
|
+
* The spring joint applies a force proportional to the distance between two objects.
|
1808
|
+
* @category Hooks - Joints
|
1809
|
+
*/
|
1810
|
+
|
1811
|
+
const useSpringJoint = (body1, body2, [body1Anchor, body2Anchor, restLength, stiffness, damping]) => {
|
1812
|
+
const {
|
1813
|
+
rapier
|
1814
|
+
} = useRapier();
|
1815
|
+
const vBody1Anchor = vector3ToRapierVector(body1Anchor);
|
1816
|
+
const vBody2Anchor = vector3ToRapierVector(body2Anchor);
|
1817
|
+
const params = rapier.JointData.spring(restLength, stiffness, damping, vBody1Anchor, vBody2Anchor);
|
1818
|
+
return useImpulseJoint(body1, body2, params);
|
1819
|
+
};
|
1770
1820
|
|
1771
1821
|
/**
|
1772
1822
|
* Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
|
@@ -1804,4 +1854,4 @@ const interactionGroups = (memberships, filters) => (bitmask(memberships) << 16)
|
|
1804
1854
|
|
1805
1855
|
const bitmask = groups => [groups].flat().reduce((acc, layer) => acc | 1 << layer, 0);
|
1806
1856
|
|
1807
|
-
export { AnyCollider, BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundConeCollider, RoundCuboidCollider, RoundCylinderCollider, TrimeshCollider, euler, interactionGroups, quat, useAfterPhysicsStep, useBeforePhysicsStep, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useSphericalJoint, vec3 };
|
1857
|
+
export { AnyCollider, BallCollider, CapsuleCollider, ConeCollider, ConvexHullCollider, CuboidCollider, CylinderCollider, HeightfieldCollider, InstancedRigidBodies, MeshCollider, Physics, RigidBody, RoundConeCollider, RoundCuboidCollider, RoundCylinderCollider, TrimeshCollider, euler, interactionGroups, quat, useAfterPhysicsStep, useBeforePhysicsStep, useFixedJoint, useImpulseJoint, usePrismaticJoint, useRapier, useRevoluteJoint, useRopeJoint, useSphericalJoint, useSpringJoint, vec3 };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-three/rapier",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.3.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",
|
@@ -29,7 +29,7 @@
|
|
29
29
|
"three": ">=0.139.0"
|
30
30
|
},
|
31
31
|
"dependencies": {
|
32
|
-
"@dimforge/rapier3d-compat": "0.
|
32
|
+
"@dimforge/rapier3d-compat": "0.12.0",
|
33
33
|
"three-stdlib": "2.23.9",
|
34
34
|
"use-asset": "1.0.4"
|
35
35
|
},
|
package/readme.md
CHANGED
@@ -78,6 +78,8 @@ For full API outline and documentation, see 🧩 [API Docs](https://pmndrs.githu
|
|
78
78
|
- [Spherical Joint](#spherical-joint)
|
79
79
|
- [Revolute Joint](#revolute-joint)
|
80
80
|
- [Prismatic Joint](#prismatic-joint)
|
81
|
+
- [Rope Joint](#rope-joint)
|
82
|
+
- [Spring Joint](#spring-joint)
|
81
83
|
- [🖼 Joints Example](#-joints-example)
|
82
84
|
- [Advanced hooks usage](#advanced-hooks-usage)
|
83
85
|
- [Manual stepping](#manual-stepping)
|
@@ -623,12 +625,14 @@ Joints can be made between two `RigidBodies` to provide a way to restrict a moti
|
|
623
625
|
|
624
626
|
Joints are available in `r3/rapier` as hooks.
|
625
627
|
|
626
|
-
There are
|
628
|
+
There are 6 different joint types available:
|
627
629
|
|
628
630
|
- Fixed (two bodies are fixed together)
|
629
631
|
- Spherical (two bodies are connected by a ball and socket, for things like arms or chains)
|
630
632
|
- Revolute (two bodies are connected by a hinge, for things like doors or wheels)
|
631
633
|
- Prismatic (two bodies are connected by a sliding joint, for things like pistons or sliders)
|
634
|
+
- Rope (limits the max distance between two bodies)
|
635
|
+
- Spring (applies a force proportional to the distance between two bodies)
|
632
636
|
|
633
637
|
Each joint hook returns a RefObject containing the raw reference to the joint instance.
|
634
638
|
|
@@ -658,6 +662,9 @@ A fixed joint ensures that two rigid-bodies don't move relative to each other. F
|
|
658
662
|
|
659
663
|
```tsx
|
660
664
|
const JointedThing = () => {
|
665
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
666
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
667
|
+
|
661
668
|
const joint = useFixedJoint(bodyA, bodyB, [
|
662
669
|
// Position of the joint in bodyA's local space
|
663
670
|
[0, 0, 0],
|
@@ -690,6 +697,9 @@ The spherical joint ensures that two points on the local-spaces of two rigid-bod
|
|
690
697
|
|
691
698
|
```tsx
|
692
699
|
const JointedThing = () => {
|
700
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
701
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
702
|
+
|
693
703
|
const joint = useSphericalJoint(bodyA, bodyB, [
|
694
704
|
// Position of the joint in bodyA's local space
|
695
705
|
[0, 0, 0],
|
@@ -718,6 +728,9 @@ The revolute joint prevents any relative movement between two rigid-bodies, exce
|
|
718
728
|
|
719
729
|
```tsx
|
720
730
|
const JointedThing = () => {
|
731
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
732
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
733
|
+
|
721
734
|
const joint = useRevoluteJoint(bodyA, bodyB, [
|
722
735
|
// Position of the joint in bodyA's local space
|
723
736
|
[0, 0, 0],
|
@@ -749,6 +762,9 @@ The prismatic joint prevents any relative movement between two rigid-bodies, exc
|
|
749
762
|
|
750
763
|
```tsx
|
751
764
|
const JointedThing = () => {
|
765
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
766
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
767
|
+
|
752
768
|
const joint = usePrismaticJoint(bodyA, bodyB, [
|
753
769
|
// Position of the joint in bodyA's local space
|
754
770
|
[0, 0, 0],
|
@@ -772,6 +788,83 @@ const JointedThing = () => {
|
|
772
788
|
};
|
773
789
|
```
|
774
790
|
|
791
|
+
### Rope Joint
|
792
|
+
|
793
|
+
The rope joint limits the max distance between two bodies.
|
794
|
+
|
795
|
+
🧩 See [RopeJoint docs](https://pmndrs.github.io/react-three-rapier/functions/useRopeJoint.html) for available options.
|
796
|
+
|
797
|
+
```tsx
|
798
|
+
const JointedThing = () => {
|
799
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
800
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
801
|
+
|
802
|
+
const joint = useRopeJoint(bodyA, bodyB, [
|
803
|
+
// Position of the joint in bodyA's local space
|
804
|
+
[0, 0, 0],
|
805
|
+
// Position of the joint in bodyB's local space
|
806
|
+
[0, 0, 0],
|
807
|
+
// The max distance between the two bodies / length of the rope
|
808
|
+
1
|
809
|
+
]);
|
810
|
+
|
811
|
+
return (
|
812
|
+
<group>
|
813
|
+
<RigidBody ref={bodyA}>
|
814
|
+
<mesh />
|
815
|
+
</RigidBody>
|
816
|
+
<RigidBody ref={bodyB}>
|
817
|
+
<mesh />
|
818
|
+
</RigidBody>
|
819
|
+
</group>
|
820
|
+
);
|
821
|
+
};
|
822
|
+
```
|
823
|
+
|
824
|
+
### Spring Joint
|
825
|
+
|
826
|
+
The spring joint applies a force proportional to the distance between two bodies.
|
827
|
+
|
828
|
+
🧩 See [SpringJoint docs](https://pmndrs.github.io/react-three-rapier/functions/useSpringJoint.html) for available options.
|
829
|
+
|
830
|
+
```tsx
|
831
|
+
const JointedThing = () => {
|
832
|
+
const bodyA = useRef<RapierRigidBody>(null);
|
833
|
+
const bodyB = useRef<RapierRigidBody>(null);
|
834
|
+
|
835
|
+
const mass = 1;
|
836
|
+
const springRestLength = 0;
|
837
|
+
const stiffness = 1.0e3;
|
838
|
+
const criticalDamping = 2.0 * Math.sqrt(stiffness * mass);
|
839
|
+
const dampingRatio = props.jointNum / (props.total / 2);
|
840
|
+
const damping = dampingRatio * criticalDamping;
|
841
|
+
|
842
|
+
const joint = useSpringJoint(bodyA, bodyB, [
|
843
|
+
// Position of the joint in bodyA's local space
|
844
|
+
[0, 0, 0],
|
845
|
+
// Position of the joint in bodyB's local space
|
846
|
+
[0, 0, 0],
|
847
|
+
// Spring rest length
|
848
|
+
springRestLength,
|
849
|
+
// Spring stiffness
|
850
|
+
stiffness,
|
851
|
+
// Spring damping
|
852
|
+
damping
|
853
|
+
]);
|
854
|
+
|
855
|
+
return (
|
856
|
+
<group>
|
857
|
+
<RigidBody ref={bodyA}>
|
858
|
+
<mesh />
|
859
|
+
</RigidBody>
|
860
|
+
<RigidBody ref={bodyB}>
|
861
|
+
<mesh />
|
862
|
+
</RigidBody>
|
863
|
+
</group>
|
864
|
+
);
|
865
|
+
};
|
866
|
+
```
|
867
|
+
|
775
868
|
### 🖼 Joints Example
|
776
869
|
|
777
870
|
<a href="https://codesandbox.io/s/react-three-rapier-joints-mhhbd4"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-joints.jpg" width="240" /></a>
|