Rapier physics in React
@react-three/rapier v2 has been released, which adds support for @react-three/fiber v9 and react v19. If you are using react v18, you will need to use @react-three/rapier v1 and @react-three/fiber v8.
For contributions, please read the Contribution Guide.
For available APIs, see API Docs
react-three/rapier (or r3/rapier) is a wrapper library around the Rapier (https://rapier.rs/docs/user_guides/javascript) WASM-based physics engine, designed to slot seamlessly into a react-three/fiber pipeline.
The goal of this library to is to provide a fast physics engine with minimal friction and small, straight forward API.
import { Box, Torus } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Physics, RigidBody, CuboidCollider } from "@react-three/rapier";
const App = () => {
return (
<Canvas>
<Suspense>
<Physics debug>
<RigidBody colliders={"hull"} restitution={2}>
<Torus />
</RigidBody>
<CuboidCollider position={[0, -2, 0]} args={[20, 0.5, 20]} />
</Physics>
</Suspense>
</Canvas>
);
};Below follows a guide on core concepts for react-three/rapier.
For full API outline and documentation, see API Docs.
The <Physics /> component is the root component of your physics world. It is responsible for creating the physics world and managing the simulation. It relies on lazily initiating Rapier and needs to be wrapped in <Suspense />.
See PhysicsProps docs for available props.
const Scene = () => {
return (
<Canvas>
<Suspense>
<Physics gravity={[0, 1, 0]} interpolation={false} colliders={false}>
...
</Physics>
</Suspense>
</Canvas>
);
};The <RigidBody /> component is used to add a mesh into the physics world. You use it by wrapping one or more meshes and setting desired props. By default, this will automatically generate Colliders based on the shape of the wrapped meshes (see Automatic colliders).
See RigidBodyProps docs for available props.
const RigidBodyMesh = () => (
<RigidBody>
<mesh />
</RigidBody>
);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.
Supported values:
"cuboid", creates a CuboidCollider based on the bounding box of the mesh"ball", creates a SphereCollider based on the bounding sphere of the mesh"trimesh", creates a TrimeshCollider based on the mesh's geometry"hull", creates a ConvexHullCollider based on the mesh's geometryfalse, disables auto-generationGenerate ConvexHull colliders for all meshes in a RigidBody by default:
const Scene = () => (
<Physics colliders="hull">
<RigidBody>
<Box />
</RigidBody>
<RigidBody position={[0, 10, 0]}>
<Sphere />
</RigidBody>
</Physics>
);Turn off automatic collider generation globally, but apply auto generation locally:
const Scene = () => (
<Physics colliders={false}>
{/* Use an automatic CuboidCollider for all meshes inside this RigidBody */}
<RigidBody colliders="cuboid">
<Box />
</RigidBody>
{/* Use an automatic BallCollider for all meshes inside this RigidBody */}
<RigidBody position={[0, 10, 0]} colliders="ball">
<Sphere />
</RigidBody>
</Physics>
);You can also create Colliders by hand and add them to a RigidBody to create compound colliders. This is useful for creating more complex shapes, for creating simplified shapes for performance reasons, or for detecting collisions on specific parts of a mesh.
See ColliderProps docs for available props.
…RigidBodies 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.
Note It's always best to create RigidBodies where the center of gravity is in the center of the object, otherwise you might get some unexpected behavior during simulation interpolation.
import { Box } from "@react-three/drei";
import { RigidBody, CuboidCollider } from "@react-three/rapier";
const Scene = () => (
<group position={[2, 5, 0]} rotation={[0, 0.3, 2]}>
<RigidBody>
<Box />
<CuboidCollider args={[0.5, 0.5, 0.5]} />
</RigidBody>
</group>
);If part of our meshes are invisible and you want to include them in the collider creation, use the includeInvisible flag.
<RigidBody colliders="hull" includeInvisible>
<object3D>
<Suzanne visible={false} />
</object3D>
</RigidBody>Instanced meshes can also be used and have automatic colliders generated from their mesh.
By wrapping exactly one Three.InstancedMesh in <InstancedRigidBodies />, each instance will be attached to an individual RigidBody.
See InstancedRigidBodiesProps docs for available props.
…We can also create compound shapes for instanced meshes by providing an array of Colliders in the colliderNodes prop.
…Set the debug prop on <Physics /> to see live representations of all colliders in a scene, using the live debug buffer from the physics engine.
import { Box, Sphere } from "@react-three/drei";
import { RigidBody } from "@react-three/rapier";
const Scene = () => {
return (
<Physics debug>
<RigidBody>
<Box />
</RigidBody>
<RigidBody>
<Sphere />
</RigidBody>
</Physics>
);
};You can access the instance for a RigidBody by storing its ref. This allows you to perform any operation on the underlying physics object directly.
r3/rapier exposes a RapierRigidBody and RapierCollider as aliases for rapiers underlying base objects.
For all available methods, see the Rapier docs.
…Rapier's API returns quaternions and vectors that are not compatible with Three.js, r3/rapier therefore exposes some helper functions (vec3, quat, euler) for quick type conversions. These helper functions can also be used as a shorthand for creating new objects.
…You can subscribe to collision and state events on a RigidBody:
See onCollisionEnter / onCollisionExit docs for more information.
…You may also subscribe to collision events on individual Colliders:
<CuboidCollider
onCollisionEnter={(payload) => {
/* ... */
}}
onCollisionExit={(payload) => {
/* ... */
}}
/>The payload object for all collision callbacks contains the following properties:
targetCollisionTarget of the object firing the event.otherCollisionTarget of the other object involved in the event.manifold (onCollisionEnter only)flipped (onCollisionEnter only)true if the data in the manifold is flipped.A CollisionTarget is an object containing references to objects involved in a collision event. It has the following properties:
rigidBody (if exists): Rapier.RigidBodyrigidBodyObject (if exists): Three.Object3Dcollider: Rapier.CollidercolliderObject: Three.Object3DBoth <RigidBody> as well as all collider components allow you to configure collisionsGroups and solverGroups properties that configures which groups the colliders are in, and what other groups they should interact with in potential collision and solving events (you will find more details on this in the Rapier documentation.)
Since these are set as bitmasks and bitmasks can get a bit unwieldy to generate, this library provides a helper called interactionGroups that can be used to generate bitmasks from numbers and arrays of groups, where groups are identified using numbers from 0 to 15.
The first argument is the group, or an array of groups, that the collider is a member of; the second argument is the group, or an array of groups, that the collider should interact with.
Here the collider is in group 0, and interacts with colliders from groups 0, 1 and 2:
<CapsuleCollider collisionGroups={interactionGroups(0, [0, 1, 2])} />This collider is in multiple groups, but only interacts with colliders from a single group:
<CapsuleCollider collisionGroups={interactionGroups([0, 5], 7)} />When the second argument is omitted, the collider will interact with all groups:
<CapsuleCollider collisionGroups={interactionGroups(12)} />Note Please remember that in Rapier, for a collision (or solving) event to occur, both colliders involved in the event must match the related interaction groups -- a one-way match will be ignored.
Note By default, colliders are members of all groups, and will interact with all other groups.
Contact force events are triggered on <RigidBody> and any collider components when two objects collider.
``
No open issues yet, or sync has not completed.