Skip to main content

rapier2d/pipeline/
physics_world.rs

1use crate::alloc_prelude::*;
2use crate::dynamics::{
3    CCDSolver, GenericJoint, ImpulseJoint, ImpulseJointHandle, ImpulseJointSet,
4    IntegrationParameters, IslandManager, Multibody, MultibodyJointHandle, MultibodyJointSet,
5    MultibodyLink, MultibodyLinkId, RigidBody, RigidBodyHandle, RigidBodySet, SoftBindingError,
6    SoftBody, SoftBodyBuilder, SoftBodyHandle, SoftBodySet, SoftBodyTearEvent, SoftClusterRemoval,
7    SoftMeshBinding,
8};
9use crate::geometry::{
10    BroadPhaseBvh, Collider, ColliderHandle, ColliderSet, ContactPair, DefaultBroadPhase,
11    NarrowPhase,
12};
13use crate::math::{DIM, Real, Vector};
14use crate::pipeline::{
15    CollisionPipeline, EventHandler, PhysicsHooks, PhysicsPipeline, Quarantine, QueryFilter,
16    QueryPipeline,
17};
18use parry::bounding_volume::{Aabb, BoundingVolume};
19use parry::partitioning::BvhNode;
20use parry::query::details::ShapeCastOptions;
21use parry::query::{NonlinearRigidMotion, RayCast, ShapeCastHit};
22use parry::shape::{FeatureId, Shape};
23
24use crate::geometry::{PointProjection, Ray, RayIntersection};
25use crate::math::Pose;
26
27#[cfg(feature = "debug-render")]
28use crate::pipeline::{DebugRenderBackend, DebugRenderPipeline};
29
30/// A convenience wrapper that bundles all the Rapier physics state into a single struct.
31///
32/// Rapier intentionally splits its state across many structs (`RigidBodySet`, `ColliderSet`,
33/// `NarrowPhase`, etc.) to give you fine-grained control over borrowing. This is important
34/// for advanced use cases, but it makes simple setups verbose.
35///
36/// `PhysicsWorld` gives you a single struct for the common case. All fields are `pub`, so
37/// you can always reach in and borrow individual fields when the borrow checker requires it.
38///
39/// # Example
40/// ```
41/// # use rapier3d::prelude::*;
42/// let mut world = PhysicsWorld::default();
43///
44/// // Create a ground plane
45/// let (_ground, _) = world.insert(
46///     RigidBodyBuilder::fixed(),
47///     ColliderBuilder::cuboid(10.0, 0.1, 10.0),
48/// );
49///
50/// // Create a falling ball
51/// let (ball, _) = world.insert(
52///     RigidBodyBuilder::dynamic().translation(Vector::new(0.0, 5.0, 0.0)),
53///     ColliderBuilder::ball(0.5),
54/// );
55///
56/// // Simulate 100 steps
57/// for _ in 0..100 {
58///     world.step();
59/// }
60///
61/// println!("Ball position: {:?}", world.bodies[ball].translation());
62/// ```
63#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
64pub struct PhysicsWorld {
65    /// Gravity applied to all dynamic bodies each step.
66    pub gravity: Vector,
67    /// Parameters controlling the simulation (timestep, solver iterations, etc.).
68    pub integration_parameters: IntegrationParameters,
69    /// The main simulation pipeline that orchestrates each physics step.
70    #[cfg_attr(feature = "serde-serialize", serde(skip))]
71    pub physics_pipeline: PhysicsPipeline,
72    /// Workspace for collision-only updates that do not integrate positions or solve constraints.
73    #[cfg_attr(feature = "serde-serialize", serde(skip))]
74    pub collision_pipeline: CollisionPipeline,
75    /// Manages active/sleeping body groups (islands) for efficient simulation.
76    pub islands: IslandManager,
77    /// The broad-phase acceleration structure for fast spatial queries.
78    pub broad_phase: BroadPhaseBvh,
79    /// Precise contact and intersection detection between collider pairs.
80    pub narrow_phase: NarrowPhase,
81    /// All rigid bodies in this world.
82    pub bodies: RigidBodySet,
83    /// All colliders (collision shapes) in this world.
84    pub colliders: ColliderSet,
85    /// All impulse-based joints (hinges, springs, ropes, etc.).
86    pub impulse_joints: ImpulseJointSet,
87    /// All multibody joints (kinematic chains, articulations).
88    pub multibody_joints: MultibodyJointSet,
89    /// All soft bodies (deformable particle bodies).
90    pub soft_bodies: SoftBodySet,
91    /// The continuous collision detection solver.
92    ///
93    /// Workspace only: not part of a snapshot (see the type docs).
94    #[cfg_attr(feature = "serde-serialize", serde(skip))]
95    pub ccd_solver: CCDSolver,
96}
97
98impl Default for PhysicsWorld {
99    fn default() -> Self {
100        Self {
101            gravity: Vector::Y * -9.81,
102            integration_parameters: IntegrationParameters::default(),
103            physics_pipeline: PhysicsPipeline::new(),
104            collision_pipeline: CollisionPipeline::new(),
105            islands: IslandManager::new(),
106            broad_phase: DefaultBroadPhase::default(),
107            narrow_phase: NarrowPhase::new(),
108            bodies: RigidBodySet::new(),
109            colliders: ColliderSet::new(),
110            impulse_joints: ImpulseJointSet::new(),
111            multibody_joints: MultibodyJointSet::new(),
112            soft_bodies: SoftBodySet::new(),
113            ccd_solver: CCDSolver::new(),
114        }
115    }
116}
117
118impl PhysicsWorld {
119    /// Creates a new physics world with default parameters and gravity `(0, -9.81, 0)`.
120    pub fn new() -> Self {
121        Self::default()
122    }
123
124    // ── Simulation ──────────────────────────────────────────────────────
125
126    /// Advance the simulation by one timestep, using no hooks and no event handler.
127    ///
128    /// This is the simplest way to step. If you need collision events or physics hooks,
129    /// use [`step_with_events`](Self::step_with_events).
130    pub fn step(&mut self) {
131        self.step_with_events(&(), &());
132    }
133
134    /// Advance the simulation by one timestep with custom physics hooks and event handling.
135    ///
136    /// # Example
137    /// ```
138    /// # use rapier3d::prelude::*;
139    /// # let mut world = PhysicsWorld::default();
140    /// # use std::sync::mpsc::channel;
141    /// let (collision_send, collision_recv) = channel();
142    /// let (contact_force_send, contact_force_recv) = channel();
143    /// let (soft_body_tear_send, soft_body_tear_recv) = channel();
144    /// let event_handler =
145    ///     ChannelEventCollector::new(collision_send, contact_force_send, soft_body_tear_send);
146    ///
147    /// world.step_with_events(&(), &event_handler);
148    ///
149    /// while let Ok(event) = collision_recv.try_recv() {
150    ///     println!("Collision event: {:?}", event);
151    /// }
152    /// ```
153    pub fn step_with_events(&mut self, hooks: &dyn PhysicsHooks, events: &dyn EventHandler) {
154        self.physics_pipeline.step(
155            self.gravity,
156            &self.integration_parameters,
157            &mut self.islands,
158            &mut self.broad_phase,
159            &mut self.narrow_phase,
160            &mut self.bodies,
161            &mut self.colliders,
162            &mut self.impulse_joints,
163            &mut self.multibody_joints,
164            &mut self.soft_bodies,
165            &mut self.ccd_solver,
166            hooks,
167            events,
168        );
169    }
170
171    /// Update broad-phase and narrow-phase collision detection without advancing simulation.
172    ///
173    /// Uses the prediction distance from this world's integration parameters. This is useful
174    /// after editing transforms when contacts and scene queries must be refreshed immediately.
175    pub fn detect_collisions(&mut self, hooks: &dyn PhysicsHooks, events: &dyn EventHandler) {
176        self.collision_pipeline.step(
177            self.integration_parameters.prediction_distance(),
178            &mut self.islands,
179            &mut self.broad_phase,
180            &mut self.narrow_phase,
181            &mut self.bodies,
182            &mut self.colliders,
183            hooks,
184            events,
185        );
186    }
187
188    /// The bodies and colliders automatically disabled during the last step because their
189    /// state became non-finite; see [`Quarantine`].
190    pub fn quarantine(&self) -> &Quarantine {
191        self.physics_pipeline.quarantine()
192    }
193
194    // ── Rigid bodies ────────────────────────────────────────────────────
195
196    /// Insert a rigid body with an attached collider, and return both handles.
197    ///
198    /// This bundles the two most common setup steps — creating a body and attaching
199    /// its collider — into a single call. For the rare case of a rigid body without
200    /// any collider (typically an anchor body for joints), use
201    /// [`insert_body`](Self::insert_body) instead. For compound bodies with multiple
202    /// colliders, pass the first collider here and use
203    /// [`insert_collider`](Self::insert_collider) with `Some(body_handle)` for the rest.
204    ///
205    /// # Example
206    /// ```
207    /// # use rapier3d::prelude::*;
208    /// # let mut world = PhysicsWorld::default();
209    /// let (body, collider) = world.insert(
210    ///     RigidBodyBuilder::dynamic().translation(Vector::new(0.0, 5.0, 0.0)),
211    ///     ColliderBuilder::ball(0.5),
212    /// );
213    /// ```
214    pub fn insert(
215        &mut self,
216        body: impl Into<RigidBody>,
217        collider: impl Into<Collider>,
218    ) -> (RigidBodyHandle, ColliderHandle) {
219        let body_handle = self.bodies.insert(body);
220        let collider_handle =
221            self.colliders
222                .insert_with_parent(collider, body_handle, &mut self.bodies);
223        (body_handle, collider_handle)
224    }
225
226    /// Insert a rigid body without any collider, and return its handle.
227    ///
228    /// Most bodies should be inserted together with a collider — prefer
229    /// [`insert`](Self::insert) when possible. Use this method for bodies that
230    /// truly don't need a collider, such as anchor bodies used purely as joint
231    /// attachment points.
232    ///
233    /// # Example
234    /// ```
235    /// # use rapier3d::prelude::*;
236    /// # let mut world = PhysicsWorld::default();
237    /// let anchor = world.insert_body(RigidBodyBuilder::fixed());
238    /// ```
239    pub fn insert_body(&mut self, body: impl Into<RigidBody>) -> RigidBodyHandle {
240        self.bodies.insert(body)
241    }
242
243    /// Remove a rigid body and all its attached colliders and joints.
244    ///
245    /// Returns the removed body, or `None` if the handle was invalid.
246    pub fn remove_body(&mut self, handle: RigidBodyHandle) -> Option<RigidBody> {
247        self.remove_body_with_colliders(handle, true)
248    }
249
250    /// Remove a rigid body and its joints, optionally preserving attached colliders.
251    ///
252    /// Preserved colliders become standalone colliders. Returns `None` for an invalid handle.
253    pub fn remove_body_with_colliders(
254        &mut self,
255        handle: RigidBodyHandle,
256        remove_attached_colliders: bool,
257    ) -> Option<RigidBody> {
258        self.bodies.remove(
259            handle,
260            &mut self.islands,
261            &mut self.colliders,
262            &mut self.impulse_joints,
263            &mut self.multibody_joints,
264            &mut self.soft_bodies,
265            remove_attached_colliders,
266        )
267    }
268
269    /// Wake a sleeping body, forcing it back into the active simulation.
270    ///
271    /// Useful after manually moving a body, applying forces, or otherwise wanting to make
272    /// sure it gets simulated on the next step. No-op for already-awake bodies, and for
273    /// fixed bodies (which don't sleep).
274    ///
275    /// # Parameters
276    /// * `strong` — if `true`, the body is guaranteed to stay awake for several frames.
277    ///   If `false`, it may sleep again immediately if sleep conditions are met.
278    pub fn wake_up(&mut self, handle: RigidBodyHandle, strong: bool) {
279        self.islands.wake_up(&mut self.bodies, handle, strong);
280    }
281
282    /// Wake every sleeping body in the world.
283    pub fn wake_up_all(&mut self, strong: bool) {
284        let handles: Vec<_> = self.bodies.iter().map(|(h, _)| h).collect();
285        for handle in handles {
286            self.islands.wake_up(&mut self.bodies, handle, strong);
287        }
288    }
289
290    // ── Colliders ───────────────────────────────────────────────────────
291
292    /// Insert a collider, optionally attached to a rigid body, and return its handle.
293    ///
294    /// Pass `Some(parent)` to attach the collider to a rigid body — its position will
295    /// then be interpreted relative to its parent. Pass `None` for a standalone collider,
296    /// useful for static collision geometry or sensors that don't need a rigid body.
297    ///
298    /// # Example
299    /// ```
300    /// # use rapier3d::prelude::*;
301    /// # let mut world = PhysicsWorld::default();
302    /// let body = world.insert_body(RigidBodyBuilder::dynamic());
303    ///
304    /// // Attached collider.
305    /// let attached = world.insert_collider(ColliderBuilder::ball(0.5), Some(body));
306    ///
307    /// // Standalone collider (e.g. static geometry).
308    /// let standalone = world.insert_collider(ColliderBuilder::cuboid(10.0, 0.1, 10.0), None);
309    /// ```
310    pub fn insert_collider(
311        &mut self,
312        collider: impl Into<Collider>,
313        parent: Option<RigidBodyHandle>,
314    ) -> ColliderHandle {
315        match parent {
316            Some(parent) => self
317                .colliders
318                .insert_with_parent(collider, parent, &mut self.bodies),
319            None => self.colliders.insert(collider),
320        }
321    }
322
323    /// Remove a collider from the world.
324    ///
325    /// Returns the removed collider, or `None` if the handle was invalid.
326    pub fn remove_collider(&mut self, handle: ColliderHandle) -> Option<Collider> {
327        self.colliders.remove(
328            handle,
329            &mut self.islands,
330            &mut self.bodies,
331            &mut self.soft_bodies,
332            true,
333        )
334    }
335
336    // ── Impulse joints ──────────────────────────────────────────────────
337
338    /// Insert an impulse joint between two bodies and return its handle.
339    ///
340    /// # Example
341    /// ```
342    /// # use rapier3d::prelude::*;
343    /// # let mut world = PhysicsWorld::default();
344    /// let body1 = world.insert_body(RigidBodyBuilder::dynamic());
345    /// let body2 = world.insert_body(RigidBodyBuilder::dynamic());
346    /// let joint = world.insert_impulse_joint(body1, body2, RevoluteJointBuilder::new(Vector::Z));
347    /// ```
348    pub fn insert_impulse_joint(
349        &mut self,
350        body1: RigidBodyHandle,
351        body2: RigidBodyHandle,
352        joint: impl Into<GenericJoint>,
353    ) -> ImpulseJointHandle {
354        self.impulse_joints.insert(body1, body2, joint, true)
355    }
356
357    /// Remove an impulse joint.
358    ///
359    /// Returns the removed joint data, or `None` if the handle was invalid.
360    pub fn remove_impulse_joint(&mut self, handle: ImpulseJointHandle) -> Option<GenericJoint> {
361        self.impulse_joints.remove(handle, true).map(|j| j.data)
362    }
363
364    /// Iterate over every impulse joint in the world as `(handle, &joint)` pairs.
365    pub fn impulse_joints(&self) -> impl Iterator<Item = (ImpulseJointHandle, &ImpulseJoint)> {
366        self.impulse_joints.iter()
367    }
368
369    /// Iterate over every impulse joint attached to the given rigid body.
370    ///
371    /// Each item is `(body1, body2, joint_handle, &joint)`. `body1` and `body2` are the
372    /// joint's endpoints — one of them is always `body`, the other is the neighbor.
373    pub fn impulse_joints_with(
374        &self,
375        body: RigidBodyHandle,
376    ) -> impl Iterator<
377        Item = (
378            RigidBodyHandle,
379            RigidBodyHandle,
380            ImpulseJointHandle,
381            &ImpulseJoint,
382        ),
383    > {
384        self.impulse_joints.attached_joints(body)
385    }
386
387    // ── Multibody joints ────────────────────────────────────────────────
388
389    /// Insert a multibody joint between two bodies and return its handle.
390    ///
391    /// Returns `None` if the joint would create an invalid kinematic chain (e.g. a cycle).
392    pub fn insert_multibody_joint(
393        &mut self,
394        body1: RigidBodyHandle,
395        body2: RigidBodyHandle,
396        joint: impl Into<GenericJoint>,
397    ) -> Option<MultibodyJointHandle> {
398        self.multibody_joints.insert(body1, body2, joint, true)
399    }
400
401    /// Remove a multibody joint.
402    pub fn remove_multibody_joint(&mut self, handle: MultibodyJointHandle) {
403        self.multibody_joints.remove(handle, true);
404    }
405
406    /// Iterate over every multibody joint in the world.
407    ///
408    /// Each item is `(joint_handle, &link_id, &multibody, &link)`.
409    pub fn multibody_joints(
410        &self,
411    ) -> impl Iterator<
412        Item = (
413            MultibodyJointHandle,
414            &MultibodyLinkId,
415            &Multibody,
416            &MultibodyLink,
417        ),
418    > {
419        self.multibody_joints.iter()
420    }
421
422    /// Iterate over every multibody joint attached to the given rigid body.
423    ///
424    /// Each item is `(body1, body2, joint_handle)`. `body1` and `body2` are the joint's
425    /// endpoints — one of them is always `body`, the other is the neighbor.
426    pub fn multibody_joints_with(
427        &self,
428        body: RigidBodyHandle,
429    ) -> impl Iterator<Item = (RigidBodyHandle, RigidBodyHandle, MultibodyJointHandle)> + '_ {
430        self.multibody_joints.attached_joints(body)
431    }
432
433    // ── Soft bodies ─────────────────────────────────────────────────────
434
435    /// Insert a soft body and return its handle; this creates its hidden root rigid body and its
436    /// colliders (a deformable surface, or one ball per surface particle), which
437    /// [`Self::remove_soft_body`] removes.
438    pub fn insert_soft_body(&mut self, soft_body: SoftBodyBuilder) -> SoftBodyHandle {
439        self.soft_bodies
440            .insert(soft_body, &mut self.bodies, &mut self.colliders)
441    }
442
443    /// Inserts a collider holding a soft body's deformable collision mesh, bound to the cluster
444    /// of `parent` (a cluster proxy: see
445    /// [`ColliderSet::insert_deformable`](crate::geometry::ColliderSet::insert_deformable)).
446    pub fn insert_deformable(
447        &mut self,
448        collider: impl Into<Collider>,
449        binding: SoftMeshBinding,
450        parent: RigidBodyHandle,
451    ) -> Result<ColliderHandle, SoftBindingError> {
452        self.colliders.insert_deformable(
453            collider,
454            binding,
455            parent,
456            &mut self.bodies,
457            &mut self.soft_bodies,
458        )
459    }
460
461    /// Remove a soft body, its root rigid body and its colliders.
462    pub fn remove_soft_body(&mut self, handle: SoftBodyHandle) -> Option<SoftBody> {
463        self.soft_bodies.remove(
464            handle,
465            &mut self.islands,
466            &mut self.bodies,
467            &mut self.colliders,
468            &mut self.impulse_joints,
469            &mut self.multibody_joints,
470        )
471    }
472
473    /// Cuts a soft body along a blade (a world segment in 2D, a triangle in 3D) at once, without
474    /// removing any material (see [`SoftBodySet::cut`]). Returns the tear event, or `None` when
475    /// the cut changed nothing.
476    pub fn cut_soft_body(
477        &mut self,
478        handle: SoftBodyHandle,
479        blade: &[Vector; DIM],
480    ) -> Option<SoftBodyTearEvent> {
481        self.soft_bodies.cut(
482            handle,
483            blade,
484            &mut self.islands,
485            &mut self.bodies,
486            &mut self.colliders,
487            &mut self.impulse_joints,
488            &mut self.multibody_joints,
489        )
490    }
491
492    /// Tears a soft body at once along the given edges and through the given cells, without
493    /// removing any material (see [`SoftBodySet::tear`] and [`SoftBody::tear_edge`]). Returns
494    /// the tear event, or `None` when nothing changed.
495    pub fn tear_soft_body(
496        &mut self,
497        handle: SoftBodyHandle,
498        edges: &[u32],
499        cells: &[u32],
500    ) -> Option<SoftBodyTearEvent> {
501        self.soft_bodies.tear(
502            handle,
503            edges,
504            cells,
505            &mut self.islands,
506            &mut self.bodies,
507            &mut self.colliders,
508            &mut self.impulse_joints,
509            &mut self.multibody_joints,
510        )
511    }
512
513    /// Adds a cluster to a soft body: a set of its particles backed by a fresh proxy rigid
514    /// body ([`crate::dynamics::RigidBodyType::SoftFrame`]) that impulse joints and colliders
515    /// can attach to.
516    /// Returns the cluster's index (see [`SoftBodySet::add_cluster`]).
517    pub fn add_soft_body_cluster(
518        &mut self,
519        handle: SoftBodyHandle,
520        particles: &[u32],
521    ) -> Option<u32> {
522        self.soft_bodies
523            .add_cluster(handle, particles, &mut self.bodies, &mut self.colliders)
524    }
525
526    /// Removes a soft body's cluster, its proxy rigid body, and the particles only that
527    /// cluster covered (see [`SoftBodySet::remove_cluster`]). Removing the proxy from the
528    /// [`RigidBodySet`] is equivalent.
529    pub fn remove_soft_body_cluster(
530        &mut self,
531        handle: SoftBodyHandle,
532        cluster: u32,
533    ) -> Option<SoftClusterRemoval> {
534        self.soft_bodies.remove_cluster(
535            handle,
536            cluster,
537            &mut self.islands,
538            &mut self.bodies,
539            &mut self.colliders,
540            &mut self.impulse_joints,
541            &mut self.multibody_joints,
542        )
543    }
544
545    /// Iterate over every soft body in the world.
546    pub fn soft_bodies(&self) -> impl Iterator<Item = (SoftBodyHandle, &SoftBody)> {
547        self.soft_bodies.iter()
548    }
549
550    // ── Scene queries ───────────────────────────────────────────────────
551
552    /// Get a [`QueryPipeline`] for performing spatial queries (raycasts, shape casts, etc.).
553    ///
554    /// # Example
555    /// ```
556    /// # use rapier3d::prelude::*;
557    /// # let mut world = PhysicsWorld::default();
558    /// # let (ground, _) = world.insert(
559    /// #     RigidBodyBuilder::fixed(),
560    /// #     ColliderBuilder::cuboid(10.0, 0.1, 10.0),
561    /// # );
562    /// # world.step();
563    /// let query_pipeline = world.query_pipeline();
564    /// let ray = Ray::new(Vector::new(0.0, 10.0, 0.0), Vector::new(0.0, -1.0, 0.0));
565    /// if let Some((handle, toi)) = query_pipeline.cast_ray(&ray, Real::MAX, true) {
566    ///     println!("Hit {:?} at distance {}", handle, toi);
567    /// }
568    /// ```
569    pub fn query_pipeline(&self) -> QueryPipeline<'_> {
570        self.query_pipeline_with_filter(QueryFilter::default())
571    }
572
573    /// Get a [`QueryPipeline`] with a custom [`QueryFilter`].
574    pub fn query_pipeline_with_filter<'a>(&'a self, filter: QueryFilter<'a>) -> QueryPipeline<'a> {
575        self.broad_phase.as_query_pipeline(
576            self.narrow_phase.query_dispatcher(),
577            &self.bodies,
578            &self.colliders,
579            filter,
580        )
581    }
582
583    /// Cast a ray and return the first collider hit.
584    ///
585    /// Shorthand for `world.query_pipeline_with_filter(filter).cast_ray(...)`.
586    ///
587    /// Returns `Some((collider_handle, distance))`, or `None` if nothing was hit.
588    /// Pass [`QueryFilter::default()`] to consider every collider.
589    pub fn cast_ray<'a>(
590        &'a self,
591        ray: &Ray,
592        max_toi: Real,
593        solid: bool,
594        filter: QueryFilter<'a>,
595    ) -> Option<(ColliderHandle, Real)> {
596        self.query_pipeline_with_filter(filter)
597            .cast_ray(ray, max_toi, solid)
598    }
599
600    /// Cast a ray and return the first hit with surface normal information.
601    ///
602    /// Shorthand for `world.query_pipeline_with_filter(filter).cast_ray_and_get_normal(...)`.
603    pub fn cast_ray_and_get_normal<'a>(
604        &'a self,
605        ray: &Ray,
606        max_toi: Real,
607        solid: bool,
608        filter: QueryFilter<'a>,
609    ) -> Option<(ColliderHandle, RayIntersection)> {
610        self.query_pipeline_with_filter(filter)
611            .cast_ray_and_get_normal(ray, max_toi, solid)
612    }
613
614    /// Cast (sweep) a shape through the world and return the first collider hit.
615    ///
616    /// Shorthand for `world.query_pipeline_with_filter(filter).cast_shape(...)`.
617    pub fn cast_shape<'a>(
618        &'a self,
619        shape_pos: &Pose,
620        shape_vel: Vector,
621        shape: &dyn Shape,
622        options: ShapeCastOptions,
623        filter: QueryFilter<'a>,
624    ) -> Option<(ColliderHandle, ShapeCastHit)> {
625        self.query_pipeline_with_filter(filter)
626            .cast_shape(shape_pos, shape_vel, shape, options)
627    }
628
629    /// Cast a shape with a nonlinear motion and return the first collider hit.
630    ///
631    /// Shorthand for `world.query_pipeline_with_filter(filter).cast_shape_nonlinear(...)`.
632    pub fn cast_shape_nonlinear<'a>(
633        &'a self,
634        shape_motion: &NonlinearRigidMotion,
635        shape: &dyn Shape,
636        start_time: Real,
637        end_time: Real,
638        stop_at_penetration: bool,
639        filter: QueryFilter<'a>,
640    ) -> Option<(ColliderHandle, ShapeCastHit)> {
641        self.query_pipeline_with_filter(filter)
642            .cast_shape_nonlinear(
643                shape_motion,
644                shape,
645                start_time,
646                end_time,
647                stop_at_penetration,
648            )
649    }
650
651    /// Find the closest point on any collider to the given point.
652    ///
653    /// Shorthand for `world.query_pipeline_with_filter(filter).project_point(...)`.
654    pub fn project_point<'a>(
655        &'a self,
656        point: Vector,
657        max_dist: Real,
658        solid: bool,
659        filter: QueryFilter<'a>,
660    ) -> Option<(ColliderHandle, PointProjection)> {
661        self.query_pipeline_with_filter(filter)
662            .project_point(point, max_dist, solid)
663    }
664
665    /// Project a point onto the closest collider and also return the geometric feature
666    /// (vertex, edge, or face) that contains the projection.
667    ///
668    /// Shorthand for
669    /// `world.query_pipeline_with_filter(filter).project_point_and_get_feature(...)`.
670    pub fn project_point_and_get_feature<'a>(
671        &'a self,
672        point: Vector,
673        filter: QueryFilter<'a>,
674        max_dist: Real,
675    ) -> Option<(ColliderHandle, PointProjection, FeatureId)> {
676        self.query_pipeline_with_filter(filter)
677            .project_point_and_get_feature(point, max_dist)
678    }
679
680    /// Iterate over every collider that the given ray passes through.
681    ///
682    /// Unlike [`cast_ray`](Self::cast_ray) which stops at the first hit, this yields
683    /// every collider along the ray's path. Each item is
684    /// `(handle, &collider, intersection)`.
685    pub fn intersect_ray<'a>(
686        &'a self,
687        ray: Ray,
688        max_toi: Real,
689        solid: bool,
690        filter: QueryFilter<'a>,
691    ) -> impl Iterator<Item = (ColliderHandle, &'a Collider, RayIntersection)> + 'a {
692        let bvh = &self.broad_phase.tree;
693        let bodies = &self.bodies;
694        let colliders = &self.colliders;
695        bvh.leaves(move |node: &BvhNode| node.aabb().intersects_local_ray(&ray, max_toi))
696            .filter_map(move |leaf| {
697                let (co, co_handle) = colliders.get_unknown_gen(leaf)?;
698                if filter.test(bodies, co_handle, co) {
699                    let intersection =
700                        co.shape
701                            .cast_ray_and_get_normal(co.position(), &ray, max_toi, solid)?;
702                    Some((co_handle, co, intersection))
703                } else {
704                    None
705                }
706            })
707    }
708
709    /// Iterate over every collider that contains the given point.
710    ///
711    /// Each item is `(handle, &collider)`.
712    pub fn intersect_point<'a>(
713        &'a self,
714        point: Vector,
715        filter: QueryFilter<'a>,
716    ) -> impl Iterator<Item = (ColliderHandle, &'a Collider)> + 'a {
717        let bvh = &self.broad_phase.tree;
718        let bodies = &self.bodies;
719        let colliders = &self.colliders;
720        bvh.leaves(move |node: &BvhNode| node.aabb().contains_local_point(point))
721            .filter_map(move |leaf| {
722                let (co, co_handle) = colliders.get_unknown_gen(leaf)?;
723                if filter.test(bodies, co_handle, co)
724                    && co.shape.contains_point(co.position(), point)
725                {
726                    Some((co_handle, co))
727                } else {
728                    None
729                }
730            })
731    }
732
733    /// Iterate over every collider whose shape intersects the given shape positioned
734    /// at `shape_pos`.
735    ///
736    /// Each item is `(handle, &collider)`.
737    pub fn intersect_shape<'a>(
738        &'a self,
739        shape_pos: Pose,
740        shape: &'a dyn Shape,
741        filter: QueryFilter<'a>,
742    ) -> impl Iterator<Item = (ColliderHandle, &'a Collider)> + 'a {
743        let bvh = &self.broad_phase.tree;
744        let bodies = &self.bodies;
745        let colliders = &self.colliders;
746        let dispatcher = self.narrow_phase.query_dispatcher();
747        let shape_aabb = shape.compute_aabb(&shape_pos);
748        bvh.leaves(move |node: &BvhNode| node.aabb().intersects(&shape_aabb))
749            .filter_map(move |leaf| {
750                let (co, co_handle) = colliders.get_unknown_gen(leaf)?;
751                if filter.test(bodies, co_handle, co) {
752                    let pos12 = shape_pos.inv_mul(co.position());
753                    if dispatcher
754                        .intersection_test(&pos12, shape, co.shape())
755                        .is_ok_and(|hit| hit.intersecting)
756                    {
757                        return Some((co_handle, co));
758                    }
759                }
760                None
761            })
762    }
763
764    /// Iterate over every collider whose stored AABB intersects the given AABB.
765    ///
766    /// This is *conservative*: the AABBs used are the ones in the broad-phase BVH,
767    /// not freshly recomputed collider AABBs. Useful for cheap, broad-strokes
768    /// proximity queries.
769    ///
770    /// Each item is `(handle, &collider)`.
771    pub fn intersect_aabb_conservative<'a>(
772        &'a self,
773        aabb: Aabb,
774        filter: QueryFilter<'a>,
775    ) -> impl Iterator<Item = (ColliderHandle, &'a Collider)> + 'a {
776        let bvh = &self.broad_phase.tree;
777        let bodies = &self.bodies;
778        let colliders = &self.colliders;
779        bvh.leaves(move |node: &BvhNode| node.aabb().intersects(&aabb))
780            .filter_map(move |leaf| {
781                let (co, co_handle) = colliders.get_unknown_gen(leaf)?;
782                if filter.test(bodies, co_handle, co) {
783                    Some((co_handle, co))
784                } else {
785                    None
786                }
787            })
788    }
789
790    // ── Contact / intersection queries (from NarrowPhase) ───────────────
791
792    /// Get the contact pair between two specific colliders, if it exists.
793    ///
794    /// Returns `None` if the two colliders are not in contact or not neighbors
795    /// in the broad-phase.
796    pub fn contact_pair(
797        &self,
798        collider1: ColliderHandle,
799        collider2: ColliderHandle,
800    ) -> Option<&ContactPair> {
801        self.narrow_phase.contact_pair(collider1, collider2)
802    }
803
804    /// Iterate over all contact pairs involving the given collider.
805    pub fn contact_pairs_with(
806        &self,
807        collider: ColliderHandle,
808    ) -> impl Iterator<Item = &ContactPair> {
809        self.narrow_phase.contact_pairs_with(collider)
810    }
811
812    /// Iterate over all contact pairs in the world.
813    pub fn contact_pairs(&self) -> impl Iterator<Item = &ContactPair> {
814        self.narrow_phase.contact_pairs()
815    }
816
817    /// Check if two specific colliders are intersecting (for sensor colliders).
818    ///
819    /// Returns `None` if the pair doesn't exist, `Some(true)` if intersecting.
820    pub fn intersection_pair(
821        &self,
822        collider1: ColliderHandle,
823        collider2: ColliderHandle,
824    ) -> Option<bool> {
825        self.narrow_phase.intersection_pair(collider1, collider2)
826    }
827
828    /// Iterate over all intersection pairs involving the given collider.
829    ///
830    /// Each item is `(handle_a, &collider_a, handle_b, &collider_b, intersecting)`.
831    ///
832    /// # Mutable access
833    ///
834    /// There is no `_mut` variant of this method: the same collider may appear in
835    /// several intersection pairs, so a safe `Iterator` yielding `&mut Collider` from
836    /// a pair iterator isn't possible in stable Rust. To mutate colliders based on
837    /// intersection pairs, iterate here to collect the handles you care about, then
838    /// call [`ColliderSet::get_pair_mut`](crate::geometry::ColliderSet::get_pair_mut)
839    /// on [`self.colliders`](Self#structfield.colliders):
840    ///
841    /// ```
842    /// # use rapier3d::prelude::*;
843    /// # let mut world = PhysicsWorld::default();
844    /// # let collider = ColliderHandle::invalid();
845    /// let pairs: Vec<_> = world
846    ///     .intersection_pairs_with(collider)
847    ///     .map(|(h1, _, h2, _, _)| (h1, h2))
848    ///     .collect();
849    /// for (h1, h2) in pairs {
850    ///     if let (Some(c1), Some(c2)) = world.colliders.get_pair_mut(h1, h2) {
851    ///         // mutate c1 and c2…
852    ///         # let _ = (c1, c2);
853    ///     }
854    /// }
855    /// ```
856    pub fn intersection_pairs_with(
857        &self,
858        collider: ColliderHandle,
859    ) -> impl Iterator<Item = (ColliderHandle, &Collider, ColliderHandle, &Collider, bool)> + '_
860    {
861        self.narrow_phase
862            .intersection_pairs_with(collider)
863            .filter_map(move |(h1, h2, intersecting)| {
864                let c1 = self.colliders.get(h1)?;
865                let c2 = self.colliders.get(h2)?;
866                Some((h1, c1, h2, c2, intersecting))
867            })
868    }
869
870    /// Iterate over all intersection pairs in the world.
871    ///
872    /// Each item is `(handle_a, &collider_a, handle_b, &collider_b, intersecting)`.
873    ///
874    /// # Mutable access
875    ///
876    /// There is no `_mut` variant of this method: the same collider may appear in
877    /// several intersection pairs, so a safe `Iterator` yielding `&mut Collider` from
878    /// a pair iterator isn't possible in stable Rust. To mutate colliders based on
879    /// intersection pairs, iterate here to collect the handles you care about, then
880    /// call [`ColliderSet::get_pair_mut`](crate::geometry::ColliderSet::get_pair_mut)
881    /// on [`self.colliders`](Self#structfield.colliders):
882    ///
883    /// ```
884    /// # use rapier3d::prelude::*;
885    /// # let mut world = PhysicsWorld::default();
886    /// let pairs: Vec<_> = world
887    ///     .intersection_pairs()
888    ///     .map(|(h1, _, h2, _, _)| (h1, h2))
889    ///     .collect();
890    /// for (h1, h2) in pairs {
891    ///     if let (Some(c1), Some(c2)) = world.colliders.get_pair_mut(h1, h2) {
892    ///         // mutate c1 and c2…
893    ///         # let _ = (c1, c2);
894    ///     }
895    /// }
896    /// ```
897    pub fn intersection_pairs(
898        &self,
899    ) -> impl Iterator<Item = (ColliderHandle, &Collider, ColliderHandle, &Collider, bool)> + '_
900    {
901        self.narrow_phase
902            .intersection_pairs()
903            .filter_map(move |(h1, h2, intersecting)| {
904                let c1 = self.colliders.get(h1)?;
905                let c2 = self.colliders.get(h2)?;
906                Some((h1, c1, h2, c2, intersecting))
907            })
908    }
909
910    // ── Iterators over all bodies and colliders ─────────────────────────
911
912    /// Iterate over every rigid body in the world as `(handle, &body)` pairs.
913    pub fn rigid_bodies(&self) -> impl Iterator<Item = (RigidBodyHandle, &RigidBody)> {
914        self.bodies.iter()
915    }
916
917    /// Iterate over every rigid body in the world as `(handle, &mut body)` pairs.
918    pub fn rigid_bodies_mut(&mut self) -> impl Iterator<Item = (RigidBodyHandle, &mut RigidBody)> {
919        self.bodies.iter_mut()
920    }
921
922    /// Iterate over only the currently active (awake) rigid bodies.
923    ///
924    /// Sleeping bodies are skipped, as are bodies that never sleep but aren't part of any
925    /// active island (e.g. unattached fixed bodies). This is the iterator to use when
926    /// rendering or syncing transforms, since transforms of sleeping bodies haven't moved
927    /// since the last step.
928    pub fn active_bodies(&self) -> impl Iterator<Item = (RigidBodyHandle, &RigidBody)> + '_ {
929        self.islands
930            .active_bodies()
931            .filter_map(move |h| Some((h, self.bodies.get(h)?)))
932    }
933
934    /// Iterate over every collider in the world as `(handle, &collider)` pairs.
935    pub fn all_colliders(&self) -> impl Iterator<Item = (ColliderHandle, &Collider)> {
936        self.colliders.iter()
937    }
938
939    /// Iterate over every collider in the world as `(handle, &mut collider)` pairs.
940    pub fn all_colliders_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
941        self.colliders.iter_mut()
942    }
943
944    // ── Debug rendering ─────────────────────────────────────────────────
945
946    /// Render debug information using the given debug-render pipeline and backend.
947    ///
948    /// This is a convenience method that passes all the required state to the
949    /// debug-render pipeline.
950    #[cfg(feature = "debug-render")]
951    pub fn debug_render(
952        &self,
953        pipeline: &mut DebugRenderPipeline,
954        backend: &mut impl DebugRenderBackend,
955    ) {
956        pipeline.render(
957            backend,
958            &self.bodies,
959            &self.colliders,
960            &self.impulse_joints,
961            &self.multibody_joints,
962            &self.narrow_phase,
963            &self.soft_bodies,
964        );
965    }
966}
967
968#[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
969impl PhysicsWorld {
970    /// Configures a dedicated thread pool for this physics world’s parallel work.
971    ///
972    /// If `num_threads` is `0`, then the new threadpool will use rayon’s default
973    /// number of threads.
974    ///
975    /// If no threadpool is configured, the global rayon thread pool, or the threadpool
976    /// setup with `ThreadPool::install`, is used.
977    pub fn configure_thread_pool(
978        &mut self,
979        num_threads: usize,
980    ) -> Result<(), rayon::ThreadPoolBuildError> {
981        self.physics_pipeline.configure_thread_pool(num_threads)
982    }
983
984    /// The thread-pool used by this physics world, if it was configured.
985    pub fn thread_pool(&self) -> Option<std::sync::Arc<rayon::ThreadPool>> {
986        self.physics_pipeline.thread_pool()
987    }
988
989    /// Sets (or clears) the thread pool running this physics world’s parallel work.
990    ///
991    /// Unlike [`Self::configure_thread_pool`], this takes an existing pool.
992    pub fn set_thread_pool(&mut self, pool: Option<std::sync::Arc<rayon::ThreadPool>>) {
993        self.physics_pipeline.set_thread_pool(pool)
994    }
995
996    /// Removes the dedicated thread pool: the parallel parts of the step run on whichever
997    /// pool the calling thread is in again.
998    pub fn clear_thread_pool(&mut self) {
999        self.physics_pipeline.clear_thread_pool()
1000    }
1001
1002    /// The number of workers this physics world’s parallel work runs on: the size of its
1003    /// dedicated thread pool if one was configured.
1004    pub fn num_threads(&self) -> Option<usize> {
1005        self.physics_pipeline.num_threads()
1006    }
1007}