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, RigidBodyType,
11};
12use crate::geometry::{
13 BroadPhaseBvh, 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 {
41 pub counters: Counters,
43 contact_pair_indices: Vec<TemporaryInteractionIndex>,
44 manifold_indices: Vec<Vec<ContactManifoldIndex>>,
45 joint_constraint_indices: Vec<Vec<ContactManifoldIndex>>,
46 broadphase_collider_pairs: Vec<ColliderPair>,
47 broad_phase_events: Vec<BroadPhasePairEvent>,
48 solvers: Vec<IslandSolver>,
49}
50
51impl Default for PhysicsPipeline {
52 fn default() -> Self {
53 PhysicsPipeline::new()
54 }
55}
56
57#[allow(dead_code)]
58fn check_pipeline_send_sync() {
59 fn do_test<T: Sync>() {}
60 do_test::<PhysicsPipeline>();
61}
62
63impl PhysicsPipeline {
64 pub fn new() -> PhysicsPipeline {
69 PhysicsPipeline {
70 counters: Counters::new(true),
71 solvers: vec![],
72 contact_pair_indices: vec![],
73 manifold_indices: vec![],
74 joint_constraint_indices: vec![],
75 broadphase_collider_pairs: vec![],
76 broad_phase_events: vec![],
77 }
78 }
79
80 fn clear_modified_colliders(
81 &mut self,
82 colliders: &mut ColliderSet,
83 modified_colliders: &mut ModifiedColliders,
84 ) {
85 for co in colliders.colliders.iter_mut() {
92 co.1.changes = ColliderChanges::empty();
93 }
94 modified_colliders.clear();
101 }
102
103 fn clear_modified_bodies(
104 &mut self,
105 bodies: &mut RigidBodySet,
106 modified_bodies: &mut ModifiedRigidBodies,
107 ) {
108 for handle in modified_bodies.iter() {
109 if let Some(rb) = bodies.get_mut_internal(*handle) {
110 rb.changes = RigidBodyChanges::empty();
111 }
112 }
113
114 modified_bodies.clear();
115 }
116
117 fn detect_collisions(
118 &mut self,
119 integration_parameters: &IntegrationParameters,
120 islands: &mut IslandManager,
121 broad_phase: &mut BroadPhaseBvh,
122 narrow_phase: &mut NarrowPhase,
123 bodies: &mut RigidBodySet,
124 colliders: &mut ColliderSet,
125 impulse_joints: &ImpulseJointSet,
126 multibody_joints: &MultibodyJointSet,
127 modified_colliders: &[ColliderHandle],
128 removed_colliders: &[ColliderHandle],
129 hooks: &dyn PhysicsHooks,
130 events: &dyn EventHandler,
131 handle_user_changes: bool,
132 ) {
133 self.counters.stages.collision_detection_time.resume();
134 self.counters.cd.broad_phase_time.resume();
135
136 self.broad_phase_events.clear();
138 self.broadphase_collider_pairs.clear();
139 broad_phase.update(
140 integration_parameters,
141 colliders,
142 bodies,
143 modified_colliders,
144 removed_colliders,
145 &mut self.broad_phase_events,
146 );
147
148 self.counters.cd.broad_phase_time.pause();
149 self.counters.cd.narrow_phase_time.resume();
150
151 if handle_user_changes {
153 narrow_phase.handle_user_changes(
154 Some(islands),
155 modified_colliders,
156 removed_colliders,
157 colliders,
158 bodies,
159 events,
160 );
161 }
162 narrow_phase.register_pairs(
163 Some(islands),
164 colliders,
165 bodies,
166 &self.broad_phase_events,
167 events,
168 );
169 narrow_phase.compute_contacts(
170 integration_parameters.prediction_distance(),
171 integration_parameters.dt,
172 islands,
173 bodies,
174 colliders,
175 impulse_joints,
176 multibody_joints,
177 hooks,
178 events,
179 );
180 narrow_phase.compute_intersections(bodies, colliders, hooks, events);
181
182 self.counters.cd.narrow_phase_time.pause();
183 self.counters.stages.collision_detection_time.pause();
184 }
185
186 fn build_islands_and_solve_velocity_constraints(
187 &mut self,
188 gravity: Vector,
189 integration_parameters: &IntegrationParameters,
190 islands: &mut IslandManager,
191 narrow_phase: &mut NarrowPhase,
192 bodies: &mut RigidBodySet,
193 colliders: &mut ColliderSet,
194 impulse_joints: &mut ImpulseJointSet,
195 multibody_joints: &mut MultibodyJointSet,
196 events: &dyn EventHandler,
197 ) {
198 self.counters.stages.island_construction_time.resume();
199 islands.update_islands(
201 integration_parameters.dt,
202 integration_parameters.length_unit,
203 bodies,
204 colliders,
205 narrow_phase,
206 impulse_joints,
207 multibody_joints,
208 );
209
210 let num_active_islands = islands.active_islands().len();
211 if self.manifold_indices.len() < num_active_islands {
212 self.manifold_indices.resize(num_active_islands, Vec::new());
213 }
214
215 if self.joint_constraint_indices.len() < num_active_islands {
216 self.joint_constraint_indices
217 .resize(num_active_islands, Vec::new());
218 }
219 self.counters.stages.island_construction_time.pause();
220
221 self.counters
222 .stages
223 .island_constraints_collection_time
224 .resume();
225 let mut manifolds = Vec::new();
226 narrow_phase.select_active_contacts(
227 islands,
228 bodies,
229 &mut self.contact_pair_indices,
230 &mut manifolds,
231 &mut self.manifold_indices,
232 );
233 impulse_joints.select_active_interactions(
234 islands,
235 bodies,
236 &mut self.joint_constraint_indices,
237 );
238 self.counters
239 .stages
240 .island_constraints_collection_time
241 .pause();
242
243 self.counters.stages.update_time.resume();
244 for handle in islands.active_bodies() {
245 let rb = bodies.index_mut_internal(handle);
248 rb.mprops
249 .update_world_mass_properties(rb.body_type, &rb.pos.position);
250 let effective_mass = rb.mprops.effective_mass();
251 rb.forces
252 .compute_effective_force_and_torque(gravity, effective_mass);
253 }
254 self.counters.stages.update_time.pause();
255
256 self.counters.stages.solver_time.resume();
257 if self.solvers.len() < num_active_islands {
258 self.solvers
259 .resize_with(num_active_islands, IslandSolver::new);
260 }
261
262 #[cfg(not(feature = "parallel"))]
263 {
264 enable_flush_to_zero!();
265
266 for (island_awake_id, island_id) in islands.active_islands().iter().enumerate() {
267 self.solvers[island_awake_id].init_and_solve(
268 *island_id,
269 &mut self.counters,
270 integration_parameters,
271 islands,
272 bodies,
273 &mut manifolds[..],
274 &self.manifold_indices[island_awake_id],
275 impulse_joints.joints_mut(),
276 &self.joint_constraint_indices[island_awake_id],
277 multibody_joints,
278 )
279 }
280 }
281
282 #[cfg(feature = "parallel")]
283 {
284 use crate::geometry::ContactManifold;
285 use rayon::prelude::*;
286 use std::sync::atomic::Ordering;
287
288 let solvers = &mut self.solvers[..num_active_islands];
289 let bodies = &std::sync::atomic::AtomicPtr::new(bodies as *mut _);
290 let manifolds = &std::sync::atomic::AtomicPtr::new(&mut manifolds as *mut _);
291 let impulse_joints =
292 &std::sync::atomic::AtomicPtr::new(impulse_joints.joints_vec_mut() as *mut _);
293 let multibody_joints = &std::sync::atomic::AtomicPtr::new(multibody_joints as *mut _);
294 let manifold_indices = &self.manifold_indices[..];
295 let joint_constraint_indices = &self.joint_constraint_indices[..];
296
297 self.counters.solver.velocity_resolution_time.resume();
301 rayon::scope(|_scope| {
302 enable_flush_to_zero!();
303
304 solvers
305 .par_iter_mut()
306 .enumerate()
307 .for_each(|(island_awake_id, solver)| {
308 let island_id = islands.active_islands()[island_awake_id];
309 let bodies: &mut RigidBodySet =
310 unsafe { &mut *bodies.load(Ordering::Relaxed) };
311 let manifolds: &mut Vec<&mut ContactManifold> =
312 unsafe { &mut *manifolds.load(Ordering::Relaxed) };
313 let impulse_joints: &mut Vec<JointGraphEdge> =
314 unsafe { &mut *impulse_joints.load(Ordering::Relaxed) };
315 let multibody_joints: &mut MultibodyJointSet =
316 unsafe { &mut *multibody_joints.load(Ordering::Relaxed) };
317
318 let mut counters = Counters::new(false);
319 solver.init_and_solve(
320 island_id,
321 &mut counters,
322 integration_parameters,
323 islands,
324 bodies,
325 &mut manifolds[..],
326 &manifold_indices[island_awake_id],
327 impulse_joints,
328 &joint_constraint_indices[island_awake_id],
329 multibody_joints,
330 )
331 });
332 });
333 self.counters.solver.velocity_resolution_time.pause();
334 }
335
336 let inv_dt = crate::utils::inv(integration_parameters.dt);
338 for pair_id in self.contact_pair_indices.drain(..) {
339 let pair = narrow_phase.contact_pair_at_index(pair_id);
340 let co1 = &colliders[pair.collider1];
341 let co2 = &colliders[pair.collider2];
342 let threshold = co1
343 .effective_contact_force_event_threshold()
344 .min(co2.effective_contact_force_event_threshold());
345
346 if threshold < Real::MAX {
347 let total_magnitude = pair.total_impulse_magnitude() * inv_dt;
348
349 if total_magnitude > threshold {
352 events.handle_contact_force_event(
353 integration_parameters.dt,
354 bodies,
355 colliders,
356 pair,
357 total_magnitude,
358 );
359 }
360 }
361 }
362
363 self.counters.stages.solver_time.pause();
364 }
365
366 fn run_ccd_motion_clamping(
367 &mut self,
368 integration_parameters: &IntegrationParameters,
369 islands: &IslandManager,
370 bodies: &mut RigidBodySet,
371 colliders: &mut ColliderSet,
372 broad_phase: &mut BroadPhaseBvh,
373 narrow_phase: &NarrowPhase,
374 ccd_solver: &mut CCDSolver,
375 events: &dyn EventHandler,
376 ) {
377 self.counters.ccd.toi_computation_time.start();
378 let impacts = ccd_solver.predict_impacts_at_next_positions(
380 integration_parameters,
381 islands,
382 bodies,
383 colliders,
384 broad_phase,
385 narrow_phase,
386 events,
387 );
388 ccd_solver.clamp_motions(integration_parameters.dt, bodies, &impacts);
389 self.counters.ccd.toi_computation_time.pause();
390 }
391
392 fn advance_to_final_positions(
393 &mut self,
394 islands: &IslandManager,
395 bodies: &mut RigidBodySet,
396 colliders: &mut ColliderSet,
397 modified_colliders: &mut ModifiedColliders,
398 ) {
399 for handle in islands.active_bodies() {
401 let rb = bodies.index_mut_internal(handle);
402 rb.pos.position = rb.pos.next_position;
403 rb.colliders
404 .update_positions(colliders, modified_colliders, &rb.pos.position);
405 }
406 }
407
408 fn interpolate_kinematic_velocities(
409 &mut self,
410 integration_parameters: &IntegrationParameters,
411 islands: &IslandManager,
412 bodies: &mut RigidBodySet,
413 ) {
414 for handle in islands.active_bodies() {
420 let rb = bodies.index_mut_internal(handle);
422
423 match rb.body_type {
424 RigidBodyType::KinematicPositionBased => {
425 rb.vels = rb.pos.interpolate_velocity(
426 integration_parameters.inv_dt(),
427 rb.mprops.local_mprops.local_com,
428 );
429 }
430 RigidBodyType::KinematicVelocityBased => {}
431 _ => {}
432 }
433 }
434 }
435
436 pub fn step(
487 &mut self,
488 gravity: Vector,
489 integration_parameters: &IntegrationParameters,
490 islands: &mut IslandManager,
491 broad_phase: &mut BroadPhaseBvh,
492 narrow_phase: &mut NarrowPhase,
493 bodies: &mut RigidBodySet,
494 colliders: &mut ColliderSet,
495 impulse_joints: &mut ImpulseJointSet,
496 multibody_joints: &mut MultibodyJointSet,
497 ccd_solver: &mut CCDSolver,
498 hooks: &dyn PhysicsHooks,
499 events: &dyn EventHandler,
500 ) {
501 self.counters.reset();
502 self.counters.step_started();
503
504 self.counters.stages.user_changes.start();
506 #[cfg(feature = "enhanced-determinism")]
507 let to_wake_up_iterator = impulse_joints
508 .to_wake_up
509 .drain(..)
510 .chain(multibody_joints.to_wake_up.drain(..));
511 #[cfg(not(feature = "enhanced-determinism"))]
512 let to_wake_up_iterator = impulse_joints
513 .to_wake_up
514 .drain()
515 .chain(multibody_joints.to_wake_up.drain());
516 for handle in to_wake_up_iterator {
517 islands.wake_up(bodies, handle, true);
518 }
519
520 let mut modified_colliders = colliders.take_modified();
522 let mut removed_colliders = colliders.take_removed();
523
524 super::user_changes::handle_user_changes_to_colliders(
525 bodies,
526 colliders,
527 &modified_colliders[..],
528 );
529
530 let mut modified_bodies = bodies.take_modified();
531 super::user_changes::handle_user_changes_to_rigid_bodies(
532 Some(islands),
533 bodies,
534 colliders,
535 impulse_joints,
536 multibody_joints,
537 &modified_bodies,
538 &mut modified_colliders,
539 );
540
541 removed_colliders.extend(
545 modified_colliders
546 .iter()
547 .copied()
548 .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
549 );
550
551 #[cfg(feature = "enhanced-determinism")]
553 let to_join_iterator = impulse_joints
554 .to_join
555 .drain(..)
556 .chain(multibody_joints.to_join.drain(..));
557 #[cfg(not(feature = "enhanced-determinism"))]
558 let to_join_iterator = impulse_joints
559 .to_join
560 .drain()
561 .chain(multibody_joints.to_join.drain());
562 for (handle1, handle2) in to_join_iterator {
563 islands.interaction_started_or_stopped(
564 bodies,
565 Some(handle1),
566 Some(handle2),
567 true,
568 false,
569 );
570 }
571 self.counters.stages.user_changes.pause();
572
573 for multibody in &mut multibody_joints.multibodies {
576 multibody.1.forward_kinematics(bodies, true);
577 multibody
578 .1
579 .update_rigid_bodies_internal(bodies, true, false, false);
580 }
581
582 self.detect_collisions(
583 integration_parameters,
584 islands,
585 broad_phase,
586 narrow_phase,
587 bodies,
588 colliders,
589 impulse_joints,
590 multibody_joints,
591 &modified_colliders,
592 &removed_colliders,
593 hooks,
594 events,
595 true,
596 );
597
598 self.counters.stages.user_changes.resume();
599 self.clear_modified_colliders(colliders, &mut modified_colliders);
600 self.clear_modified_bodies(bodies, &mut modified_bodies);
601 removed_colliders.clear();
602 self.counters.stages.user_changes.pause();
603
604 let mut remaining_time = integration_parameters.dt;
605 let mut integration_parameters = *integration_parameters;
606
607 let (ccd_is_enabled, mut remaining_substeps) =
608 if integration_parameters.max_ccd_substeps == 0 {
609 (false, 1)
610 } else {
611 (true, integration_parameters.max_ccd_substeps)
612 };
613
614 while remaining_substeps > 0 {
615 if ccd_is_enabled && remaining_substeps > 1 {
626 let ccd_active =
629 ccd_solver.update_ccd_active_flags(islands, bodies, remaining_time, true);
630 let first_impact = if ccd_active {
631 ccd_solver.find_first_impact(
632 remaining_time,
633 &integration_parameters,
634 islands,
635 bodies,
636 colliders,
637 broad_phase,
638 narrow_phase,
639 )
640 } else {
641 None
642 };
643
644 if let Some(toi) = first_impact {
645 let original_interval = remaining_time / (remaining_substeps as Real);
646
647 if toi < original_interval {
648 integration_parameters.dt = original_interval;
649 } else {
650 integration_parameters.dt =
651 toi + (remaining_time - toi) / (remaining_substeps as Real);
652 }
653
654 remaining_substeps -= 1;
655 } else {
656 integration_parameters.dt = remaining_time;
658 remaining_substeps = 0;
659 }
660
661 remaining_time -= integration_parameters.dt;
662
663 if remaining_time <= integration_parameters.min_ccd_dt {
665 integration_parameters.dt += remaining_time;
666 remaining_substeps = 0;
667 }
668 } else {
669 integration_parameters.dt = remaining_time;
670 remaining_time = 0.0;
671 remaining_substeps = 0;
672 }
673
674 self.counters.ccd.num_substeps += 1;
675
676 self.counters.custom.resume();
677 self.interpolate_kinematic_velocities(&integration_parameters, islands, bodies);
678 self.counters.custom.pause();
679 self.build_islands_and_solve_velocity_constraints(
680 gravity,
681 &integration_parameters,
682 islands,
683 narrow_phase,
684 bodies,
685 colliders,
686 impulse_joints,
687 multibody_joints,
688 events,
689 );
690
691 if ccd_is_enabled {
693 let ccd_active = ccd_solver.update_ccd_active_flags(
696 islands,
697 bodies,
698 integration_parameters.dt,
699 false,
700 );
701 if ccd_active {
702 self.run_ccd_motion_clamping(
703 &integration_parameters,
704 islands,
705 bodies,
706 colliders,
707 broad_phase,
708 narrow_phase,
709 ccd_solver,
710 events,
711 );
712 }
713 }
714
715 self.counters.stages.update_time.resume();
716 self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders);
717 self.counters.stages.update_time.pause();
718
719 if remaining_substeps > 0 {
720 self.detect_collisions(
721 &integration_parameters,
722 islands,
723 broad_phase,
724 narrow_phase,
725 bodies,
726 colliders,
727 impulse_joints,
728 multibody_joints,
729 &modified_colliders,
730 &[],
731 hooks,
732 events,
733 false,
734 );
735
736 self.clear_modified_colliders(colliders, &mut modified_colliders);
737 } else {
738 self.counters.stages.collision_detection_time.resume();
741 self.counters.cd.final_broad_phase_time.resume();
742 for handle in modified_colliders.iter() {
743 let co = colliders.index_mut_internal(*handle);
744 if co.is_enabled() {
751 let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies);
752 broad_phase.set_aabb(&integration_parameters, *handle, aabb);
753 }
754
755 co.changes.remove(ColliderChanges::IN_MODIFIED_SET);
765 }
766
767 modified_colliders.clear();
769 self.counters.cd.final_broad_phase_time.pause();
770 self.counters.stages.collision_detection_time.pause();
771 }
772 }
773
774 self.counters.stages.update_time.resume();
781 for handle in islands.active_bodies() {
782 let rb = bodies.index_mut_internal(handle);
783 rb.mprops
784 .update_world_mass_properties(rb.body_type, &rb.pos.position);
785 }
786 self.counters.stages.update_time.pause();
787
788 colliders.set_modified(modified_colliders);
790
791 self.counters.step_completed();
792 }
793}
794
795#[cfg(test)]
796mod test {
797 use crate::dynamics::{
798 CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, RigidBodyBuilder,
799 RigidBodySet,
800 };
801 use crate::geometry::{BroadPhaseBvh, ColliderBuilder, ColliderSet, NarrowPhase};
802 #[cfg(feature = "dim2")]
803 use crate::math::Rotation;
804 use crate::math::Vector;
805 use crate::pipeline::PhysicsPipeline;
806 use crate::prelude::{MultibodyJointSet, RevoluteJointBuilder, RigidBodyType};
807
808 #[test]
809 fn kinematic_and_fixed_contact_crash() {
810 let mut colliders = ColliderSet::new();
811 let mut impulse_joints = ImpulseJointSet::new();
812 let mut multibody_joints = MultibodyJointSet::new();
813 let mut pipeline = PhysicsPipeline::new();
814 let mut bf = BroadPhaseBvh::new();
815 let mut nf = NarrowPhase::new();
816 let mut bodies = RigidBodySet::new();
817 let mut islands = IslandManager::new();
818
819 let rb = RigidBodyBuilder::fixed().build();
820 let h1 = bodies.insert(rb.clone());
821 let co = ColliderBuilder::ball(10.0).build();
822 colliders.insert_with_parent(co.clone(), h1, &mut bodies);
823
824 let rb = RigidBodyBuilder::kinematic_position_based().build();
826 let h2 = bodies.insert(rb.clone());
827 colliders.insert_with_parent(co, h2, &mut bodies);
828
829 pipeline.step(
830 Vector::ZERO,
831 &IntegrationParameters::default(),
832 &mut islands,
833 &mut bf,
834 &mut nf,
835 &mut bodies,
836 &mut colliders,
837 &mut impulse_joints,
838 &mut multibody_joints,
839 &mut CCDSolver::new(),
840 &(),
841 &(),
842 );
843 }
844
845 #[test]
846 fn rigid_body_removal_before_step() {
847 let mut colliders = ColliderSet::new();
848 let mut impulse_joints = ImpulseJointSet::new();
849 let mut multibody_joints = MultibodyJointSet::new();
850 let mut pipeline = PhysicsPipeline::new();
851 let mut bf = BroadPhaseBvh::new();
852 let mut nf = NarrowPhase::new();
853 let mut islands = IslandManager::new();
854
855 let mut bodies = RigidBodySet::new();
856
857 let rb = RigidBodyBuilder::dynamic().build();
861 let h1 = bodies.insert(rb.clone());
862 let h2 = bodies.insert(rb.clone());
863
864 let rb = RigidBodyBuilder::kinematic_position_based().build();
866 let h3 = bodies.insert(rb.clone());
867
868 let rb = RigidBodyBuilder::fixed().build();
870 let h4 = bodies.insert(rb.clone());
871
872 let to_delete = [h1, h2, h3, h4];
873 for h in &to_delete {
874 bodies.remove(
875 *h,
876 &mut islands,
877 &mut colliders,
878 &mut impulse_joints,
879 &mut multibody_joints,
880 true,
881 );
882 }
883
884 pipeline.step(
885 Vector::ZERO,
886 &IntegrationParameters::default(),
887 &mut islands,
888 &mut bf,
889 &mut nf,
890 &mut bodies,
891 &mut colliders,
892 &mut impulse_joints,
893 &mut multibody_joints,
894 &mut CCDSolver::new(),
895 &(),
896 &(),
897 );
898 }
899
900 #[cfg(feature = "serde-serialize")]
901 #[test]
902 fn rigid_body_removal_snapshot_handle_determinism() {
903 let mut colliders = ColliderSet::new();
904 let mut impulse_joints = ImpulseJointSet::new();
905 let mut multibody_joints = MultibodyJointSet::new();
906 let mut islands = IslandManager::new();
907
908 let mut bodies = RigidBodySet::new();
909 let rb = RigidBodyBuilder::dynamic().build();
910 let h1 = bodies.insert(rb.clone());
911 let h2 = bodies.insert(rb.clone());
912 let h3 = bodies.insert(rb.clone());
913
914 bodies.remove(
915 h1,
916 &mut islands,
917 &mut colliders,
918 &mut impulse_joints,
919 &mut multibody_joints,
920 true,
921 );
922 bodies.remove(
923 h3,
924 &mut islands,
925 &mut colliders,
926 &mut impulse_joints,
927 &mut multibody_joints,
928 true,
929 );
930 bodies.remove(
931 h2,
932 &mut islands,
933 &mut colliders,
934 &mut impulse_joints,
935 &mut multibody_joints,
936 true,
937 );
938
939 let ser_bodies = bincode::serialize(&bodies).unwrap();
940 let mut bodies2: RigidBodySet = bincode::deserialize(&ser_bodies).unwrap();
941
942 let h1a = bodies.insert(rb.clone());
943 let h2a = bodies.insert(rb.clone());
944 let h3a = bodies.insert(rb.clone());
945
946 let h1b = bodies2.insert(rb.clone());
947 let h2b = bodies2.insert(rb.clone());
948 let h3b = bodies2.insert(rb.clone());
949
950 assert_eq!(h1a, h1b);
951 assert_eq!(h2a, h2b);
952 assert_eq!(h3a, h3b);
953 }
954
955 #[test]
956 fn collider_removal_before_step() {
957 let mut pipeline = PhysicsPipeline::new();
958 let gravity = Vector::Y * -9.81;
959 let integration_parameters = IntegrationParameters::default();
960 let mut broad_phase = BroadPhaseBvh::new();
961 let mut narrow_phase = NarrowPhase::new();
962 let mut bodies = RigidBodySet::new();
963 let mut colliders = ColliderSet::new();
964 let mut ccd = CCDSolver::new();
965 let mut impulse_joints = ImpulseJointSet::new();
966 let mut multibody_joints = MultibodyJointSet::new();
967 let mut islands = IslandManager::new();
968 let physics_hooks = ();
969 let event_handler = ();
970
971 let body = RigidBodyBuilder::dynamic().build();
972 let b_handle = bodies.insert(body);
973 let collider = ColliderBuilder::ball(1.0).build();
974 let c_handle = colliders.insert_with_parent(collider, b_handle, &mut bodies);
975 colliders.remove(c_handle, &mut islands, &mut bodies, true);
976 bodies.remove(
977 b_handle,
978 &mut islands,
979 &mut colliders,
980 &mut impulse_joints,
981 &mut multibody_joints,
982 true,
983 );
984
985 for _ in 0..10 {
986 pipeline.step(
987 gravity,
988 &integration_parameters,
989 &mut islands,
990 &mut broad_phase,
991 &mut narrow_phase,
992 &mut bodies,
993 &mut colliders,
994 &mut impulse_joints,
995 &mut multibody_joints,
996 &mut ccd,
997 &physics_hooks,
998 &event_handler,
999 );
1000 }
1001 }
1002
1003 #[test]
1004 fn rigid_body_type_changed_dynamic_is_in_active_set() {
1005 let mut colliders = ColliderSet::new();
1006 let mut impulse_joints = ImpulseJointSet::new();
1007 let mut multibody_joints = MultibodyJointSet::new();
1008 let mut pipeline = PhysicsPipeline::new();
1009 let mut bf = BroadPhaseBvh::new();
1010 let mut nf = NarrowPhase::new();
1011 let mut islands = IslandManager::new();
1012
1013 let mut bodies = RigidBodySet::new();
1014
1015 let rb = RigidBodyBuilder::kinematic_position_based()
1017 .additional_mass(1.0)
1018 .build();
1019 let h = bodies.insert(rb.clone());
1020
1021 let gravity = Vector::Y * -9.81;
1023 pipeline.step(
1024 gravity,
1025 &IntegrationParameters::default(),
1026 &mut islands,
1027 &mut bf,
1028 &mut nf,
1029 &mut bodies,
1030 &mut colliders,
1031 &mut impulse_joints,
1032 &mut multibody_joints,
1033 &mut CCDSolver::new(),
1034 &(),
1035 &(),
1036 );
1037
1038 bodies
1040 .get_mut(h)
1041 .unwrap()
1042 .set_body_type(RigidBodyType::Dynamic, true);
1043
1044 pipeline.step(
1046 gravity,
1047 &IntegrationParameters::default(),
1048 &mut islands,
1049 &mut bf,
1050 &mut nf,
1051 &mut bodies,
1052 &mut colliders,
1053 &mut impulse_joints,
1054 &mut multibody_joints,
1055 &mut CCDSolver::new(),
1056 &(),
1057 &(),
1058 );
1059
1060 let body = bodies.get(h).unwrap();
1061 let h_y = body.pos.position.translation.y;
1062
1063 assert!(h_y < 0.0);
1065
1066 assert!(!body.is_sleeping());
1068 }
1069
1070 #[test]
1071 fn joint_step_delta_time_0() {
1072 let mut colliders = ColliderSet::new();
1073 let mut impulse_joints = ImpulseJointSet::new();
1074 let mut multibody_joints = MultibodyJointSet::new();
1075 let mut pipeline = PhysicsPipeline::new();
1076 let mut bf = BroadPhaseBvh::new();
1077 let mut nf = NarrowPhase::new();
1078 let mut islands = IslandManager::new();
1079
1080 let mut bodies = RigidBodySet::new();
1081
1082 let rb = RigidBodyBuilder::fixed().additional_mass(1.0).build();
1084 let h = bodies.insert(rb.clone());
1085 let rb_dynamic = RigidBodyBuilder::dynamic().additional_mass(1.0).build();
1086 let h_dynamic = bodies.insert(rb_dynamic.clone());
1087
1088 #[cfg(feature = "dim2")]
1090 let joint = RevoluteJointBuilder::new()
1091 .local_anchor1(Vector::new(0.0, 1.0))
1092 .local_anchor2(Vector::new(0.0, -3.0));
1093 #[cfg(feature = "dim3")]
1094 let joint = RevoluteJointBuilder::new(Vector::Z)
1095 .local_anchor1(Vector::new(0.0, 1.0, 0.0))
1096 .local_anchor2(Vector::new(0.0, -3.0, 0.0));
1097 impulse_joints.insert(h, h_dynamic, joint, true);
1098
1099 let parameters = IntegrationParameters {
1100 dt: 0.0,
1101 ..Default::default()
1102 };
1103 let gravity = Vector::Y * -9.81;
1105 pipeline.step(
1106 gravity,
1107 ¶meters,
1108 &mut islands,
1109 &mut bf,
1110 &mut nf,
1111 &mut bodies,
1112 &mut colliders,
1113 &mut impulse_joints,
1114 &mut multibody_joints,
1115 &mut CCDSolver::new(),
1116 &(),
1117 &(),
1118 );
1119 let translation = bodies[h_dynamic].translation();
1120 let rotation = bodies[h_dynamic].rotation();
1121 assert!(translation.x.is_finite());
1122 assert!(translation.y.is_finite());
1123 #[cfg(feature = "dim2")]
1124 {
1125 assert!(rotation.re.is_finite());
1126 assert!(rotation.im.is_finite());
1127 }
1128 #[cfg(feature = "dim3")]
1129 {
1130 assert!(translation.z.is_finite());
1131 assert!(rotation.x.is_finite());
1132 assert!(rotation.y.is_finite());
1133 assert!(rotation.z.is_finite());
1134 assert!(rotation.w.is_finite());
1135 }
1136 }
1137
1138 #[test]
1139 #[cfg(feature = "dim2")]
1140 fn test_multi_sap_disable_body() {
1141 let mut rigid_body_set = RigidBodySet::new();
1142 let mut collider_set = ColliderSet::new();
1143
1144 let collider = ColliderBuilder::cuboid(100.0, 0.1);
1146 collider_set.insert(collider);
1147
1148 let rigid_body = RigidBodyBuilder::dynamic().translation(Vector::new(0.0, 10.0));
1150 let collider = ColliderBuilder::ball(0.5).restitution(0.7);
1151 let ball_body_handle = rigid_body_set.insert(rigid_body);
1152 collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);
1153
1154 let gravity = Vector::new(0.0, -9.81);
1156 let integration_parameters = IntegrationParameters::default();
1157 let mut physics_pipeline = PhysicsPipeline::new();
1158 let mut island_manager = IslandManager::new();
1159 let mut broad_phase = BroadPhaseBvh::new();
1160 let mut narrow_phase = NarrowPhase::new();
1161 let mut impulse_joint_set = ImpulseJointSet::new();
1162 let mut multibody_joint_set = MultibodyJointSet::new();
1163 let mut ccd_solver = CCDSolver::new();
1164 let physics_hooks = ();
1165 let event_handler = ();
1166
1167 physics_pipeline.step(
1168 gravity,
1169 &integration_parameters,
1170 &mut island_manager,
1171 &mut broad_phase,
1172 &mut narrow_phase,
1173 &mut rigid_body_set,
1174 &mut collider_set,
1175 &mut impulse_joint_set,
1176 &mut multibody_joint_set,
1177 &mut ccd_solver,
1178 &physics_hooks,
1179 &event_handler,
1180 );
1181
1182 {
1184 let ball_body = &mut rigid_body_set[ball_body_handle];
1185
1186 ball_body.set_translation(Vector::new(1.0, 1.0), true);
1188 ball_body.set_rotation(Rotation::from_angle(1.0), true);
1189 ball_body.set_enabled(false);
1190 }
1191
1192 physics_pipeline.step(
1193 gravity,
1194 &integration_parameters,
1195 &mut island_manager,
1196 &mut broad_phase,
1197 &mut narrow_phase,
1198 &mut rigid_body_set,
1199 &mut collider_set,
1200 &mut impulse_joint_set,
1201 &mut multibody_joint_set,
1202 &mut ccd_solver,
1203 &physics_hooks,
1204 &event_handler,
1205 );
1206
1207 {
1209 let ball_body = &mut rigid_body_set[ball_body_handle];
1210
1211 ball_body.set_translation(Vector::new(0.0, 0.0), true);
1213 ball_body.set_rotation(Rotation::from_angle(0.0), true);
1214 ball_body.set_enabled(true);
1215 }
1216
1217 physics_pipeline.step(
1218 gravity,
1219 &integration_parameters,
1220 &mut island_manager,
1221 &mut broad_phase,
1222 &mut narrow_phase,
1223 &mut rigid_body_set,
1224 &mut collider_set,
1225 &mut impulse_joint_set,
1226 &mut multibody_joint_set,
1227 &mut ccd_solver,
1228 &physics_hooks,
1229 &event_handler,
1230 );
1231 }
1232}