r3f-physics

安装量: 252
排名: #3475

安装

npx skills add https://github.com/enzed/r3f-skills --skill r3f-physics

React Three Fiber Physics (Rapier) Quick Start import { Canvas } from '@react-three/fiber' import { Physics, RigidBody, CuboidCollider } from '@react-three/rapier' import { Suspense } from 'react'

function Scene() { return ( {/ Falling box /}

      {/* Static ground */}
      <CuboidCollider position={[0, -2, 0]} args={[10, 0.5, 10]} />
    </Physics>
  </Suspense>

  <ambientLight />
  <directionalLight position={[5, 5, 5]} />
</Canvas>

) }

Installation npm install @react-three/rapier

Physics Component

The root component that creates the physics world.

import { Physics } from '@react-three/rapier'

{/* Physics objects */}

On-Demand Rendering

For performance optimization with static scenes:

{/* Physics only triggers render when bodies are active */}

RigidBody

Makes objects participate in physics simulation.

Basic Usage import { RigidBody } from '@react-three/rapier'

// Dynamic body (affected by forces/gravity)

// Fixed body (immovable)

// Kinematic body (moved programmatically)

RigidBody Types Type Description dynamic Affected by forces, gravity, collisions (default) fixed Immovable, infinite mass kinematicPosition Moved via setNextKinematicTranslation kinematicVelocity Moved via setNextKinematicRotation RigidBody Properties <RigidBody // Transform position={[0, 5, 0]} rotation={[0, Math.PI / 4, 0]} scale={1}

// Physics type="dynamic" mass={1} restitution={0.5} // Bounciness (0-1) friction={0.5} // Surface friction linearDamping={0} // Slows linear velocity angularDamping={0} // Slows angular velocity gravityScale={1} // Multiplier for gravity

// Collider generation colliders="cuboid" // "cuboid" | "ball" | "hull" | "trimesh" | false

// Constraints lockTranslations={false} // Prevent all translation lockRotations={false} // Prevent all rotation enabledTranslations={[true, true, true]} // Lock specific axes enabledRotations={[true, true, true]} // Lock specific axes

// Sleeping canSleep={true} ccd={false} // Continuous collision detection (fast objects)

// Naming (for collision events) name="player" />

Colliders Automatic Colliders

RigidBody auto-generates colliders from child meshes:

// Global default {/ Gets hull collider /}

// Per-body override

Collider Types Type Description Best For cuboid Box shape Boxes, crates ball Sphere shape Balls, spherical objects hull Convex hull Complex convex shapes trimesh Triangle mesh Concave/complex static geometry Manual Colliders import { CuboidCollider, BallCollider, CapsuleCollider, CylinderCollider, ConeCollider, HeightfieldCollider, TrimeshCollider, ConvexHullCollider } from '@react-three/rapier'

// Standalone collider (static)

// Inside RigidBody (compound collider)

{/ Additional colliders /}

// Collider args reference

Mesh Colliders

For complex shapes:

import { MeshCollider } from '@react-three/rapier'

// Convex hull for dynamic bodies

Applying Forces Using Refs import { RigidBody, RapierRigidBody } from '@react-three/rapier' import { useRef, useEffect } from 'react'

function ForcefulBox() { const rigidBody = useRef(null)

useEffect(() => { if (rigidBody.current) { // One-time impulse (instantaneous) rigidBody.current.applyImpulse({ x: 0, y: 10, z: 0 }, true)

  // Continuous force (apply each frame)
  rigidBody.current.addForce({ x: 0, y: 10, z: 0 }, true)

  // Torque (rotation)
  rigidBody.current.applyTorqueImpulse({ x: 0, y: 5, z: 0 }, true)
  rigidBody.current.addTorque({ x: 0, y: 5, z: 0 }, true)
}

}, [])

return ( ) }

In useFrame import { useFrame } from '@react-three/fiber'

function ContinuousForce() { const rigidBody = useRef(null)

useFrame(() => { if (rigidBody.current) { // Apply force every frame rigidBody.current.addForce({ x: 0, y: 20, z: 0 }, true) } })

return ( ) }

Getting/Setting Position import { vec3, quat, euler } from '@react-three/rapier'

function PositionControl() { const rigidBody = useRef(null)

const teleport = () => { if (rigidBody.current) { // Get current transform const position = vec3(rigidBody.current.translation()) const rotation = quat(rigidBody.current.rotation())

  // Set new transform
  rigidBody.current.setTranslation({ x: 0, y: 10, z: 0 }, true)
  rigidBody.current.setRotation({ x: 0, y: 0, z: 0, w: 1 }, true)

  // Set velocities
  rigidBody.current.setLinvel({ x: 0, y: 0, z: 0 }, true)
  rigidBody.current.setAngvel({ x: 0, y: 0, z: 0 }, true)
}

}

return ( ) }

Collision Events On RigidBody { console.log('Collision with', other.rigidBodyObject?.name) console.log('Contact point', manifold.solverContactPoint(0)) }} onCollisionExit={({ target, other }) => { console.log('Collision ended with', other.rigidBodyObject?.name) }} onContactForce={({ totalForce }) => { console.log('Contact force:', totalForce) }} onSleep={() => console.log('Body went to sleep')} onWake={() => console.log('Body woke up')}

On Colliders console.log('Collider hit')} onCollisionExit={(payload) => console.log('Collider exit')} />

Sensors

Detect overlaps without physical collision:

{/ Visible mesh /}

{/ Invisible sensor trigger /} console.log('Entered trigger zone')} onIntersectionExit={() => console.log('Exited trigger zone')} />

// Goal detection example console.log('Goal!')} />

Collision Groups

Control which objects can collide:

import { interactionGroups } from '@react-three/rapier'

// Group 0, interacts with groups 0, 1, 2

// Group 12, interacts with all groups

// Groups 0 and 5, only interacts with group 7

// On RigidBody (applies to all auto-generated colliders) ...

Joints

Connect rigid bodies together.

Fixed Joint

Bodies don't move relative to each other:

import { useFixedJoint, RapierRigidBody } from '@react-three/rapier'

function FixedJointExample() { const bodyA = useRef(null) const bodyB = useRef(null)

useFixedJoint(bodyA, bodyB, [ [0, 0, 0], // Position in bodyA's local space [0, 0, 0, 1], // Orientation in bodyA's local space (quaternion) [0, -1, 0], // Position in bodyB's local space [0, 0, 0, 1], // Orientation in bodyB's local space ])

return ( <> </> ) }

Revolute Joint (Hinge)

Rotation around one axis:

import { useRevoluteJoint } from '@react-three/rapier'

function HingeDoor() { const frame = useRef(null) const door = useRef(null)

useRevoluteJoint(frame, door, [ [0.5, 0, 0], // Joint position in frame's local space [-0.5, 0, 0], // Joint position in door's local space [0, 1, 0], // Rotation axis ])

return ( <> </> ) }

Spherical Joint (Ball-Socket)

Rotation in all directions:

import { useSphericalJoint } from '@react-three/rapier'

function BallJoint() { const bodyA = useRef(null) const bodyB = useRef(null)

useSphericalJoint(bodyA, bodyB, [ [0, -0.5, 0], // Position in bodyA's local space [0, 0.5, 0], // Position in bodyB's local space ])

return ( <> </> ) }

Prismatic Joint (Slider)

Translation along one axis:

import { usePrismaticJoint } from '@react-three/rapier'

function Slider() { const track = useRef(null) const slider = useRef(null)

usePrismaticJoint(track, slider, [ [0, 0, 0], // Position in track's local space [0, 0, 0], // Position in slider's local space [1, 0, 0], // Axis of translation ])

return ( <> </> ) }

Spring Joint

Elastic connection:

import { useSpringJoint } from '@react-three/rapier'

function SpringConnection() { const anchor = useRef(null) const ball = useRef(null)

useSpringJoint(anchor, ball, [ [0, 0, 0], // Position in anchor's local space [0, 0, 0], // Position in ball's local space 2, // Rest length 1000, // Stiffness 10, // Damping ])

return ( <> </> ) }

Rope Joint

Maximum distance constraint:

import { useRopeJoint } from '@react-three/rapier'

function RopeConnection() { const anchor = useRef(null) const weight = useRef(null)

useRopeJoint(anchor, weight, [ [0, 0, 0], // Position in anchor's local space [0, 0, 0], // Position in weight's local space 3, // Max distance (rope length) ])

return ( <> </> ) }

Motorized Joints import { useRevoluteJoint } from '@react-three/rapier' import { useFrame } from '@react-three/fiber'

function MotorizedWheel({ bodyA, bodyB }) { const joint = useRevoluteJoint(bodyA, bodyB, [ [0, 0, 0], [0, 0, 0], [0, 0, 1], // Rotation axis ])

useFrame(() => { if (joint.current) { // Configure motor: velocity, damping joint.current.configureMotorVelocity(10, 2) } })

return null }

Instanced Physics

Efficient physics for many identical objects:

import { InstancedRigidBodies, RapierRigidBody } from '@react-three/rapier' import { useRef, useMemo } from 'react'

function InstancedBalls() { const COUNT = 100 const rigidBodies = useRef(null)

const instances = useMemo(() => { return Array.from({ length: COUNT }, (_, i) => ({ key: ball-${i}, position: [ (Math.random() - 0.5) * 10, Math.random() * 10 + 5, (Math.random() - 0.5) * 10, ] as [number, number, number], rotation: [0, 0, 0] as [number, number, number], })) }, [])

return ( ) }

Accessing the World import { useRapier } from '@react-three/rapier' import { useEffect } from 'react'

function WorldAccess() { const { world, rapier } = useRapier()

useEffect(() => { // Change gravity world.setGravity({ x: 0, y: -20, z: 0 })

// Iterate over bodies
world.bodies.forEach((body) => {
  console.log(body.translation())
})

}, [world])

return null }

Manual Stepping function ManualStep() { const { step } = useRapier()

const advancePhysics = () => { step(1 / 60) // Advance by one frame }

return }

World Snapshots

Save and restore physics state:

function SnapshotSystem() { const { world, setWorld, rapier } = useRapier() const snapshot = useRef()

const saveState = () => { snapshot.current = world.takeSnapshot() }

const loadState = () => { if (snapshot.current) { setWorld(rapier.World.restoreSnapshot(snapshot.current)) } }

return ( <> </> ) }

Attractors

From @react-three/rapier-addons:

import { Attractor } from '@react-three/rapier-addons'

// Attract nearby bodies

// Repel bodies

// Selective attraction (only affect certain groups)

Debug Visualization {/ All colliders shown as wireframes /}

// Conditional debug ...

Performance Tips Use appropriate collider types: cuboid and ball are fastest Avoid trimesh for dynamic bodies: Use hull instead Enable sleeping: Bodies at rest stop computing Use collision groups: Reduce collision checks Limit active bodies: Too many dynamic bodies hurts performance Use instanced bodies: For many identical objects Fixed timestep: More stable than variable // Performance-optimized setup <Physics timeStep={1/60} colliders="cuboid" gravity={[0, -9.81, 0]}

{/ Use collision groups to limit checks /} ...

See Also r3f-fundamentals - R3F basics and hooks r3f-interaction - User input and controls r3f-animation - Combining physics with animation

返回排行榜