Struct jumpy::core::physics::rapier::BroadPhaseMultiSap
pub struct BroadPhaseMultiSap {
proxies: SAPProxies,
layers: Vec<SAPLayer>,
smallest_layer: u8,
largest_layer: u8,
colliders_proxy_ids: IndexMap<ColliderHandle, u32, BuildHasherDefault<FxHasher32>>,
region_pool: Vec<Box<SAPRegion>>,
reporting: IndexMap<(u32, u32), bool, BuildHasherDefault<FxHasher32>>,
}Expand description
A broad-phase combining a Hierarchical Grid and Sweep-and-Prune.
The basic Sweep-and-Prune (SAP) algorithm has one significant flaws: the interactions between far-away objects. This means that objects that are very far away will still have some of their endpoints swapped within the SAP data-structure. This results in poor scaling because this results in lots of swapping between endpoints of Aabbs that won’t ever actually interact.
The first optimization to address this problem is to use the Multi-SAP method. This basically combines an SAP with a grid. The grid subdivides the spaces into equally-sized subspaces (grid cells). Each subspace, which we call a “region” contains an SAP instance (i.e. there SAP axes responsible for collecting endpoints and swapping them when they move to detect interaction pairs). Each Aabb is inserted in all the regions it intersects. This prevents the far-away problem because two objects that are far away will be located on different regions. So their endpoints will never meet.
However, the Multi-SAP approach has one notable problem: the region size must be chosen wisely. It could be user-defined, but that’s makes it more difficult to use (for the end-user). Or it can be given a fixed value. Using a fixed value may result in large objects intersecting lots of regions, resulting in poor performances and very high memory usage.
So a solution to that large-objects problem is the Multi-SAP approach is to replace the grid by a hierarchical grid. A hierarchical grid is composed of several layers. And each layer have different region sizes. For example all the regions on layer 0 will have the size 1x1x1. All the regions on the layer 1 will have the size 10x10x10, etc. That way, a given Aabb will be inserted on the layer that has regions big enough to avoid the large-object problem. For example a 20x20x20 object will be inserted in the layer with region of size 10x10x10, resulting in only 8 regions being intersect by the Aabb. (If it was inserted in the layer with regions of size 1x1x1, it would have intersected 8000 regions, which is a problem performancewise.)
We call this new method the Hierarchical-SAP.
Now with the Hierarchical-SAP, we can update each layer independently from one another. However, objects belonging to different layers will never be detected as intersecting that way. So we need a way to do inter-layer interference detection. There is a lot ways of doing this: performing inter-layer Multi-Box-Pruning passes is one example (but this is not what we do). In our implementation, we do the following:
- The Aabb bounds of each region of the layer
nare inserted into the corresponding larger region of the layern + 1. - When an Aabb in the region of the layer
n + 1intersects the Aabb corresponding to one of the regions at the smaller layern, we add that Aabb to that smaller region. So in the end it means that a given Aabb will be inserted into all the region it intersects at the layern. And it will also be inserted into all the regions it intersects at the smaller layers (the layers< n), but only for the regions that already exist (so we don’t have to discretize our Aabb into the layers< n). This involves a fair amount of bookkeeping unfortunately, but this has the benefit of keep the overall complexity of the algorithm O(1) in the typical specially coherent scenario.
From an implementation point-of-view, our hierarchical SAP is implemented with the following structures:
- There is one
SAPLayerper layer of the hierarchical grid. - Each
SAPLayercontains multipleSAPRegion(each being a region of the grid represented by that layer). - Each
SAPRegioncontains threeSAPAxis, representing the “classical” SAP algorithm running on this region. - Each
SAPAxismaintains a sorted list ofSAPEndpointsrepresenting the endpoints of the Aabbs intersecting the bounds on theSAPRegioncontaining thisSAPAxis. - A set of
SAPProxyare maintained separately. It contains the Aabbs of all the colliders managed by this broad-phase, as well as the Aabbs of all the regions part of this broad-phase.
Fields§
§proxies: SAPProxies§layers: Vec<SAPLayer>§smallest_layer: u8§largest_layer: u8§colliders_proxy_ids: IndexMap<ColliderHandle, u32, BuildHasherDefault<FxHasher32>>§region_pool: Vec<Box<SAPRegion>>§reporting: IndexMap<(u32, u32), bool, BuildHasherDefault<FxHasher32>>Implementations§
§impl BroadPhaseMultiSap
impl BroadPhaseMultiSap
pub fn new() -> BroadPhaseMultiSap
pub fn new() -> BroadPhaseMultiSap
Create a new empty broad-phase.
Trait Implementations§
§impl BroadPhase for BroadPhaseMultiSap
impl BroadPhase for BroadPhaseMultiSap
§fn update(
&mut self,
dt: f32,
prediction_distance: f32,
colliders: &mut ColliderSet,
bodies: &RigidBodySet,
modified_colliders: &[ColliderHandle],
removed_colliders: &[ColliderHandle],
events: &mut Vec<BroadPhasePairEvent>,
)
fn update( &mut self, dt: f32, prediction_distance: f32, colliders: &mut ColliderSet, bodies: &RigidBodySet, modified_colliders: &[ColliderHandle], removed_colliders: &[ColliderHandle], events: &mut Vec<BroadPhasePairEvent>, )
Updates the broad-phase, taking into account the new collider positions.
§impl Clone for BroadPhaseMultiSap
impl Clone for BroadPhaseMultiSap
§fn clone(&self) -> BroadPhaseMultiSap
fn clone(&self) -> BroadPhaseMultiSap
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more§impl Default for BroadPhaseMultiSap
impl Default for BroadPhaseMultiSap
§fn default() -> BroadPhaseMultiSap
fn default() -> BroadPhaseMultiSap
Auto Trait Implementations§
impl Freeze for BroadPhaseMultiSap
impl RefUnwindSafe for BroadPhaseMultiSap
impl Send for BroadPhaseMultiSap
impl Sync for BroadPhaseMultiSap
impl Unpin for BroadPhaseMultiSap
impl UnwindSafe for BroadPhaseMultiSap
Blanket Implementations§
§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
§fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
T [ShaderType] for self. When used in [AsBindGroup]
derives, it is safe to assume that all images in self exist.§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit)§impl<T> Conv for T
impl<T> Conv for T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Self using data from the given [World]§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
§fn from_world(_world: &World) -> T
fn from_world(_world: &World) -> T
Self using data from the given World.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoArcAny for T
impl<T> IntoArcAny for T
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> RawDefault for Twhere
T: Default,
impl<T> RawDefault for Twhere
T: Default,
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.