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}