1use core::cell::RefCell;
2use core::marker::PhantomData;
3
4use crate::{
5 collider_tree::{
6 ColliderTree, ColliderTreeDiagnostics, ColliderTreeProxy, ColliderTreeProxyKey,
7 ColliderTreeSystems, ColliderTreeType, ColliderTrees, ProxyId,
8 tree::ColliderTreeProxyFlags,
9 },
10 collision::collider::EnlargedAabb,
11 data_structures::bit_vec::BitVec,
12 dynamics::solver::solver_body::SolverBody,
13 prelude::*,
14 schedule::LastPhysicsTick,
15};
16use bevy::{
17 ecs::{
18 change_detection::Tick,
19 entity_disabling::Disabled,
20 query::QueryFilter,
21 system::{StaticSystemParam, SystemChangeTick},
22 },
23 platform::collections::HashSet,
24 prelude::*,
25};
26use obvhs::aabb::Aabb;
27use thread_local::ThreadLocal;
28
29const AABB_MARGIN: Scalar = 0.05;
35
36pub(super) struct ColliderTreeUpdatePlugin<C: AnyCollider>(PhantomData<C>);
40
41impl<C: AnyCollider> Default for ColliderTreeUpdatePlugin<C> {
42 fn default() -> Self {
43 Self(PhantomData)
44 }
45}
46
47impl<C: AnyCollider> Plugin for ColliderTreeUpdatePlugin<C> {
48 fn build(&self, app: &mut App) {
49 app.init_resource::<MovedProxies>()
51 .init_resource::<EnlargedProxies>()
52 .init_resource::<LastDynamicKinematicAabbUpdate>();
53
54 app.add_systems(
57 PhysicsSchedule,
58 update_moved_collider_aabbs::<C>
59 .in_set(ColliderTreeSystems::UpdateAabbs)
60 .ambiguous_with_all(),
63 );
64
65 app.add_systems(
67 PhysicsSchedule,
68 (clear_moved_proxies, update_solver_body_aabbs::<C>)
69 .chain()
70 .after(PhysicsStepSystems::Finalize)
71 .before(PhysicsStepSystems::Last),
72 );
73
74 app.add_observer(
76 |trigger: On<Add, C>,
77 mut query: Query<(
78 &C,
79 &Position,
80 &Rotation,
81 Option<&CollisionMargin>,
82 &mut ColliderAabb,
83 &mut EnlargedAabb,
84 )>,
85 narrow_phase_config: Res<NarrowPhaseConfig>,
86 length_unit: Res<PhysicsLengthUnit>,
87 collider_context: StaticSystemParam<C::Context>| {
88 let contact_tolerance = length_unit.0 * narrow_phase_config.contact_tolerance;
89 let margin = length_unit.0 * AABB_MARGIN;
90
91 if let Ok((collider, pos, rot, collision_margin, mut aabb, mut enlarged_aabb)) =
92 query.get_mut(trigger.entity)
93 {
94 let collision_margin = collision_margin.map_or(0.0, |m| m.0);
95
96 let context = AabbContext::new(trigger.entity, &*collider_context);
99 let growth = Vector::splat(contact_tolerance + collision_margin);
100 *aabb = collider
101 .aabb_with_context(pos.0, *rot, context)
102 .grow(growth);
103
104 enlarged_aabb.update(&aabb, margin);
105 }
106 },
107 );
108
109 app.add_observer(add_to_tree_on::<Insert, (C, ColliderOf), Without<ColliderDisabled>>);
125
126 app.add_observer(remove_from_tree_on::<Remove, C, Allow<Disabled>>);
132
133 app.add_observer(
135 |trigger: On<Remove, ColliderOf>,
136 mut collider_query: Query<
137 (
138 &ColliderTreeProxyKey,
139 &EnlargedAabb,
140 Option<&CollisionLayers>,
141 Has<Sensor>,
142 Has<CollisionEventsEnabled>,
143 Option<&ActiveCollisionHooks>,
144 ),
145 (With<C>, Without<ColliderDisabled>),
146 >,
147 mut trees: ResMut<ColliderTrees>,
148 mut moved_proxies: ResMut<MovedProxies>| {
149 let entity = trigger.entity;
150
151 let Ok((
152 proxy_key,
153 enlarged_aabb,
154 layers,
155 is_sensor,
156 has_contact_events,
157 active_hooks,
158 )) = collider_query.get_mut(entity)
159 else {
160 return;
161 };
162
163 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
165 if tree.remove_proxy(proxy_key.id()).is_none() {
166 return;
167 }
168 moved_proxies.remove(proxy_key);
169
170 let proxy = ColliderTreeProxy {
172 collider: entity,
173 body: None,
174 layers: layers.copied().unwrap_or_default(),
175 flags: ColliderTreeProxyFlags::new(
176 is_sensor,
177 false,
178 has_contact_events,
179 active_hooks.copied().unwrap_or_default(),
180 ),
181 };
182
183 let standalone_tree = &mut trees.standalone_tree;
184 let proxy_id = standalone_tree.add_proxy(Aabb::from(enlarged_aabb.get()), proxy);
185 let new_proxy_key =
186 ColliderTreeProxyKey::new(proxy_id, ColliderTreeType::Standalone);
187
188 moved_proxies.insert(new_proxy_key);
190 },
191 );
192
193 app.add_observer(
196 add_to_tree_on::<Replace, Disabled, (Without<ColliderDisabled>, Allow<Disabled>)>,
197 );
198 app.add_observer(add_to_tree_on::<Replace, ColliderDisabled, ()>);
199
200 app.add_observer(
202 remove_from_tree_on::<Add, Disabled, (Without<ColliderDisabled>, Allow<Disabled>)>,
203 );
204 app.add_observer(remove_from_tree_on::<Add, ColliderDisabled, ()>);
205
206 app.add_observer(
208 |trigger: On<Insert, RigidBody>,
209 body_query: Query<(&RigidBody, &RigidBodyColliders, Has<RigidBodyDisabled>)>,
210 mut collider_query: Query<
211 (
212 &EnlargedAabb,
213 &mut ColliderTreeProxyKey,
214 Option<&CollisionLayers>,
215 Has<Sensor>,
216 Has<CollisionEventsEnabled>,
217 Option<&ActiveCollisionHooks>,
218 ),
219 Without<ColliderDisabled>,
220 >,
221 mut trees: ResMut<ColliderTrees>,
222 mut moved_proxies: ResMut<MovedProxies>| {
223 let entity = trigger.entity;
224
225 let Ok((new_rb, body_colliders, is_body_disabled)) = body_query.get(entity) else {
226 return;
227 };
228
229 for collider_entity in body_colliders.iter() {
230 let Ok((
231 enlarged_aabb,
232 mut proxy_key,
233 layers,
234 is_sensor,
235 has_contact_events,
236 active_hooks,
237 )) = collider_query.get_mut(collider_entity)
238 else {
239 continue;
240 };
241
242 let new_tree_type = ColliderTreeType::from_body(Some(*new_rb));
243
244 if new_tree_type == proxy_key.tree_type() {
245 break;
247 }
248
249 let old_tree = trees.tree_for_type_mut(proxy_key.tree_type());
251 old_tree.remove_proxy(proxy_key.id());
252 moved_proxies.remove(&proxy_key);
253
254 let enlarged_aabb = Aabb::from(enlarged_aabb.get());
256
257 let proxy = ColliderTreeProxy {
258 collider: collider_entity,
259 body: Some(entity),
260 layers: layers.copied().unwrap_or_default(),
261 flags: ColliderTreeProxyFlags::new(
262 is_sensor,
263 is_body_disabled,
264 has_contact_events,
265 active_hooks.copied().unwrap_or_default(),
266 ),
267 };
268
269 let new_tree = trees.tree_for_type_mut(new_tree_type);
270 let proxy_id = new_tree.add_proxy(enlarged_aabb, proxy);
271 let new_proxy_key = ColliderTreeProxyKey::new(proxy_id, new_tree_type);
272
273 *proxy_key = new_proxy_key;
275
276 moved_proxies.insert(new_proxy_key);
278 }
279 },
280 );
281
282 app.add_observer(
284 |trigger: On<Add, Sensor>,
285 mut collider_query: Query<&ColliderTreeProxyKey, Without<ColliderDisabled>>,
286 mut trees: ResMut<ColliderTrees>| {
287 let entity = trigger.entity;
288
289 let Ok(proxy_key) = collider_query.get_mut(entity) else {
290 return;
291 };
292
293 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
294
295 if let Some(proxy) = tree.get_proxy_mut(proxy_key.id()) {
297 proxy.flags.insert(ColliderTreeProxyFlags::SENSOR);
298 }
299 },
300 );
301
302 app.add_observer(
304 |trigger: On<Remove, Sensor>,
305 mut collider_query: Query<&ColliderTreeProxyKey, Without<ColliderDisabled>>,
306 mut trees: ResMut<ColliderTrees>| {
307 let entity = trigger.entity;
308
309 let Ok(proxy_key) = collider_query.get_mut(entity) else {
310 return;
311 };
312
313 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
314
315 if let Some(proxy) = tree.get_proxy_mut(proxy_key.id()) {
317 proxy.flags.remove(ColliderTreeProxyFlags::SENSOR);
318 }
319 },
320 );
321
322 app.add_observer(
324 |trigger: On<Insert, CollisionLayers>,
325 mut collider_query: Query<
326 (&ColliderTreeProxyKey, Option<&CollisionLayers>),
327 Without<ColliderDisabled>,
328 >,
329 mut trees: ResMut<ColliderTrees>| {
330 let entity = trigger.entity;
331
332 let Ok((proxy_key, layers)) = collider_query.get_mut(entity) else {
333 return;
334 };
335
336 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
337
338 if let Some(proxy) = tree.get_proxy_mut(proxy_key.id()) {
340 proxy.layers = layers.copied().unwrap_or_default();
341 }
342 },
343 );
344
345 app.add_observer(
347 |trigger: On<Insert, ActiveCollisionHooks>,
348 mut collider_query: Query<
349 (&ColliderTreeProxyKey, Option<&ActiveCollisionHooks>),
350 Without<ColliderDisabled>,
351 >,
352 mut trees: ResMut<ColliderTrees>| {
353 let entity = trigger.entity;
354
355 let Ok((proxy_key, active_hooks)) = collider_query.get_mut(entity) else {
356 return;
357 };
358
359 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
360
361 if let Some(proxy) = tree.get_proxy_mut(proxy_key.id()) {
363 proxy.flags.set(
364 ColliderTreeProxyFlags::CUSTOM_FILTER,
365 active_hooks
366 .is_some_and(|h| h.contains(ActiveCollisionHooks::FILTER_PAIRS)),
367 );
368 }
369 },
370 );
371
372 app.add_observer(
374 |trigger: On<Replace, RigidBodyDisabled>,
375 body_query: Query<(&RigidBodyColliders, Has<RigidBodyDisabled>)>,
376 mut collider_query: Query<&ColliderTreeProxyKey, Without<ColliderDisabled>>,
377 mut trees: ResMut<ColliderTrees>| {
378 let entity = trigger.entity;
379
380 let Ok((body_colliders, is_body_disabled)) = body_query.get(entity) else {
381 return;
382 };
383
384 for collider_entity in body_colliders.iter() {
385 let Ok(proxy_key) = collider_query.get_mut(collider_entity) else {
386 continue;
387 };
388
389 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
390
391 if let Some(proxy) = tree.get_proxy_mut(proxy_key.id()) {
393 proxy
394 .flags
395 .set(ColliderTreeProxyFlags::BODY_DISABLED, is_body_disabled);
396 }
397 }
398 },
399 );
400 }
401}
402
403fn add_to_tree_on<E: EntityEvent, B: Bundle, F: QueryFilter>(
405 trigger: On<E, B>,
406 body_query: Query<(&RigidBody, Has<RigidBodyDisabled>), Allow<Disabled>>,
407 mut collider_query: Query<
408 (
409 Option<&ColliderOf>,
410 &EnlargedAabb,
411 &mut ColliderTreeProxyKey,
412 Option<&CollisionLayers>,
413 Has<Sensor>,
414 Has<CollisionEventsEnabled>,
415 Option<&ActiveCollisionHooks>,
416 ),
417 F,
418 >,
419 mut trees: ResMut<ColliderTrees>,
420 mut moved_proxies: ResMut<MovedProxies>,
421) {
422 let entity = trigger.event_target();
423
424 let Ok((
425 collider_of,
426 enlarged_aabb,
427 mut proxy_key,
428 layers,
429 is_sensor,
430 has_contact_events,
431 active_hooks,
432 )) = collider_query.get_mut(entity)
433 else {
434 return;
435 };
436
437 let (tree_type, is_body_disabled) =
438 if let Some(Ok((rb, disabled))) = collider_of.map(|c| body_query.get(c.body)) {
439 (ColliderTreeType::from_body(Some(*rb)), disabled)
440 } else {
441 (ColliderTreeType::Standalone, false)
442 };
443
444 let proxy = ColliderTreeProxy {
445 collider: entity,
446 body: collider_of.map(|c| c.body),
447 layers: layers.copied().unwrap_or_default(),
448 flags: ColliderTreeProxyFlags::new(
449 is_sensor,
450 is_body_disabled,
451 has_contact_events,
452 active_hooks.copied().unwrap_or_default(),
453 ),
454 };
455
456 if *proxy_key != ColliderTreeProxyKey::PLACEHOLDER {
458 let old_tree_type = proxy_key.tree_type();
459 let old_tree = trees.tree_for_type_mut(old_tree_type);
460 old_tree.remove_proxy(proxy_key.id());
461 moved_proxies.remove(&proxy_key);
462 }
463
464 let tree = trees.tree_for_type_mut(tree_type);
466 let proxy_id = tree.add_proxy(Aabb::from(enlarged_aabb.get()), proxy);
467
468 *proxy_key = ColliderTreeProxyKey::new(proxy_id, tree_type);
470
471 moved_proxies.insert(*proxy_key);
473}
474
475fn remove_from_tree_on<E: EntityEvent, B: Bundle, F: QueryFilter>(
477 trigger: On<E, B>,
478 mut collider_query: Query<&mut ColliderTreeProxyKey, F>,
479 mut trees: ResMut<ColliderTrees>,
480 mut moved_proxies: ResMut<MovedProxies>,
481) {
482 let entity = trigger.event_target();
483
484 let Ok(mut proxy_key) = collider_query.get_mut(entity) else {
485 return;
486 };
487
488 if *proxy_key == ColliderTreeProxyKey::PLACEHOLDER {
489 return;
490 }
491
492 let tree = trees.tree_for_type_mut(proxy_key.tree_type());
494 tree.remove_proxy(proxy_key.id());
495 moved_proxies.remove(&proxy_key);
496
497 *proxy_key = ColliderTreeProxyKey::PLACEHOLDER;
499}
500
501#[derive(Resource, Default)]
504struct LastDynamicKinematicAabbUpdate(Tick);
505
506#[derive(Resource, Default)]
513pub struct MovedProxies {
514 proxies: Vec<ColliderTreeProxyKey>,
516 set: HashSet<ColliderTreeProxyKey>,
518}
519
520impl MovedProxies {
521 #[inline]
525 pub fn proxies(&self) -> &[ColliderTreeProxyKey] {
526 &self.proxies
527 }
528
529 #[inline]
531 pub fn contains(&self, proxy_key: ColliderTreeProxyKey) -> bool {
532 self.set.contains(&proxy_key)
533 }
534
535 #[inline]
539 pub fn insert(&mut self, proxy_key: ColliderTreeProxyKey) -> bool {
540 if self.set.insert(proxy_key) {
541 self.proxies.push(proxy_key);
542 true
543 } else {
544 false
545 }
546 }
547
548 #[inline]
553 pub fn remove(&mut self, proxy_key: &ColliderTreeProxyKey) {
554 if self.set.remove(proxy_key)
555 && let Some(pos) = self.proxies.iter().position(|k| k == proxy_key)
556 {
557 self.proxies.swap_remove(pos);
558 }
559 }
560
561 #[inline]
563 pub fn clear(&mut self) {
564 self.proxies.clear();
565 self.set.clear();
566 }
567}
568
569#[derive(Resource, Default)]
574pub struct EnlargedProxies {
575 dynamic_proxies: EnlargedProxiesBitVec,
581 kinematic_proxies: EnlargedProxiesBitVec,
582 static_proxies: EnlargedProxiesBitVec,
583 standalone_proxies: EnlargedProxiesBitVec,
584}
585
586impl EnlargedProxies {
587 #[inline]
589 pub const fn bit_vec_for_type(&self, tree_type: ColliderTreeType) -> &EnlargedProxiesBitVec {
590 match tree_type {
591 ColliderTreeType::Dynamic => &self.dynamic_proxies,
592 ColliderTreeType::Kinematic => &self.kinematic_proxies,
593 ColliderTreeType::Static => &self.static_proxies,
594 ColliderTreeType::Standalone => &self.standalone_proxies,
595 }
596 }
597
598 #[inline]
600 pub fn bit_vec_for_type_mut(
601 &mut self,
602 tree_type: ColliderTreeType,
603 ) -> &mut EnlargedProxiesBitVec {
604 match tree_type {
605 ColliderTreeType::Dynamic => &mut self.dynamic_proxies,
606 ColliderTreeType::Kinematic => &mut self.kinematic_proxies,
607 ColliderTreeType::Static => &mut self.static_proxies,
608 ColliderTreeType::Standalone => &mut self.standalone_proxies,
609 }
610 }
611}
612
613#[derive(Default)]
620pub struct EnlargedProxiesBitVec {
621 global: BitVec,
622 thread_local: ThreadLocal<RefCell<BitVec>>,
623}
624
625impl EnlargedProxiesBitVec {
626 #[inline]
628 pub fn clear_and_set_capacity(&mut self, capacity: usize) {
629 self.global.set_bit_count_and_clear(capacity);
630 self.thread_local.iter_mut().for_each(|context| {
631 let bit_vec_mut = &mut context.borrow_mut();
632 bit_vec_mut.set_bit_count_and_clear(capacity);
633 });
634 }
635
636 #[inline]
638 pub fn combine_thread_local(&mut self) {
639 self.thread_local.iter_mut().for_each(|context| {
640 let thread_local = context.borrow();
641 self.global.or(&thread_local);
642 });
643 }
644}
645
646fn update_solver_body_aabbs<C: AnyCollider>(
654 body_query: Query<
655 (
656 &Position,
657 &ComputedCenterOfMass,
658 &LinearVelocity,
659 &AngularVelocity,
660 &RigidBodyColliders,
661 Has<SweptCcd>,
662 ),
663 With<SolverBody>,
664 >,
665 mut colliders: ParamSet<(
666 Query<
667 (
668 Ref<C>,
669 &mut ColliderAabb,
670 &mut EnlargedAabb,
671 &ColliderTreeProxyKey,
672 &Position,
673 &Rotation,
674 Option<&CollisionMargin>,
675 Option<&SpeculativeMargin>,
676 ),
677 Without<ColliderDisabled>,
678 >,
679 Query<&EnlargedAabb, Without<ColliderDisabled>>,
680 )>,
681 narrow_phase_config: Res<NarrowPhaseConfig>,
682 length_unit: Res<PhysicsLengthUnit>,
683 mut trees: ResMut<ColliderTrees>,
684 mut moved_proxies: ResMut<MovedProxies>,
685 mut enlarged_proxies: ResMut<EnlargedProxies>,
686 time: Res<Time>,
687 collider_context: StaticSystemParam<C::Context>,
688 mut diagnostics: ResMut<ColliderTreeDiagnostics>,
689 mut last_tick: ResMut<LastDynamicKinematicAabbUpdate>,
690 system_tick: SystemChangeTick,
691) {
692 let start = crate::utils::Instant::now();
693
694 let this_run = system_tick.this_run();
695
696 let cap_dynamic = trees.dynamic_tree.proxies.capacity();
699 let cap_kinematic = trees.kinematic_tree.proxies.capacity();
700
701 let e = &mut enlarged_proxies;
703 e.dynamic_proxies.clear_and_set_capacity(cap_dynamic);
704 e.kinematic_proxies.clear_and_set_capacity(cap_kinematic);
705
706 let delta_secs = time.delta_seconds_adjusted();
707 let default_speculative_margin = length_unit.0 * narrow_phase_config.default_speculative_margin;
708 let contact_tolerance = length_unit.0 * narrow_phase_config.contact_tolerance;
709 let margin = length_unit.0 * AABB_MARGIN;
710
711 let collider_query = colliders.p0();
712
713 body_query.par_iter().for_each(
714 |(rb_pos, center_of_mass, lin_vel, ang_vel, body_colliders, has_swept_ccd)| {
715 for collider_entity in body_colliders.iter() {
716 let Ok((
717 collider,
718 mut aabb,
719 mut enlarged_aabb,
720 proxy_key,
721 pos,
722 rot,
723 collision_margin,
724 speculative_margin,
725 )) = (unsafe { collider_query.get_unchecked(collider_entity) })
726 else {
727 continue;
728 };
729
730 let collision_margin = collision_margin.map_or(0.0, |margin| margin.0);
731 let speculative_margin = if has_swept_ccd {
732 Scalar::MAX
733 } else {
734 speculative_margin.map_or(default_speculative_margin, |margin| margin.0)
735 };
736
737 let context = AabbContext::new(collider_entity, &*collider_context);
738 let growth = Vector::splat(contact_tolerance + collision_margin);
739
740 if speculative_margin <= 0.0 {
741 *aabb = collider
742 .aabb_with_context(pos.0, *rot, context)
743 .grow(growth);
744 } else {
745 let offset = pos.0 - rb_pos.0 - center_of_mass.0;
752 #[cfg(feature = "2d")]
753 let vel = lin_vel.0 + Vector::new(-ang_vel.0 * offset.y, ang_vel.0 * offset.x);
754 #[cfg(feature = "3d")]
755 let vel = lin_vel.0 + ang_vel.cross(offset);
756 let movement = (vel * delta_secs)
757 .clamp_length_max(speculative_margin.max(contact_tolerance));
758
759 #[cfg(feature = "2d")]
761 let (end_pos, end_rot) = (
762 pos.0 + movement,
763 *rot * Rotation::radians(ang_vel.0 * delta_secs),
764 );
765
766 #[cfg(feature = "3d")]
767 let (end_pos, end_rot) = (
768 pos.0 + movement,
769 Rotation(Quaternion::from_scaled_axis(ang_vel.0 * delta_secs) * rot.0)
770 .fast_renormalize(),
771 );
772
773 *aabb = collider
776 .swept_aabb_with_context(pos.0, *rot, end_pos, end_rot, context)
777 .grow(growth);
778 }
779
780 let moved = enlarged_aabb.update(&aabb, margin);
781
782 if moved {
783 let tree_type = proxy_key.tree_type();
784 let mut thread_local_bit_vec = enlarged_proxies
785 .bit_vec_for_type(tree_type)
786 .thread_local
787 .get_or(|| {
788 let capacity = match tree_type {
789 ColliderTreeType::Dynamic => cap_dynamic,
790 ColliderTreeType::Kinematic => cap_kinematic,
791 _ => unreachable!("Static or standalone proxy {proxy_key:?} moved in dynamic AABB update"),
792 };
793 let mut bit_vec = BitVec::new(capacity);
794 bit_vec.set_bit_count_and_clear(capacity);
795 RefCell::new(bit_vec)
796 })
797 .borrow_mut();
798
799 thread_local_bit_vec.set(proxy_key.id().index());
800 }
801 }
802 },
803 );
804
805 let aabb_query = colliders.p1();
807 for &tree_type in &[ColliderTreeType::Dynamic, ColliderTreeType::Kinematic] {
808 let tree = trees.tree_for_type_mut(tree_type);
809 let bit_vec = enlarged_proxies.bit_vec_for_type_mut(tree_type);
810
811 tree.bvh.init_primitives_to_nodes_if_uninit();
812 bit_vec.combine_thread_local();
813
814 update_tree(
815 tree_type,
816 tree,
817 &bit_vec.global,
818 &aabb_query,
819 &mut moved_proxies,
820 |tree, proxy_id, enlarged_aabb| {
821 tree.set_proxy_aabb(proxy_id, enlarged_aabb);
822 },
823 );
824
825 tree.refit_all();
829 }
830
831 last_tick.0 = this_run;
834
835 diagnostics.update += start.elapsed();
836}
837
838pub fn update_moved_collider_aabbs<C: AnyCollider>(
840 mut colliders: ParamSet<(
841 Query<
842 (
843 Entity,
844 Ref<Position>,
845 Ref<Rotation>,
846 &mut ColliderAabb,
847 &mut EnlargedAabb,
848 Ref<C>,
849 Option<&CollisionMargin>,
850 &ColliderTreeProxyKey,
851 ),
852 Without<ColliderDisabled>,
853 >,
854 Query<&EnlargedAabb, Without<ColliderDisabled>>,
855 )>,
856 narrow_phase_config: Res<NarrowPhaseConfig>,
857 length_unit: Res<PhysicsLengthUnit>,
858 mut trees: ResMut<ColliderTrees>,
859 mut moved_proxies: ResMut<MovedProxies>,
860 mut enlarged_proxies: ResMut<EnlargedProxies>,
861 collider_context: StaticSystemParam<C::Context>,
862 mut diagnostics: ResMut<ColliderTreeDiagnostics>,
863 last_tick: Res<LastPhysicsTick>,
864 system_tick: SystemChangeTick,
865) {
866 let start = crate::utils::Instant::now();
867
868 let this_run = system_tick.this_run();
869
870 let cap_dynamic = trees.dynamic_tree.proxies.capacity();
872 let cap_kinematic = trees.kinematic_tree.proxies.capacity();
873 let cap_static = trees.static_tree.proxies.capacity();
874 let cap_standalone = trees.standalone_tree.proxies.capacity();
875
876 let e = &mut enlarged_proxies;
878 e.dynamic_proxies.clear_and_set_capacity(cap_dynamic);
879 e.kinematic_proxies.clear_and_set_capacity(cap_kinematic);
880 e.static_proxies.clear_and_set_capacity(cap_static);
881 e.standalone_proxies.clear_and_set_capacity(cap_standalone);
882
883 let contact_tolerance = length_unit.0 * narrow_phase_config.contact_tolerance;
884 let margin = length_unit.0 * AABB_MARGIN;
885
886 let mut collider_query = colliders.p0();
890 collider_query.par_iter_mut().for_each(
891 |(entity, pos, rot, mut aabb, mut enlarged_aabb, collider, collision_margin, proxy_key)| {
892 if !pos.last_changed().is_newer_than(last_tick.0, this_run)
894 && !rot.last_changed().is_newer_than(last_tick.0, this_run)
895 && !collider.last_changed().is_newer_than(last_tick.0, this_run)
896 {
897 return;
898 }
899
900 let collision_margin = collision_margin.map_or(0.0, |margin| margin.0);
901
902 let context = AabbContext::new(entity, &*collider_context);
904 let growth = Vector::splat(contact_tolerance + collision_margin);
905 *aabb = collider
906 .aabb_with_context(pos.0, *rot, context)
907 .grow(growth);
908
909 let moved = enlarged_aabb.update(&aabb, margin);
911
912 if moved {
913 let tree_type = proxy_key.tree_type();
914 let mut thread_local_bit_vec = enlarged_proxies
915 .bit_vec_for_type(tree_type)
916 .thread_local
917 .get_or(|| {
918 let capacity = match tree_type {
919 ColliderTreeType::Dynamic => cap_dynamic,
920 ColliderTreeType::Kinematic => cap_kinematic,
921 ColliderTreeType::Static => cap_static,
922 ColliderTreeType::Standalone => cap_standalone,
923 };
924 let mut bit_vec = BitVec::new(capacity);
925 bit_vec.set_bit_count_and_clear(capacity);
926 RefCell::new(bit_vec)
927 })
928 .borrow_mut();
929
930 thread_local_bit_vec.set(proxy_key.id().index());
931 }
932 },
933 );
934
935 let aabb_query = colliders.p1();
937 for tree_type in ColliderTreeType::ALL {
938 let tree = trees.tree_for_type_mut(tree_type);
939 let bit_vec = enlarged_proxies.bit_vec_for_type_mut(tree_type);
940
941 tree.bvh.init_primitives_to_nodes_if_uninit();
942 bit_vec.combine_thread_local();
943
944 let moved_count = bit_vec.global.count_ones();
945 let moved_ratio = if tree.proxies.is_empty() {
946 0.0
947 } else {
948 moved_count as f32 / tree.proxies.len() as f32
949 };
950
951 if moved_ratio < 0.1 {
955 update_tree(
956 tree_type,
957 tree,
958 &bit_vec.global,
959 &aabb_query,
960 &mut moved_proxies,
961 |tree, proxy_id, enlarged_aabb| {
962 tree.resize_proxy_aabb(proxy_id, enlarged_aabb);
963 },
964 );
965 } else {
966 update_tree(
967 tree_type,
968 tree,
969 &bit_vec.global,
970 &aabb_query,
971 &mut moved_proxies,
972 |tree, proxy_id, enlarged_aabb| {
973 tree.set_proxy_aabb(proxy_id, enlarged_aabb);
974 },
975 );
976 tree.refit_all();
977 }
978 }
979
980 diagnostics.update += start.elapsed();
981}
982
983fn update_tree(
985 tree_type: ColliderTreeType,
986 tree: &mut ColliderTree,
987 bit_vec: &BitVec,
988 aabbs: &Query<&EnlargedAabb, Without<ColliderDisabled>>,
989 moved_proxies: &mut MovedProxies,
990 update_proxy_fn: impl Fn(&mut ColliderTree, ProxyId, Aabb),
991) {
992 for (i, mut bits) in bit_vec.blocks().enumerate() {
993 while bits != 0 {
994 let trailing_zeros = bits.trailing_zeros();
995 let proxy_id = ProxyId::new(i as u32 * 64 + trailing_zeros);
996 let proxy = &mut tree.proxies[proxy_id.index()];
997 let entity = proxy.collider;
998
999 let enlarged_aabb = aabbs.get(entity).unwrap_or_else(|_| {
1000 panic!(
1001 "EnlargedAabb missing for moved collider entity {:?}",
1002 entity
1003 )
1004 });
1005
1006 update_proxy_fn(tree, proxy_id, Aabb::from(enlarged_aabb.get()));
1008
1009 let proxy_key = ColliderTreeProxyKey::new(proxy_id, tree_type);
1011 if moved_proxies.insert(proxy_key) {
1012 tree.moved_proxies.push(proxy_id);
1013 }
1014
1015 bits &= bits - 1;
1017 }
1018 }
1019}
1020
1021fn clear_moved_proxies(mut moved_proxies: ResMut<MovedProxies>, mut trees: ResMut<ColliderTrees>) {
1022 moved_proxies.clear();
1023 trees.iter_trees_mut().for_each(|t| t.moved_proxies.clear());
1024}