‼️ Breaking changes and API upgrades
- Completely removed the proxy api layer for both RigidBodies and Joints which added unnecessary complexity and slowed maintenance
- A RigidBody
ref
will now contain the instance of the RigidBody - A Collider
ref
will not contain the instance of the Collider (not an array, like before) - A Joint will now return a
RefObject
, and it'scurrent
value contains the instance of the Joint
- A RigidBody
- Providing some simple helper functions for quickly converting Rapier objects to ThreeJS ones.
quat
,vec3
,euler
. InstancedRigidBodies
is completely refactored to be a lot leaner- Now only takes one
instancedMesh
as child - Each instance can have it's own values, controlled by the
instances
array prop, which allows you to set RigidBody props accordingly
- Now only takes one
- Smaller footprint, easier to maintain
Changes
- 02055ed: Removed joints api, replaced with RefObjects containing the joint instances
- 25c4261: Update rapier to 0.11.1
- 02055ed: Refreshed InstancedRigidBody component with support for dynamic count and fine-grain control over each instance
- 02055ed: Remove RigidBody proxy apis for much needed simplification, add helper functions for dealing with Rapier math functions
- 02055ed: Collider refs now return a single collider rather than an array, as it should be
Migration guide
Ref changes
RigidBodies now contains a direct path to the rapier instance. The RigidBodyApi
proxy has been removed completely, which changes how values are returned. Math helpers are now included to make conversions from Rapier primitives easy.
Previously:
import { RigidBodyApi } from '@react-three/rapier'
...
const ref = useRef<RigidBodyApi>()
useEffect(() => {
if (ref.current) {
// get translation
const position = ref.current.translation() // Three.Vector3
// get raw instance
const instance = ref.current.raw(); // Rapier.RigidBody
// set translation
ref.current.setTranslation({x: 0, y: 10, z: 0})
}
}, [])
Now:
import { vec3, RapierRigidBody } from '@react-three/rapier'
...
const ref = useRef<RapierRigidBody>()
useEffect(() => {
if (ref.current) {
// get translation
const translation = ref.current.translation() // Rapier.Vector
const position = vec3(translation) // Three.Vector3
// get raw instance
const instance = ref.current; // Rapier.RigidBody
// set translation
ref.current.setTranslation({x: 0, y: 10, z: 0}, true)
}
}, [])
Similarly Colliders
now also provides a direct path to their Rapier representations in their ref
, which previously returned an array.
Previously:
const colliders = useRef()
useEffect(() => {
const collider = colliders.current[0] // Rapier.Collider
}, [])
return <BallCollider ref={colliders} />
Now:
import { RapierCollider } from '@react-three/rapier'
...
const collider = useRef<RapierCollider>()
useEffect(() => {
const collider = colliders.current // Rapier.Collider
}, [])
return <BallCollider ref={collider} />
Joint hooks
Joint hooks now return a RefObject
containing the instance of their Rapier representation.
Previously:
const joint = usePrismaticJoint(bodyA, bodyB, [[0,0,0],[0,0,0],[0,0,0]]) // JointApi
useEffect(() => {
// get raw instance
const rawJoint = joint.raw() // Rapier.PrismaticImpulseJoint
// Access joint api
joint.raw().configureMotor(2, 2, 10, 5);
}, [])
Now:
const joint = usePrismaticJoint() // ObjectRef<Rapier.PrismaticImpulseJoint>
useEffect(() => {
// get raw instance
const rawJoint = joint.current // Rapier.PrismaticImpulseJoint
// Access joint api
joint.current.configureMotor(2, 2, 10, 5);
}, [])
InstancedRigidBodies
InstancedRigidBodies is set up in a different way, providing a more streamlined dev experience and allowing for fine-grain control as well as dynamic instance ranges.
Now you provide individual RigidBodyProps for each instance using the instances
prop. Each instance are required to have a key
set.
Providing compound colliders to assign shape is now controlled via the colliderNodes
prop.
Previously:
const positions = Array.from({length: COUNT}).map(() => [1, 2, 3])
const rotations = Array.from({length: COUNT}).map(() => [3,2,1])
const scales = Array.from({length: COUNT}).map(() => [1,1,1])
<InstancedRigidBodies
colliders={false}
positions={positions}
rotations={rotations}
scales={scales}
>
<instancedMesh args={[null, null, COUNT]}>
...
</instancedMesh>
<BallCollider args={[1]} />
<CuboidCollider args={[1,2,1]} />
</InstancedRigidBodies>
Now:
const instances = Array.from({length: COUNT}).map((_, index) => ({
key: 'instance_' + index,
position: [1,2,3],
rotation: [1,2,3],
scale: [1,1,1],
restitution: Math.random(),
}))
<InstancedRigidBodies
colliders={false}
instances={instances}
colliderNodes={[
<BallCollider args={[1]} />,
<CuboidCollider args={[1,2,1]} />
]}
>
<instancedMesh args={[null, null, COUNT]}>
...
</instancedMesh>
</InstancedRigidBodies>
The count
of a instancedMesh
can be changed at runtime, provided there is an instance for it.