1use crate::counters::Counters;
4use crate::dynamics::IslandSolver;
6#[cfg(feature = "parallel")]
7use crate::dynamics::JointGraphEdge;
8use crate::dynamics::{
9 CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
10 RigidBodyChanges, RigidBodyPosition, RigidBodyType,
11};
12use crate::geometry::{
13 BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
14 ContactManifoldIndex, ModifiedColliders, NarrowPhase, TemporaryInteractionIndex,
15};
16use crate::math::{Real, Vector};
17use crate::pipeline::{EventHandler, PhysicsHooks};
18use crate::prelude::ModifiedRigidBodies;
19use {crate::dynamics::RigidBodySet, crate::geometry::ColliderSet};
20
21pub struct PhysicsPipeline {
33 pub counters: Counters,
35 contact_pair_indices: Vec<TemporaryInteractionIndex>,
36 manifold_indices: Vec<Vec<ContactManifoldIndex>>,
37 joint_constraint_indices: Vec<Vec<ContactManifoldIndex>>,
38 broadphase_collider_pairs: Vec<ColliderPair>,
39 broad_phase_events: Vec<BroadPhasePairEvent>,
40 solvers: Vec<IslandSolver>,
41}
42
43impl Default for PhysicsPipeline {
44 fn default() -> Self {
45 PhysicsPipeline::new()
46 }
47}
48
49#[allow(dead_code)]
50fn check_pipeline_send_sync() {
51 fn do_test<T: Sync>() {}
52 do_test::<PhysicsPipeline>();
53}
54
55impl PhysicsPipeline {
56 pub fn new() -> PhysicsPipeline {
58 PhysicsPipeline {
59 counters: Counters::new(true),
60 solvers: vec![],
61 contact_pair_indices: vec![],
62 manifold_indices: vec![],
63 joint_constraint_indices: vec![],
64 broadphase_collider_pairs: vec![],
65 broad_phase_events: vec![],
66 }
67 }
68
69 fn clear_modified_colliders(
70 &mut self,
71 colliders: &mut ColliderSet,
72 modified_colliders: &mut ModifiedColliders,
73 ) {
74 for handle in modified_colliders.iter() {
75 if let Some(co) = colliders.get_mut_internal(*handle) {
76 co.changes = ColliderChanges::empty();
77 }
78 }
79
80 modified_colliders.clear();
81 }
82
83 fn clear_modified_bodies(
84 &mut self,
85 bodies: &mut RigidBodySet,
86 modified_bodies: &mut ModifiedRigidBodies,
87 ) {
88 for handle in modified_bodies.iter() {
89 if let Some(rb) = bodies.get_mut_internal(*handle) {
90 rb.changes = RigidBodyChanges::empty();
91 }
92 }
93
94 modified_bodies.clear();
95 }
96
97 fn detect_collisions(
98 &mut self,
99 integration_parameters: &IntegrationParameters,
100 islands: &mut IslandManager,
101 broad_phase: &mut dyn BroadPhase,
102 narrow_phase: &mut NarrowPhase,
103 bodies: &mut RigidBodySet,
104 colliders: &mut ColliderSet,
105 impulse_joints: &ImpulseJointSet,
106 multibody_joints: &MultibodyJointSet,
107 modified_colliders: &[ColliderHandle],
108 removed_colliders: &[ColliderHandle],
109 hooks: &dyn PhysicsHooks,
110 events: &dyn EventHandler,
111 handle_user_changes: bool,
112 ) {
113 self.counters.stages.collision_detection_time.resume();
114 self.counters.cd.broad_phase_time.resume();
115
116 self.broad_phase_events.clear();
118 self.broadphase_collider_pairs.clear();
119 broad_phase.update(
120 integration_parameters,
121 colliders,
122 bodies,
123 modified_colliders,
124 removed_colliders,
125 &mut self.broad_phase_events,
126 );
127
128 self.counters.cd.broad_phase_time.pause();
129 self.counters.cd.narrow_phase_time.resume();
130
131 if handle_user_changes {
133 narrow_phase.handle_user_changes(
134 Some(islands),
135 modified_colliders,
136 removed_colliders,
137 colliders,
138 bodies,
139 events,
140 );
141 }
142 narrow_phase.register_pairs(
143 Some(islands),
144 colliders,
145 bodies,
146 &self.broad_phase_events,
147 events,
148 );
149 narrow_phase.compute_contacts(
150 integration_parameters.prediction_distance(),
151 integration_parameters.dt,
152 bodies,
153 colliders,
154 impulse_joints,
155 multibody_joints,
156 modified_colliders,
157 hooks,
158 events,
159 );
160 narrow_phase.compute_intersections(bodies, colliders, modified_colliders, hooks, events);
161
162 self.counters.cd.narrow_phase_time.pause();
163 self.counters.stages.collision_detection_time.pause();
164 }
165
166 fn build_islands_and_solve_velocity_constraints(
167 &mut self,
168 gravity: &Vector<Real>,
169 integration_parameters: &IntegrationParameters,
170 islands: &mut IslandManager,
171 narrow_phase: &mut NarrowPhase,
172 bodies: &mut RigidBodySet,
173 colliders: &mut ColliderSet,
174 impulse_joints: &mut ImpulseJointSet,
175 multibody_joints: &mut MultibodyJointSet,
176 events: &dyn EventHandler,
177 ) {
178 self.counters.stages.island_construction_time.resume();
179 islands.update_active_set_with_contacts(
180 integration_parameters.dt,
181 integration_parameters.length_unit,
182 bodies,
183 colliders,
184 narrow_phase,
185 impulse_joints,
186 multibody_joints,
187 integration_parameters.min_island_size,
188 );
189
190 if self.manifold_indices.len() < islands.num_islands() {
191 self.manifold_indices
192 .resize(islands.num_islands(), Vec::new());
193 }
194
195 if self.joint_constraint_indices.len() < islands.num_islands() {
196 self.joint_constraint_indices
197 .resize(islands.num_islands(), Vec::new());
198 }
199
200 let mut manifolds = Vec::new();
201 narrow_phase.select_active_contacts(
202 islands,
203 bodies,
204 &mut self.contact_pair_indices,
205 &mut manifolds,
206 &mut self.manifold_indices,
207 );
208 impulse_joints.select_active_interactions(
209 islands,
210 bodies,
211 &mut self.joint_constraint_indices,
212 );
213 self.counters.stages.island_construction_time.pause();
214
215 self.counters.stages.update_time.resume();
216 for handle in islands.active_dynamic_bodies() {
217 let rb = bodies.index_mut_internal(*handle);
220 rb.mprops.update_world_mass_properties(&rb.pos.position);
221 let effective_mass = rb.mprops.effective_mass();
222 rb.forces
223 .compute_effective_force_and_torque(gravity, &effective_mass);
224 }
225 self.counters.stages.update_time.pause();
226
227 self.counters.stages.solver_time.resume();
228 if self.solvers.len() < islands.num_islands() {
229 self.solvers
230 .resize_with(islands.num_islands(), IslandSolver::new);
231 }
232
233 #[cfg(not(feature = "parallel"))]
234 {
235 enable_flush_to_zero!();
236
237 for island_id in 0..islands.num_islands() {
238 self.solvers[island_id].init_and_solve(
239 island_id,
240 &mut self.counters,
241 integration_parameters,
242 islands,
243 bodies,
244 &mut manifolds[..],
245 &self.manifold_indices[island_id],
246 impulse_joints.joints_mut(),
247 &self.joint_constraint_indices[island_id],
248 multibody_joints,
249 )
250 }
251 }
252
253 #[cfg(feature = "parallel")]
254 {
255 use crate::geometry::ContactManifold;
256 use rayon::prelude::*;
257 use std::sync::atomic::Ordering;
258
259 let num_islands = islands.num_islands();
260 let solvers = &mut self.solvers[..num_islands];
261 let bodies = &std::sync::atomic::AtomicPtr::new(bodies as *mut _);
262 let manifolds = &std::sync::atomic::AtomicPtr::new(&mut manifolds as *mut _);
263 let impulse_joints =
264 &std::sync::atomic::AtomicPtr::new(impulse_joints.joints_vec_mut() as *mut _);
265 let multibody_joints = &std::sync::atomic::AtomicPtr::new(multibody_joints as *mut _);
266 let manifold_indices = &self.manifold_indices[..];
267 let joint_constraint_indices = &self.joint_constraint_indices[..];
268
269 self.counters.solver.velocity_resolution_time.resume();
273 rayon::scope(|_scope| {
274 enable_flush_to_zero!();
275
276 solvers
277 .par_iter_mut()
278 .enumerate()
279 .for_each(|(island_id, solver)| {
280 let bodies: &mut RigidBodySet =
281 unsafe { &mut *bodies.load(Ordering::Relaxed) };
282 let manifolds: &mut Vec<&mut ContactManifold> =
283 unsafe { &mut *manifolds.load(Ordering::Relaxed) };
284 let impulse_joints: &mut Vec<JointGraphEdge> =
285 unsafe { &mut *impulse_joints.load(Ordering::Relaxed) };
286 let multibody_joints: &mut MultibodyJointSet =
287 unsafe { &mut *multibody_joints.load(Ordering::Relaxed) };
288
289 let mut counters = Counters::new(false);
290 solver.init_and_solve(
291 island_id,
292 &mut counters,
293 integration_parameters,
294 islands,
295 bodies,
296 &mut manifolds[..],
297 &manifold_indices[island_id],
298 impulse_joints,
299 &joint_constraint_indices[island_id],
300 multibody_joints,
301 )
302 });
303 });
304 self.counters.solver.velocity_resolution_time.pause();
305 }
306
307 let inv_dt = crate::utils::inv(integration_parameters.dt);
309 for pair_id in self.contact_pair_indices.drain(..) {
310 let pair = narrow_phase.contact_pair_at_index(pair_id);
311 let co1 = &colliders[pair.collider1];
312 let co2 = &colliders[pair.collider2];
313 let threshold = co1
314 .effective_contact_force_event_threshold()
315 .min(co2.effective_contact_force_event_threshold());
316
317 if threshold < Real::MAX {
318 let total_magnitude = pair.total_impulse_magnitude() * inv_dt;
319
320 if total_magnitude > threshold {
323 events.handle_contact_force_event(
324 integration_parameters.dt,
325 bodies,
326 colliders,
327 pair,
328 total_magnitude,
329 );
330 }
331 }
332 }
333
334 self.counters.stages.solver_time.pause();
335 }
336
337 fn run_ccd_motion_clamping(
338 &mut self,
339 integration_parameters: &IntegrationParameters,
340 islands: &IslandManager,
341 bodies: &mut RigidBodySet,
342 colliders: &mut ColliderSet,
343 narrow_phase: &NarrowPhase,
344 ccd_solver: &mut CCDSolver,
345 events: &dyn EventHandler,
346 ) {
347 self.counters.ccd.toi_computation_time.start();
348 let impacts = ccd_solver.predict_impacts_at_next_positions(
350 integration_parameters.dt,
351 islands,
352 bodies,
353 colliders,
354 narrow_phase,
355 events,
356 );
357 ccd_solver.clamp_motions(integration_parameters.dt, bodies, &impacts);
358 self.counters.ccd.toi_computation_time.pause();
359 }
360
361 fn advance_to_final_positions(
362 &mut self,
363 islands: &IslandManager,
364 bodies: &mut RigidBodySet,
365 colliders: &mut ColliderSet,
366 modified_colliders: &mut ModifiedColliders,
367 ) {
368 for handle in islands.iter_active_bodies() {
370 let rb = bodies.index_mut_internal(handle);
371 rb.pos.position = rb.pos.next_position;
372 rb.colliders
373 .update_positions(colliders, modified_colliders, &rb.pos.position);
374 }
375 }
376
377 fn interpolate_kinematic_velocities(
378 &mut self,
379 integration_parameters: &IntegrationParameters,
380 islands: &IslandManager,
381 bodies: &mut RigidBodySet,
382 ) {
383 for handle in islands.active_kinematic_bodies() {
389 let rb = bodies.index_mut_internal(*handle);
390
391 match rb.body_type {
392 RigidBodyType::KinematicPositionBased => {
393 rb.vels = rb.pos.interpolate_velocity(
394 integration_parameters.inv_dt(),
395 &rb.mprops.local_mprops.local_com,
396 );
397 }
398 RigidBodyType::KinematicVelocityBased => {
399 let new_pos = rb.vels.integrate(
400 integration_parameters.dt,
401 &rb.pos.position,
402 &rb.mprops.local_mprops.local_com,
403 );
404 rb.pos = RigidBodyPosition::from(new_pos);
405 }
406 _ => {}
407 }
408 }
409 }
410
411 pub fn step(
413 &mut self,
414 gravity: &Vector<Real>,
415 integration_parameters: &IntegrationParameters,
416 islands: &mut IslandManager,
417 broad_phase: &mut dyn BroadPhase,
418 narrow_phase: &mut NarrowPhase,
419 bodies: &mut RigidBodySet,
420 colliders: &mut ColliderSet,
421 impulse_joints: &mut ImpulseJointSet,
422 multibody_joints: &mut MultibodyJointSet,
423 ccd_solver: &mut CCDSolver,
424 hooks: &dyn PhysicsHooks,
425 events: &dyn EventHandler,
426 ) {
427 self.counters.reset();
428 self.counters.step_started();
429
430 self.counters.stages.user_changes.start();
432 #[cfg(feature = "enhanced-determinism")]
433 let impulse_joints_iterator = impulse_joints
434 .to_wake_up
435 .drain(..)
436 .chain(multibody_joints.to_wake_up.drain(..));
437 #[cfg(not(feature = "enhanced-determinism"))]
438 let impulse_joints_iterator = impulse_joints
439 .to_wake_up
440 .drain()
441 .chain(multibody_joints.to_wake_up.drain());
442 for handle in impulse_joints_iterator {
443 islands.wake_up(bodies, handle, true);
444 }
445
446 let mut modified_colliders = colliders.take_modified();
448 let mut removed_colliders = colliders.take_removed();
449
450 super::user_changes::handle_user_changes_to_colliders(
451 bodies,
452 colliders,
453 &modified_colliders[..],
454 );
455
456 let mut modified_bodies = bodies.take_modified();
457 super::user_changes::handle_user_changes_to_rigid_bodies(
458 Some(islands),
459 bodies,
460 colliders,
461 impulse_joints,
462 multibody_joints,
463 &modified_bodies,
464 &mut modified_colliders,
465 );
466
467 removed_colliders.extend(
471 modified_colliders
472 .iter()
473 .copied()
474 .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
475 );
476 self.counters.stages.user_changes.pause();
477
478 for multibody in &mut multibody_joints.multibodies {
481 multibody.1.forward_kinematics(bodies, true);
482 multibody
483 .1
484 .update_rigid_bodies_internal(bodies, true, false, false);
485 }
486
487 self.detect_collisions(
488 integration_parameters,
489 islands,
490 broad_phase,
491 narrow_phase,
492 bodies,
493 colliders,
494 impulse_joints,
495 multibody_joints,
496 &modified_colliders,
497 &removed_colliders,
498 hooks,
499 events,
500 true,
501 );
502
503 self.counters.stages.user_changes.resume();
504 self.clear_modified_colliders(colliders, &mut modified_colliders);
505 self.clear_modified_bodies(bodies, &mut modified_bodies);
506 removed_colliders.clear();
507 self.counters.stages.user_changes.pause();
508
509 let mut remaining_time = integration_parameters.dt;
510 let mut integration_parameters = *integration_parameters;
511
512 let (ccd_is_enabled, mut remaining_substeps) =
513 if integration_parameters.max_ccd_substeps == 0 {
514 (false, 1)
515 } else {
516 (true, integration_parameters.max_ccd_substeps)
517 };
518
519 while remaining_substeps > 0 {
520 if ccd_is_enabled && remaining_substeps > 1 {
531 let ccd_active =
534 ccd_solver.update_ccd_active_flags(islands, bodies, remaining_time, true);
535 let first_impact = if ccd_active {
536 ccd_solver.find_first_impact(
537 remaining_time,
538 islands,
539 bodies,
540 colliders,
541 narrow_phase,
542 )
543 } else {
544 None
545 };
546
547 if let Some(toi) = first_impact {
548 let original_interval = remaining_time / (remaining_substeps as Real);
549
550 if toi < original_interval {
551 integration_parameters.dt = original_interval;
552 } else {
553 integration_parameters.dt =
554 toi + (remaining_time - toi) / (remaining_substeps as Real);
555 }
556
557 remaining_substeps -= 1;
558 } else {
559 integration_parameters.dt = remaining_time;
561 remaining_substeps = 0;
562 }
563
564 remaining_time -= integration_parameters.dt;
565
566 if remaining_time <= integration_parameters.min_ccd_dt {
568 integration_parameters.dt += remaining_time;
569 remaining_substeps = 0;
570 }
571 } else {
572 integration_parameters.dt = remaining_time;
573 remaining_time = 0.0;
574 remaining_substeps = 0;
575 }
576
577 self.counters.ccd.num_substeps += 1;
578
579 self.interpolate_kinematic_velocities(&integration_parameters, islands, bodies);
580 self.build_islands_and_solve_velocity_constraints(
581 gravity,
582 &integration_parameters,
583 islands,
584 narrow_phase,
585 bodies,
586 colliders,
587 impulse_joints,
588 multibody_joints,
589 events,
590 );
591
592 if ccd_is_enabled {
594 let ccd_active = ccd_solver.update_ccd_active_flags(
597 islands,
598 bodies,
599 integration_parameters.dt,
600 false,
601 );
602 if ccd_active {
603 self.run_ccd_motion_clamping(
604 &integration_parameters,
605 islands,
606 bodies,
607 colliders,
608 narrow_phase,
609 ccd_solver,
610 events,
611 );
612 }
613 }
614
615 self.counters.stages.update_time.resume();
616 self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders);
617 self.counters.stages.update_time.pause();
618
619 self.detect_collisions(
620 &integration_parameters,
621 islands,
622 broad_phase,
623 narrow_phase,
624 bodies,
625 colliders,
626 impulse_joints,
627 multibody_joints,
628 &modified_colliders,
629 &[],
630 hooks,
631 events,
632 false,
633 );
634
635 self.clear_modified_colliders(colliders, &mut modified_colliders);
636 }
637
638 self.counters.stages.update_time.resume();
645 for handle in islands.active_dynamic_bodies() {
646 let rb = bodies.index_mut_internal(*handle);
647 rb.mprops.update_world_mass_properties(&rb.pos.position);
648 }
649 self.counters.stages.update_time.pause();
650
651 self.counters.step_completed();
652 }
653}
654
655#[cfg(test)]
656mod test {
657 use na::point;
658
659 use crate::dynamics::{
660 CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, RigidBodyBuilder,
661 RigidBodySet,
662 };
663 use crate::geometry::{BroadPhaseBvh, ColliderBuilder, ColliderSet, NarrowPhase};
664 use crate::math::Vector;
665 use crate::pipeline::PhysicsPipeline;
666 use crate::prelude::{MultibodyJointSet, RevoluteJointBuilder, RigidBodyType};
667
668 #[test]
669 fn kinematic_and_fixed_contact_crash() {
670 let mut colliders = ColliderSet::new();
671 let mut impulse_joints = ImpulseJointSet::new();
672 let mut multibody_joints = MultibodyJointSet::new();
673 let mut pipeline = PhysicsPipeline::new();
674 let mut bf = BroadPhaseBvh::new();
675 let mut nf = NarrowPhase::new();
676 let mut bodies = RigidBodySet::new();
677 let mut islands = IslandManager::new();
678
679 let rb = RigidBodyBuilder::fixed().build();
680 let h1 = bodies.insert(rb.clone());
681 let co = ColliderBuilder::ball(10.0).build();
682 colliders.insert_with_parent(co.clone(), h1, &mut bodies);
683
684 let rb = RigidBodyBuilder::kinematic_position_based().build();
686 let h2 = bodies.insert(rb.clone());
687 colliders.insert_with_parent(co, h2, &mut bodies);
688
689 pipeline.step(
690 &Vector::zeros(),
691 &IntegrationParameters::default(),
692 &mut islands,
693 &mut bf,
694 &mut nf,
695 &mut bodies,
696 &mut colliders,
697 &mut impulse_joints,
698 &mut multibody_joints,
699 &mut CCDSolver::new(),
700 &(),
701 &(),
702 );
703 }
704
705 #[test]
706 fn rigid_body_removal_before_step() {
707 let mut colliders = ColliderSet::new();
708 let mut impulse_joints = ImpulseJointSet::new();
709 let mut multibody_joints = MultibodyJointSet::new();
710 let mut pipeline = PhysicsPipeline::new();
711 let mut bf = BroadPhaseBvh::new();
712 let mut nf = NarrowPhase::new();
713 let mut islands = IslandManager::new();
714
715 let mut bodies = RigidBodySet::new();
716
717 let rb = RigidBodyBuilder::dynamic().build();
721 let h1 = bodies.insert(rb.clone());
722 let h2 = bodies.insert(rb.clone());
723
724 let rb = RigidBodyBuilder::kinematic_position_based().build();
726 let h3 = bodies.insert(rb.clone());
727
728 let rb = RigidBodyBuilder::fixed().build();
730 let h4 = bodies.insert(rb.clone());
731
732 let to_delete = [h1, h2, h3, h4];
733 for h in &to_delete {
734 bodies.remove(
735 *h,
736 &mut islands,
737 &mut colliders,
738 &mut impulse_joints,
739 &mut multibody_joints,
740 true,
741 );
742 }
743
744 pipeline.step(
745 &Vector::zeros(),
746 &IntegrationParameters::default(),
747 &mut islands,
748 &mut bf,
749 &mut nf,
750 &mut bodies,
751 &mut colliders,
752 &mut impulse_joints,
753 &mut multibody_joints,
754 &mut CCDSolver::new(),
755 &(),
756 &(),
757 );
758 }
759
760 #[cfg(feature = "serde-serialize")]
761 #[test]
762 fn rigid_body_removal_snapshot_handle_determinism() {
763 let mut colliders = ColliderSet::new();
764 let mut impulse_joints = ImpulseJointSet::new();
765 let mut multibody_joints = MultibodyJointSet::new();
766 let mut islands = IslandManager::new();
767
768 let mut bodies = RigidBodySet::new();
769 let rb = RigidBodyBuilder::dynamic().build();
770 let h1 = bodies.insert(rb.clone());
771 let h2 = bodies.insert(rb.clone());
772 let h3 = bodies.insert(rb.clone());
773
774 bodies.remove(
775 h1,
776 &mut islands,
777 &mut colliders,
778 &mut impulse_joints,
779 &mut multibody_joints,
780 true,
781 );
782 bodies.remove(
783 h3,
784 &mut islands,
785 &mut colliders,
786 &mut impulse_joints,
787 &mut multibody_joints,
788 true,
789 );
790 bodies.remove(
791 h2,
792 &mut islands,
793 &mut colliders,
794 &mut impulse_joints,
795 &mut multibody_joints,
796 true,
797 );
798
799 let ser_bodies = bincode::serialize(&bodies).unwrap();
800 let mut bodies2: RigidBodySet = bincode::deserialize(&ser_bodies).unwrap();
801
802 let h1a = bodies.insert(rb.clone());
803 let h2a = bodies.insert(rb.clone());
804 let h3a = bodies.insert(rb.clone());
805
806 let h1b = bodies2.insert(rb.clone());
807 let h2b = bodies2.insert(rb.clone());
808 let h3b = bodies2.insert(rb.clone());
809
810 assert_eq!(h1a, h1b);
811 assert_eq!(h2a, h2b);
812 assert_eq!(h3a, h3b);
813 }
814
815 #[test]
816 fn collider_removal_before_step() {
817 let mut pipeline = PhysicsPipeline::new();
818 let gravity = Vector::y() * -9.81;
819 let integration_parameters = IntegrationParameters::default();
820 let mut broad_phase = BroadPhaseBvh::new();
821 let mut narrow_phase = NarrowPhase::new();
822 let mut bodies = RigidBodySet::new();
823 let mut colliders = ColliderSet::new();
824 let mut ccd = CCDSolver::new();
825 let mut impulse_joints = ImpulseJointSet::new();
826 let mut multibody_joints = MultibodyJointSet::new();
827 let mut islands = IslandManager::new();
828 let physics_hooks = ();
829 let event_handler = ();
830
831 let body = RigidBodyBuilder::dynamic().build();
832 let b_handle = bodies.insert(body);
833 let collider = ColliderBuilder::ball(1.0).build();
834 let c_handle = colliders.insert_with_parent(collider, b_handle, &mut bodies);
835 colliders.remove(c_handle, &mut islands, &mut bodies, true);
836 bodies.remove(
837 b_handle,
838 &mut islands,
839 &mut colliders,
840 &mut impulse_joints,
841 &mut multibody_joints,
842 true,
843 );
844
845 for _ in 0..10 {
846 pipeline.step(
847 &gravity,
848 &integration_parameters,
849 &mut islands,
850 &mut broad_phase,
851 &mut narrow_phase,
852 &mut bodies,
853 &mut colliders,
854 &mut impulse_joints,
855 &mut multibody_joints,
856 &mut ccd,
857 &physics_hooks,
858 &event_handler,
859 );
860 }
861 }
862
863 #[test]
864 fn rigid_body_type_changed_dynamic_is_in_active_set() {
865 let mut colliders = ColliderSet::new();
866 let mut impulse_joints = ImpulseJointSet::new();
867 let mut multibody_joints = MultibodyJointSet::new();
868 let mut pipeline = PhysicsPipeline::new();
869 let mut bf = BroadPhaseBvh::new();
870 let mut nf = NarrowPhase::new();
871 let mut islands = IslandManager::new();
872
873 let mut bodies = RigidBodySet::new();
874
875 let rb = RigidBodyBuilder::kinematic_position_based()
877 .additional_mass(1.0)
878 .build();
879 let h = bodies.insert(rb.clone());
880
881 let gravity = Vector::y() * -9.81;
883 pipeline.step(
884 &gravity,
885 &IntegrationParameters::default(),
886 &mut islands,
887 &mut bf,
888 &mut nf,
889 &mut bodies,
890 &mut colliders,
891 &mut impulse_joints,
892 &mut multibody_joints,
893 &mut CCDSolver::new(),
894 &(),
895 &(),
896 );
897
898 bodies
900 .get_mut(h)
901 .unwrap()
902 .set_body_type(RigidBodyType::Dynamic, true);
903
904 pipeline.step(
906 &gravity,
907 &IntegrationParameters::default(),
908 &mut islands,
909 &mut bf,
910 &mut nf,
911 &mut bodies,
912 &mut colliders,
913 &mut impulse_joints,
914 &mut multibody_joints,
915 &mut CCDSolver::new(),
916 &(),
917 &(),
918 );
919
920 let body = bodies.get(h).unwrap();
921 let h_y = body.pos.position.translation.y;
922
923 assert!(h_y < 0.0);
925
926 assert!(islands.active_dynamic_set.contains(&h));
928 }
929
930 #[test]
931 fn joint_step_delta_time_0() {
932 let mut colliders = ColliderSet::new();
933 let mut impulse_joints = ImpulseJointSet::new();
934 let mut multibody_joints = MultibodyJointSet::new();
935 let mut pipeline = PhysicsPipeline::new();
936 let mut bf = BroadPhaseBvh::new();
937 let mut nf = NarrowPhase::new();
938 let mut islands = IslandManager::new();
939
940 let mut bodies = RigidBodySet::new();
941
942 let rb = RigidBodyBuilder::fixed().additional_mass(1.0).build();
944 let h = bodies.insert(rb.clone());
945 let rb_dynamic = RigidBodyBuilder::dynamic().additional_mass(1.0).build();
946 let h_dynamic = bodies.insert(rb_dynamic.clone());
947
948 #[cfg(feature = "dim2")]
950 let joint = RevoluteJointBuilder::new()
951 .local_anchor1(point![0.0, 1.0])
952 .local_anchor2(point![0.0, -3.0]);
953 #[cfg(feature = "dim3")]
954 let joint = RevoluteJointBuilder::new(Vector::z_axis())
955 .local_anchor1(point![0.0, 1.0, 0.0])
956 .local_anchor2(point![0.0, -3.0, 0.0]);
957 impulse_joints.insert(h, h_dynamic, joint, true);
958
959 let parameters = IntegrationParameters {
960 dt: 0.0,
961 ..Default::default()
962 };
963 let gravity = Vector::y() * -9.81;
965 pipeline.step(
966 &gravity,
967 ¶meters,
968 &mut islands,
969 &mut bf,
970 &mut nf,
971 &mut bodies,
972 &mut colliders,
973 &mut impulse_joints,
974 &mut multibody_joints,
975 &mut CCDSolver::new(),
976 &(),
977 &(),
978 );
979 let translation = bodies[h_dynamic].translation();
980 let rotation = bodies[h_dynamic].rotation();
981 assert!(translation.x.is_finite());
982 assert!(translation.y.is_finite());
983 #[cfg(feature = "dim2")]
984 assert!(rotation.is_finite());
985 #[cfg(feature = "dim3")]
986 {
987 assert!(translation.z.is_finite());
988 assert!(rotation.i.is_finite());
989 assert!(rotation.j.is_finite());
990 assert!(rotation.k.is_finite());
991 assert!(rotation.w.is_finite());
992 }
993 }
994
995 #[test]
996 #[cfg(feature = "dim2")]
997 fn test_multi_sap_disable_body() {
998 use na::vector;
999 let mut rigid_body_set = RigidBodySet::new();
1000 let mut collider_set = ColliderSet::new();
1001
1002 let collider = ColliderBuilder::cuboid(100.0, 0.1).build();
1004 collider_set.insert(collider);
1005
1006 let rigid_body = RigidBodyBuilder::dynamic()
1008 .translation(vector![0.0, 10.0])
1009 .build();
1010 let collider = ColliderBuilder::ball(0.5).restitution(0.7).build();
1011 let ball_body_handle = rigid_body_set.insert(rigid_body);
1012 collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);
1013
1014 let gravity = vector![0.0, -9.81];
1016 let integration_parameters = IntegrationParameters::default();
1017 let mut physics_pipeline = PhysicsPipeline::new();
1018 let mut island_manager = IslandManager::new();
1019 let mut broad_phase = BroadPhaseBvh::new();
1020 let mut narrow_phase = NarrowPhase::new();
1021 let mut impulse_joint_set = ImpulseJointSet::new();
1022 let mut multibody_joint_set = MultibodyJointSet::new();
1023 let mut ccd_solver = CCDSolver::new();
1024 let physics_hooks = ();
1025 let event_handler = ();
1026
1027 physics_pipeline.step(
1028 &gravity,
1029 &integration_parameters,
1030 &mut island_manager,
1031 &mut broad_phase,
1032 &mut narrow_phase,
1033 &mut rigid_body_set,
1034 &mut collider_set,
1035 &mut impulse_joint_set,
1036 &mut multibody_joint_set,
1037 &mut ccd_solver,
1038 &physics_hooks,
1039 &event_handler,
1040 );
1041
1042 {
1044 let ball_body = &mut rigid_body_set[ball_body_handle];
1045
1046 ball_body.set_translation(vector![1.0, 1.0], true);
1048 ball_body.set_rotation(nalgebra::UnitComplex::new(1.0), true);
1049
1050 ball_body.set_enabled(false);
1051 }
1052
1053 physics_pipeline.step(
1054 &gravity,
1055 &integration_parameters,
1056 &mut island_manager,
1057 &mut broad_phase,
1058 &mut narrow_phase,
1059 &mut rigid_body_set,
1060 &mut collider_set,
1061 &mut impulse_joint_set,
1062 &mut multibody_joint_set,
1063 &mut ccd_solver,
1064 &physics_hooks,
1065 &event_handler,
1066 );
1067
1068 {
1070 let ball_body = &mut rigid_body_set[ball_body_handle];
1071
1072 ball_body.set_translation(vector![0.0, 0.0], true);
1074 ball_body.set_rotation(nalgebra::UnitComplex::new(0.0), true);
1075
1076 ball_body.set_enabled(true);
1077 }
1078
1079 physics_pipeline.step(
1080 &gravity,
1081 &integration_parameters,
1082 &mut island_manager,
1083 &mut broad_phase,
1084 &mut narrow_phase,
1085 &mut rigid_body_set,
1086 &mut collider_set,
1087 &mut impulse_joint_set,
1088 &mut multibody_joint_set,
1089 &mut ccd_solver,
1090 &physics_hooks,
1091 &event_handler,
1092 );
1093 }
1094}