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