import type Rapier from "@dimforge/rapier3d-compat"; import { Collider, ColliderHandle, RigidBody, RigidBodyHandle, SolverFlags, World } from "@dimforge/rapier3d-compat"; import React, { FC, ReactNode } from "react"; import { Matrix4, Object3D, Vector3 } from "three"; import { CollisionEnterHandler, CollisionExitHandler, ContactForceHandler, IntersectionEnterHandler, IntersectionExitHandler, RigidBodyAutoCollider, Vector3Tuple } from "../types.js"; export interface RigidBodyState { meshType: "instancedMesh" | "mesh"; rigidBody: RigidBody; object: Object3D; invertedWorldMatrix: Matrix4; setMatrix: (matrix: Matrix4) => void; getMatrix: (matrix: Matrix4) => Matrix4; /** * Required for instanced rigid bodies. */ scale: Vector3; isSleeping: boolean; } export type RigidBodyStateMap = Map; export type WorldStepCallback = (world: World) => void; export type WorldStepCallbackSet = Set<{ current: WorldStepCallback; }>; export type FilterContactPairCallback = (collider1: ColliderHandle, collider2: ColliderHandle, body1: RigidBodyHandle, body2: RigidBodyHandle) => SolverFlags | null; export type FilterIntersectionPairCallback = (collider1: ColliderHandle, collider2: ColliderHandle, body1: RigidBodyHandle, body2: RigidBodyHandle) => boolean; export type FilterContactPairCallbackSet = Set<{ current: FilterContactPairCallback; }>; export type FilterIntersectionPairCallbackSet = Set<{ current: FilterIntersectionPairCallback; }>; export interface ColliderState { collider: Collider; object: Object3D; /** * The parent of which this collider needs to base its * world position on, can be empty */ worldParent?: Object3D; } export type ColliderStateMap = Map; export interface RapierContext { /** * Used by the world to keep track of RigidBody states * @internal */ rigidBodyStates: RigidBodyStateMap; /** * Used by the world to keep track of Collider states * @internal */ colliderStates: ColliderStateMap; /** * Used by the world to keep track of RigidBody events * @internal */ rigidBodyEvents: EventMap; /** * Used by the world to keep track of Collider events * @internal */ colliderEvents: EventMap; /** * Default options for rigid bodies and colliders * @internal */ physicsOptions: { colliders: RigidBodyAutoCollider; }; /** * Triggered before the physics world is stepped * @internal */ beforeStepCallbacks: WorldStepCallbackSet; /** * Triggered after the physics world is stepped * @internal */ afterStepCallbacks: WorldStepCallbackSet; /** * Hooks to filter contact pairs * @internal */ filterContactPairHooks: FilterContactPairCallbackSet; /** * Hooks to filter intersection pairs * @internal */ filterIntersectionPairHooks: FilterIntersectionPairCallbackSet; /** * Direct access to the Rapier instance */ rapier: typeof Rapier; /** * The Rapier physics world */ world: World; /** * Can be used to overwrite the current World. Useful when working with snapshots. * * @example * ```tsx * import { useRapier } from '@react-three/rapier'; * * const SnapshottingComponent = () => { * const { world, setWorld, rapier } = useRapier(); * const worldSnapshot = useRef(); * * // Store the snapshot * const takeSnapshot = () => { * const snapshot = world.takeSnapshot() * worldSnapshot.current = snapshot * } * * // Create a new World from the snapshot, and replace the current one * const restoreSnapshot = () => { * setWorld(rapier.World.restoreSnapshot(worldSnapshot.current)) * } * * return <> * ... * ... * ... * ... * ... * * } * ``` */ setWorld: (world: World) => void; /** * If the physics simulation is paused */ isPaused: boolean; /** * Step the physics world one step * * @param deltaTime The delta time to step the world with * * @example * ``` * step(1/60) * ``` */ step: (deltaTime: number) => void; /** * Is debug mode enabled */ isDebug: boolean; } export declare const rapierContext: React.Context; export type EventMapValue = { onSleep?(): void; onWake?(): void; onCollisionEnter?: CollisionEnterHandler; onCollisionExit?: CollisionExitHandler; onIntersectionEnter?: IntersectionEnterHandler; onIntersectionExit?: IntersectionExitHandler; onContactForce?: ContactForceHandler; }; export type EventMap = Map; export interface PhysicsProps { children: ReactNode; /** * Set the gravity of the physics world * @defaultValue [0, -9.81, 0] */ gravity?: Vector3Tuple; /** * Amount of penetration the engine wont attempt to correct * @defaultValue 0.001 */ allowedLinearError?: number; /** * The number of solver iterations run by the constraints solver for calculating forces. * The greater this value is, the most rigid and realistic the physics simulation will be. * However a greater number of iterations is more computationally intensive. * * @defaultValue 4 */ numSolverIterations?: number; /** * Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration. * Increasing this parameter will improve stability of the simulation. It will have a lesser effect than * increasing `numSolverIterations` but is also less computationally expensive. * * @defaultValue 1 */ numInternalPgsIterations?: number; /** * The maximal distance separating two objects that will generate predictive contacts * * @defaultValue 0.002 * */ predictionDistance?: number; /** * Minimum number of dynamic bodies in each active island * * @defaultValue 128 */ minIslandSize?: number; /** * Maximum number of substeps performed by the solver * * @defaultValue 1 */ maxCcdSubsteps?: number; /** * Directly affects the `erp` (Error Reduction Parameter) which is the proportion (0 to 1) of the positional error to be corrected at each time step. * The higher this value is, the more the physics engine will try to correct errors. * * This prop is currently undocumented in the Rapier documentation. * * @see https://github.com/dimforge/rapier/pull/651 where this change was made to Rapier * @defaultValue 30 */ contactNaturalFrequency?: number; /** * The approximate size of most dynamic objects in the scene. * * This value is used internally to estimate some length-based tolerance. * This value can be understood as the number of units-per-meter in your physical world compared to a human-sized world in meter. * * @defaultValue 1 */ lengthUnit?: number; /** * Set the base automatic colliders for this physics world * All Meshes inside RigidBodies will generate a collider * based on this value, if not overridden. */ colliders?: RigidBodyAutoCollider; /** * Set the timestep for the simulation. * Setting this to a number (eg. 1/60) will run the * simulation at that framerate. Alternatively, you can set this to * "vary", which will cause the simulation to always synchronize with * the current frame delta times. * * @defaultValue 1/60 */ timeStep?: number | "vary"; /** * Pause the physics simulation * * @defaultValue false */ paused?: boolean; /** * Interpolate the world transform using the frame delta times. * Has no effect if timeStep is set to "vary". * * @defaultValue true **/ interpolate?: boolean; /** * The update priority at which the physics simulation should run. * Only used when `updateLoop` is set to "follow". * * @see https://docs.pmnd.rs/react-three-fiber/api/hooks#taking-over-the-render-loop * @defaultValue undefined */ updatePriority?: number; /** * Set the update loop strategy for the physics world. * * If set to "follow", the physics world will be stepped * in a `useFrame` callback, managed by @react-three/fiber. * You can use `updatePriority` prop to manage the scheduling. * * If set to "independent", the physics world will be stepped * in a separate loop, not tied to the render loop. * This is useful when using the "demand" `frameloop` strategy for the * @react-three/fiber ``. * * @see https://docs.pmnd.rs/react-three-fiber/advanced/scaling-performance#on-demand-rendering * @defaultValue "follow" */ updateLoop?: "follow" | "independent"; /** * Enable debug rendering of the physics world. * @defaultValue false */ debug?: boolean; } /** * The main physics component used to create a physics world. * @category Components */ export declare const Physics: FC;