Skip to content

@react-three/[email protected]

Compare
Choose a tag to compare
@github-actions github-actions released this 05 Feb 12:53
· 104 commits to main since this release
d900f51

‼️ 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's current value contains the instance of the Joint
  • 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
  • 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.