Add prelude + use vectors for setting linvel/translation in builders
This commit is contained in:
@@ -2,10 +2,11 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle};
|
||||
use crate::geometry::{
|
||||
ColliderBroadPhaseData, ColliderChanges, ColliderGroups, ColliderMassProperties,
|
||||
ColliderMaterial, ColliderParent, ColliderPosition, ColliderShape, ColliderType,
|
||||
InteractionGroups, SharedShape, SolverFlags,
|
||||
InteractionGroups, SharedShape,
|
||||
};
|
||||
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
|
||||
use crate::parry::transformation::vhacd::VHACDParameters;
|
||||
use crate::pipeline::PhysicsHooksFlags;
|
||||
use na::Unit;
|
||||
use parry::bounding_volume::AABB;
|
||||
use parry::shape::Shape;
|
||||
@@ -20,7 +21,7 @@ pub struct Collider {
|
||||
pub(crate) co_shape: ColliderShape,
|
||||
pub(crate) co_mprops: ColliderMassProperties,
|
||||
pub(crate) co_changes: ColliderChanges,
|
||||
pub(crate) co_parent: ColliderParent,
|
||||
pub(crate) co_parent: Option<ColliderParent>,
|
||||
pub(crate) co_pos: ColliderPosition,
|
||||
pub(crate) co_material: ColliderMaterial,
|
||||
pub(crate) co_groups: ColliderGroups,
|
||||
@@ -31,14 +32,14 @@ pub struct Collider {
|
||||
|
||||
impl Collider {
|
||||
pub(crate) fn reset_internal_references(&mut self) {
|
||||
self.co_parent.handle = RigidBodyHandle::invalid();
|
||||
self.co_parent = None;
|
||||
self.co_bf_data.proxy_index = crate::INVALID_U32;
|
||||
self.co_changes = ColliderChanges::all();
|
||||
}
|
||||
|
||||
/// The rigid body this collider is attached to.
|
||||
pub fn parent(&self) -> RigidBodyHandle {
|
||||
self.co_parent.handle
|
||||
pub fn parent(&self) -> Option<RigidBodyHandle> {
|
||||
self.co_parent.map(|parent| parent.handle)
|
||||
}
|
||||
|
||||
/// Is this collider a sensor?
|
||||
@@ -46,6 +47,26 @@ impl Collider {
|
||||
self.co_type.is_sensor()
|
||||
}
|
||||
|
||||
/// The physics hooks enabled for this collider.
|
||||
pub fn active_hooks(&self) -> PhysicsHooksFlags {
|
||||
self.co_material.active_hooks
|
||||
}
|
||||
|
||||
/// Sets the physics hooks enabled for this collider.
|
||||
pub fn set_active_hooks(&mut self, active_hooks: PhysicsHooksFlags) {
|
||||
self.co_material.active_hooks = active_hooks;
|
||||
}
|
||||
|
||||
/// The friction coefficient of this collider.
|
||||
pub fn friction(&self) -> Real {
|
||||
self.co_material.friction
|
||||
}
|
||||
|
||||
/// Sets the friction coefficient of this collider.
|
||||
pub fn set_friction(&mut self, coefficient: Real) {
|
||||
self.co_material.friction = coefficient
|
||||
}
|
||||
|
||||
/// The combine rule used by this collider to combine its friction
|
||||
/// coefficient with the friction coefficient of the other collider it
|
||||
/// is in contact with.
|
||||
@@ -60,6 +81,16 @@ impl Collider {
|
||||
self.co_material.friction_combine_rule = rule;
|
||||
}
|
||||
|
||||
/// The restitution coefficient of this collider.
|
||||
pub fn restitution(&self) -> Real {
|
||||
self.co_material.restitution
|
||||
}
|
||||
|
||||
/// Sets the restitution coefficient of this collider.
|
||||
pub fn set_restitution(&mut self, coefficient: Real) {
|
||||
self.co_material.restitution = coefficient
|
||||
}
|
||||
|
||||
/// The combine rule used by this collider to combine its restitution
|
||||
/// coefficient with the restitution coefficient of the other collider it
|
||||
/// is in contact with.
|
||||
@@ -86,15 +117,22 @@ impl Collider {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_position_debug(&mut self, position: Isometry<Real>) {
|
||||
self.co_pos.0 = position;
|
||||
/// Sets the translational part of this collider's position.
|
||||
pub fn set_translation(&mut self, translation: Vector<Real>) {
|
||||
self.co_changes.insert(ColliderChanges::POSITION);
|
||||
self.co_pos.0.translation.vector = translation;
|
||||
}
|
||||
|
||||
/// The position of this collider expressed in the local-space of the rigid-body it is attached to.
|
||||
#[deprecated(note = "use `.position_wrt_parent()` instead.")]
|
||||
pub fn delta(&self) -> &Isometry<Real> {
|
||||
&self.co_parent.pos_wrt_parent
|
||||
/// Sets the rotational part of this collider's position.
|
||||
pub fn set_rotation(&mut self, rotation: AngVector<Real>) {
|
||||
self.co_changes.insert(ColliderChanges::POSITION);
|
||||
self.co_pos.0.rotation = Rotation::new(rotation);
|
||||
}
|
||||
|
||||
/// Sets the position of this collider.
|
||||
pub fn set_position(&mut self, position: Isometry<Real>) {
|
||||
self.co_changes.insert(ColliderChanges::POSITION);
|
||||
self.co_pos.0 = position;
|
||||
}
|
||||
|
||||
/// The world-space position of this collider.
|
||||
@@ -102,15 +140,31 @@ impl Collider {
|
||||
&self.co_pos
|
||||
}
|
||||
|
||||
/// The translational part of this rigid-body's position.
|
||||
pub fn translation(&self) -> &Vector<Real> {
|
||||
&self.co_pos.0.translation.vector
|
||||
}
|
||||
|
||||
/// The rotational part of this rigid-body's position.
|
||||
pub fn rotation(&self) -> &Rotation<Real> {
|
||||
&self.co_pos.0.rotation
|
||||
}
|
||||
|
||||
/// The position of this collider wrt the body it is attached to.
|
||||
pub fn position_wrt_parent(&self) -> &Isometry<Real> {
|
||||
&self.co_parent.pos_wrt_parent
|
||||
pub fn position_wrt_parent(&self) -> Option<&Isometry<Real>> {
|
||||
self.co_parent.as_ref().map(|p| &p.pos_wrt_parent)
|
||||
}
|
||||
|
||||
/// Sets the position of this collider wrt. its parent rigid-body.
|
||||
pub fn set_position_wrt_parent(&mut self, position: Isometry<Real>) {
|
||||
///
|
||||
/// Panics if the collider is not attached to a rigid-body.
|
||||
pub fn set_position_wrt_parent(&mut self, pos_wrt_parent: Isometry<Real>) {
|
||||
self.co_changes.insert(ColliderChanges::PARENT);
|
||||
self.co_parent.pos_wrt_parent = position;
|
||||
let co_parent = self
|
||||
.co_parent
|
||||
.as_mut()
|
||||
.expect("This collider has no parent.");
|
||||
co_parent.pos_wrt_parent = pos_wrt_parent;
|
||||
}
|
||||
|
||||
/// The collision groups used by this collider.
|
||||
@@ -213,13 +267,12 @@ pub struct ColliderBuilder {
|
||||
pub restitution: Real,
|
||||
/// The rule used to combine two restitution coefficients.
|
||||
pub restitution_combine_rule: CoefficientCombineRule,
|
||||
/// The position of this collider relative to the local frame of the rigid-body it is attached to.
|
||||
pub pos_wrt_parent: Isometry<Real>,
|
||||
/// The position of this collider.
|
||||
pub position: Isometry<Real>,
|
||||
/// Is this collider a sensor?
|
||||
pub is_sensor: bool,
|
||||
/// Do we have to always call the contact modifier
|
||||
/// on this collider?
|
||||
pub modify_solver_contacts: bool,
|
||||
/// Physics hooks enabled for this collider.
|
||||
pub active_hooks: PhysicsHooksFlags,
|
||||
/// The user-data of the collider being built.
|
||||
pub user_data: u128,
|
||||
/// The collision groups for the collider being built.
|
||||
@@ -237,14 +290,14 @@ impl ColliderBuilder {
|
||||
mass_properties: None,
|
||||
friction: Self::default_friction(),
|
||||
restitution: 0.0,
|
||||
pos_wrt_parent: Isometry::identity(),
|
||||
position: Isometry::identity(),
|
||||
is_sensor: false,
|
||||
user_data: 0,
|
||||
collision_groups: InteractionGroups::all(),
|
||||
solver_groups: InteractionGroups::all(),
|
||||
friction_combine_rule: CoefficientCombineRule::Average,
|
||||
restitution_combine_rule: CoefficientCombineRule::Average,
|
||||
modify_solver_contacts: false,
|
||||
active_hooks: PhysicsHooksFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,6 +542,11 @@ impl ColliderBuilder {
|
||||
0.5
|
||||
}
|
||||
|
||||
/// The default density used by the collider builder.
|
||||
pub fn default_density() -> Real {
|
||||
1.0
|
||||
}
|
||||
|
||||
/// Sets an arbitrary user-defined 128-bit integer associated to the colliders built by this builder.
|
||||
pub fn user_data(mut self, data: u128) -> Self {
|
||||
self.user_data = data;
|
||||
@@ -522,10 +580,9 @@ impl ColliderBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// If set to `true` then the physics hooks will always run to modify
|
||||
/// contacts involving this collider.
|
||||
pub fn modify_solver_contacts(mut self, modify_solver_contacts: bool) -> Self {
|
||||
self.modify_solver_contacts = modify_solver_contacts;
|
||||
/// The set of physics hooks enabled for this collider.
|
||||
pub fn active_hooks(mut self, active_hooks: PhysicsHooksFlags) -> Self {
|
||||
self.active_hooks = active_hooks;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -571,51 +628,45 @@ impl ColliderBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial translation of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn translation(mut self, x: Real, y: Real) -> Self {
|
||||
self.pos_wrt_parent.translation.x = x;
|
||||
self.pos_wrt_parent.translation.y = y;
|
||||
/// Sets the initial translation of the collider to be created.
|
||||
///
|
||||
/// If the collider will be attached to a rigid-body, this sets the translation relative to the
|
||||
/// rigid-body it will be attached to.
|
||||
pub fn translation(mut self, translation: Vector<Real>) -> Self {
|
||||
self.position.translation.vector = translation;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial translation of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn translation(mut self, x: Real, y: Real, z: Real) -> Self {
|
||||
self.pos_wrt_parent.translation.x = x;
|
||||
self.pos_wrt_parent.translation.y = y;
|
||||
self.pos_wrt_parent.translation.z = z;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial orientation of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
/// Sets the initial orientation of the collider to be created.
|
||||
///
|
||||
/// If the collider will be attached to a rigid-body, this sets the orientation relative to the
|
||||
/// rigid-body it will be attached to.
|
||||
pub fn rotation(mut self, angle: AngVector<Real>) -> Self {
|
||||
self.pos_wrt_parent.rotation = Rotation::new(angle);
|
||||
self.position.rotation = Rotation::new(angle);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial position (translation and orientation) of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
pub fn position_wrt_parent(mut self, pos: Isometry<Real>) -> Self {
|
||||
self.pos_wrt_parent = pos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial position (translation and orientation) of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
#[deprecated(note = "Use `.position_wrt_parent` instead.")]
|
||||
/// Sets the initial position (translation and orientation) of the collider to be created.
|
||||
///
|
||||
/// If the collider will be attached to a rigid-body, this sets the position relative
|
||||
/// to the rigid-body it will be attached to.
|
||||
pub fn position(mut self, pos: Isometry<Real>) -> Self {
|
||||
self.pos_wrt_parent = pos;
|
||||
self.position = pos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial position (translation and orientation) of the collider to be created,
|
||||
/// relative to the rigid-body it is attached to.
|
||||
#[deprecated(note = "Use `.position` instead.")]
|
||||
pub fn position_wrt_parent(mut self, pos: Isometry<Real>) -> Self {
|
||||
self.position = pos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the position of this collider in the local-space of the rigid-body it is attached to.
|
||||
#[deprecated(note = "Use `.position_wrt_parent` instead.")]
|
||||
#[deprecated(note = "Use `.position` instead.")]
|
||||
pub fn delta(mut self, delta: Isometry<Real>) -> Self {
|
||||
self.pos_wrt_parent = delta;
|
||||
self.position = delta;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -623,15 +674,11 @@ impl ColliderBuilder {
|
||||
pub fn build(&self) -> Collider {
|
||||
let (co_changes, co_pos, co_bf_data, co_shape, co_type, co_groups, co_material, co_mprops) =
|
||||
self.components();
|
||||
let co_parent = ColliderParent {
|
||||
pos_wrt_parent: co_pos.0,
|
||||
handle: RigidBodyHandle::invalid(),
|
||||
};
|
||||
Collider {
|
||||
co_shape,
|
||||
co_mprops,
|
||||
co_material,
|
||||
co_parent,
|
||||
co_parent: None,
|
||||
co_changes,
|
||||
co_pos,
|
||||
co_bf_data,
|
||||
@@ -657,17 +704,11 @@ impl ColliderBuilder {
|
||||
let mass_info = if let Some(mp) = self.mass_properties {
|
||||
ColliderMassProperties::MassProperties(Box::new(mp))
|
||||
} else {
|
||||
let default_density = if self.is_sensor { 0.0 } else { 1.0 };
|
||||
let default_density = Self::default_density();
|
||||
let density = self.density.unwrap_or(default_density);
|
||||
ColliderMassProperties::Density(density)
|
||||
};
|
||||
|
||||
let mut solver_flags = SolverFlags::default();
|
||||
solver_flags.set(
|
||||
SolverFlags::MODIFY_SOLVER_CONTACTS,
|
||||
self.modify_solver_contacts,
|
||||
);
|
||||
|
||||
let co_shape = self.shape.clone();
|
||||
let co_mprops = mass_info;
|
||||
let co_material = ColliderMaterial {
|
||||
@@ -675,10 +716,10 @@ impl ColliderBuilder {
|
||||
restitution: self.restitution,
|
||||
friction_combine_rule: self.friction_combine_rule,
|
||||
restitution_combine_rule: self.restitution_combine_rule,
|
||||
solver_flags,
|
||||
active_hooks: self.active_hooks,
|
||||
};
|
||||
let co_changes = ColliderChanges::all();
|
||||
let co_pos = ColliderPosition(self.pos_wrt_parent);
|
||||
let co_pos = ColliderPosition(self.position);
|
||||
let co_bf_data = ColliderBroadPhaseData::default();
|
||||
let co_groups = ColliderGroups {
|
||||
collision_groups: self.collision_groups,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle};
|
||||
use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape, SolverFlags};
|
||||
use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape};
|
||||
use crate::math::{Isometry, Real};
|
||||
use crate::parry::partitioning::IndexedData;
|
||||
use crate::pipeline::PhysicsHooksFlags;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// The unique identifier of a collider added to a collider set.
|
||||
@@ -241,9 +242,8 @@ pub struct ColliderMaterial {
|
||||
pub friction_combine_rule: CoefficientCombineRule,
|
||||
/// The rule applied to combine the restitution coefficients of two colliders.
|
||||
pub restitution_combine_rule: CoefficientCombineRule,
|
||||
/// The solver flags attached to this collider in order to customize the way the
|
||||
/// constraints solver will work with contacts involving this collider.
|
||||
pub solver_flags: SolverFlags,
|
||||
/// The physics hooks enabled for contact pairs and intersection pairs involving this collider.
|
||||
pub active_hooks: PhysicsHooksFlags,
|
||||
}
|
||||
|
||||
impl ColliderMaterial {
|
||||
@@ -264,7 +264,7 @@ impl Default for ColliderMaterial {
|
||||
restitution: 0.0,
|
||||
friction_combine_rule: CoefficientCombineRule::default(),
|
||||
restitution_combine_rule: CoefficientCombineRule::default(),
|
||||
solver_flags: SolverFlags::default(),
|
||||
active_hooks: PhysicsHooksFlags::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,12 +61,19 @@ impl_field_component_set!(ColliderType, co_type);
|
||||
impl_field_component_set!(ColliderShape, co_shape);
|
||||
impl_field_component_set!(ColliderMassProperties, co_mprops);
|
||||
impl_field_component_set!(ColliderChanges, co_changes);
|
||||
impl_field_component_set!(ColliderParent, co_parent);
|
||||
impl_field_component_set!(ColliderPosition, co_pos);
|
||||
impl_field_component_set!(ColliderMaterial, co_material);
|
||||
impl_field_component_set!(ColliderGroups, co_groups);
|
||||
impl_field_component_set!(ColliderBroadPhaseData, co_bf_data);
|
||||
|
||||
impl ComponentSetOption<ColliderParent> for ColliderSet {
|
||||
#[inline(always)]
|
||||
fn get(&self, handle: crate::data::Index) -> Option<&ColliderParent> {
|
||||
self.get(ColliderHandle(handle))
|
||||
.and_then(|b| b.co_parent.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl ColliderSet {
|
||||
/// Create a new empty set of colliders.
|
||||
pub fn new() -> Self {
|
||||
@@ -122,7 +129,17 @@ impl ColliderSet {
|
||||
}
|
||||
|
||||
/// Inserts a new collider to this set and retrieve its handle.
|
||||
pub fn insert(
|
||||
pub fn insert(&mut self, mut coll: Collider) -> ColliderHandle {
|
||||
// Make sure the internal links are reset, they may not be
|
||||
// if this rigid-body was obtained by cloning another one.
|
||||
coll.reset_internal_references();
|
||||
let handle = ColliderHandle(self.colliders.insert(coll));
|
||||
self.modified_colliders.push(handle);
|
||||
handle
|
||||
}
|
||||
|
||||
/// Inserts a new collider to this set, attach it to the given rigid-body, and retrieve its handle.
|
||||
pub fn insert_with_parent(
|
||||
&mut self,
|
||||
mut coll: Collider,
|
||||
parent_handle: RigidBodyHandle,
|
||||
@@ -131,7 +148,10 @@ impl ColliderSet {
|
||||
// Make sure the internal links are reset, they may not be
|
||||
// if this rigid-body was obtained by cloning another one.
|
||||
coll.reset_internal_references();
|
||||
coll.co_parent.handle = parent_handle;
|
||||
coll.co_parent = Some(ColliderParent {
|
||||
handle: parent_handle,
|
||||
pos_wrt_parent: coll.co_pos.0,
|
||||
});
|
||||
|
||||
// NOTE: we use `get_mut` instead of `get_mut_internal` so that the
|
||||
// modification flag is updated properly.
|
||||
@@ -144,7 +164,7 @@ impl ColliderSet {
|
||||
let coll = self.colliders.get_mut(handle.0).unwrap();
|
||||
parent.add_collider(
|
||||
handle,
|
||||
&mut coll.co_parent,
|
||||
coll.co_parent.as_mut().unwrap(),
|
||||
&mut coll.co_pos,
|
||||
&coll.co_shape,
|
||||
&coll.co_mprops,
|
||||
@@ -170,13 +190,15 @@ impl ColliderSet {
|
||||
*/
|
||||
// NOTE: we use `get_mut_internal_with_modification_tracking` instead of `get_mut_internal` so that the
|
||||
// modification flag is updated properly.
|
||||
if let Some(parent) =
|
||||
bodies.get_mut_internal_with_modification_tracking(collider.co_parent.handle)
|
||||
{
|
||||
parent.remove_collider_internal(handle, &collider);
|
||||
if let Some(co_parent) = &collider.co_parent {
|
||||
if let Some(parent) =
|
||||
bodies.get_mut_internal_with_modification_tracking(co_parent.handle)
|
||||
{
|
||||
parent.remove_collider_internal(handle, &collider);
|
||||
|
||||
if wake_up {
|
||||
islands.wake_up(bodies, collider.co_parent.handle, true);
|
||||
if wake_up {
|
||||
islands.wake_up(bodies, co_parent.handle, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::dynamics::RigidBodyHandle;
|
||||
use crate::geometry::{ColliderPair, Contact, ContactManifold};
|
||||
use crate::geometry::{ColliderHandle, Contact, ContactManifold};
|
||||
use crate::math::{Point, Real, Vector};
|
||||
use parry::query::ContactManifoldsWorkspace;
|
||||
|
||||
@@ -10,9 +10,6 @@ bitflags::bitflags! {
|
||||
/// The constraint solver will take this contact manifold into
|
||||
/// account for force computation.
|
||||
const COMPUTE_IMPULSES = 0b001;
|
||||
/// The user-defined physics hooks will be used to
|
||||
/// modify the solver contacts of this contact manifold.
|
||||
const MODIFY_SOLVER_CONTACTS = 0b010;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +53,10 @@ impl Default for ContactData {
|
||||
#[derive(Clone)]
|
||||
/// The description of all the contacts between a pair of colliders.
|
||||
pub struct ContactPair {
|
||||
/// The pair of colliders involved.
|
||||
pub pair: ColliderPair,
|
||||
/// The first collider involved in the contact pair.
|
||||
pub collider1: ColliderHandle,
|
||||
/// The second collider involved in the contact pair.
|
||||
pub collider2: ColliderHandle,
|
||||
/// The set of contact manifolds between the two colliders.
|
||||
///
|
||||
/// All contact manifold contain themselves contact points between the colliders.
|
||||
@@ -68,9 +67,10 @@ pub struct ContactPair {
|
||||
}
|
||||
|
||||
impl ContactPair {
|
||||
pub(crate) fn new(pair: ColliderPair) -> Self {
|
||||
pub(crate) fn new(collider1: ColliderHandle, collider2: ColliderHandle) -> Self {
|
||||
Self {
|
||||
pair,
|
||||
collider1,
|
||||
collider2,
|
||||
has_any_active_contact: false,
|
||||
manifolds: Vec::new(),
|
||||
workspace: None,
|
||||
|
||||
@@ -1,56 +1,66 @@
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
/// Pairwise filtering using bit masks.
|
||||
///
|
||||
/// This filtering method is based on two 16-bit values:
|
||||
/// - The interaction groups (the 16 left-most bits of `self.0`).
|
||||
/// - The interaction mask (the 16 right-most bits of `self.0`).
|
||||
/// This filtering method is based on two 32-bit values:
|
||||
/// - The interaction groups memberships.
|
||||
/// - The interaction groups filter.
|
||||
///
|
||||
/// An interaction is allowed between two filters `a` and `b` when two conditions
|
||||
/// are met simultaneously:
|
||||
/// - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`.
|
||||
/// - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`.
|
||||
/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
|
||||
/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
|
||||
///
|
||||
/// In other words, interactions are allowed between two filter iff. the following condition is met:
|
||||
/// ```ignore
|
||||
/// ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
|
||||
/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
|
||||
/// ```
|
||||
pub struct InteractionGroups(pub u32);
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct InteractionGroups {
|
||||
/// Groups memberships.
|
||||
pub memberships: u32,
|
||||
/// Groups filter.
|
||||
pub filter: u32,
|
||||
}
|
||||
|
||||
impl InteractionGroups {
|
||||
/// Initializes with the given interaction groups and interaction mask.
|
||||
pub const fn new(groups: u16, masks: u16) -> Self {
|
||||
Self::none().with_groups(groups).with_mask(masks)
|
||||
pub const fn new(memberships: u32, filter: u32) -> Self {
|
||||
Self {
|
||||
memberships,
|
||||
filter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow interaction with everything.
|
||||
pub const fn all() -> Self {
|
||||
Self(u32::MAX)
|
||||
Self::new(u32::MAX, u32::MAX)
|
||||
}
|
||||
|
||||
/// Prevent all interactions.
|
||||
pub const fn none() -> Self {
|
||||
Self(0)
|
||||
Self::new(0, 0)
|
||||
}
|
||||
|
||||
/// Sets the group this filter is part of.
|
||||
pub const fn with_groups(self, groups: u16) -> Self {
|
||||
Self((self.0 & 0x0000ffff) | ((groups as u32) << 16))
|
||||
pub const fn with_memberships(mut self, memberships: u32) -> Self {
|
||||
self.memberships = memberships;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the interaction mask of this filter.
|
||||
pub const fn with_mask(self, mask: u16) -> Self {
|
||||
Self((self.0 & 0xffff0000) | (mask as u32))
|
||||
pub const fn with_filter(mut self, filter: u32) -> Self {
|
||||
self.filter = filter;
|
||||
self
|
||||
}
|
||||
|
||||
/// Check if interactions should be allowed based on the interaction groups and mask.
|
||||
/// Check if interactions should be allowed based on the interaction memberships and filter.
|
||||
///
|
||||
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
|
||||
/// with the mask of `rhs`, and vice-versa.
|
||||
/// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common
|
||||
/// with the filter of `rhs`, and vice-versa.
|
||||
#[inline]
|
||||
pub const fn test(self, rhs: Self) -> bool {
|
||||
((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
|
||||
(self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,18 @@ impl NarrowPhase {
|
||||
&self.intersection_graph
|
||||
}
|
||||
|
||||
/// All the contacts involving the given collider.
|
||||
///
|
||||
/// It is strongly recommended to use the [`NarrowPhase::contacts_with`] method instead. This
|
||||
/// method can be used if the generation number of the collider handle isn't known.
|
||||
pub fn contacts_with_unknown_gen(
|
||||
&self,
|
||||
collider: u32,
|
||||
) -> Option<impl Iterator<Item = (ColliderHandle, ColliderHandle, &ContactPair)>> {
|
||||
let id = self.graph_indices.get_unknown_gen(collider)?;
|
||||
Some(self.contact_graph.interactions_with(id.contact_graph_index))
|
||||
}
|
||||
|
||||
/// All the contacts involving the given collider.
|
||||
pub fn contacts_with(
|
||||
&self,
|
||||
@@ -106,6 +118,22 @@ impl NarrowPhase {
|
||||
Some(self.contact_graph.interactions_with(id.contact_graph_index))
|
||||
}
|
||||
|
||||
/// All the intersections involving the given collider.
|
||||
///
|
||||
/// It is strongly recommended to use the [`NarrowPhase::intersections_with`] method instead.
|
||||
/// This method can be used if the generation number of the collider handle isn't known.
|
||||
pub fn intersections_with_unknown_gen(
|
||||
&self,
|
||||
collider: u32,
|
||||
) -> Option<impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_> {
|
||||
let id = self.graph_indices.get_unknown_gen(collider)?;
|
||||
Some(
|
||||
self.intersection_graph
|
||||
.interactions_with(id.intersection_graph_index)
|
||||
.map(|e| (e.0, e.1, *e.2)),
|
||||
)
|
||||
}
|
||||
|
||||
/// All the intersections involving the given collider.
|
||||
pub fn intersections_with(
|
||||
&self,
|
||||
@@ -119,6 +147,22 @@ impl NarrowPhase {
|
||||
)
|
||||
}
|
||||
|
||||
/// The contact pair involving two specific colliders.
|
||||
///
|
||||
/// It is strongly recommended to use the [`NarrowPhase::contact_pair`] method instead. This
|
||||
/// method can be used if the generation number of the collider handle isn't known.
|
||||
///
|
||||
/// If this returns `None`, there is no contact between the two colliders.
|
||||
/// If this returns `Some`, then there may be a contact between the two colliders. Check the
|
||||
/// result [`ContactPair::has_any_active_collider`] method to see if there is an actual contact.
|
||||
pub fn contact_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<&ContactPair> {
|
||||
let id1 = self.graph_indices.get_unknown_gen(collider1)?;
|
||||
let id2 = self.graph_indices.get_unknown_gen(collider2)?;
|
||||
self.contact_graph
|
||||
.interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
|
||||
.map(|c| c.2)
|
||||
}
|
||||
|
||||
/// The contact pair involving two specific colliders.
|
||||
///
|
||||
/// If this returns `None`, there is no contact between the two colliders.
|
||||
@@ -136,6 +180,21 @@ impl NarrowPhase {
|
||||
.map(|c| c.2)
|
||||
}
|
||||
|
||||
/// The intersection pair involving two specific colliders.
|
||||
///
|
||||
/// It is strongly recommended to use the [`NarrowPhase::intersection_pair`] method instead. This
|
||||
/// method can be used if the generation number of the collider handle isn't known.
|
||||
///
|
||||
/// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders.
|
||||
/// If this returns `Some(true)`, then there may be an intersection between the two colliders.
|
||||
pub fn intersection_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<bool> {
|
||||
let id1 = self.graph_indices.get_unknown_gen(collider1)?;
|
||||
let id2 = self.graph_indices.get_unknown_gen(collider2)?;
|
||||
self.intersection_graph
|
||||
.interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
|
||||
.map(|c| *c.2)
|
||||
}
|
||||
|
||||
/// The intersection pair involving two specific colliders.
|
||||
///
|
||||
/// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders.
|
||||
@@ -527,7 +586,7 @@ impl NarrowPhase {
|
||||
.find_edge(gid1.contact_graph_index, gid2.contact_graph_index)
|
||||
.is_none()
|
||||
{
|
||||
let interaction = ContactPair::new(*pair);
|
||||
let interaction = ContactPair::new(pair.collider1, pair.collider2);
|
||||
let _ = self.contact_graph.add_edge(
|
||||
gid1.contact_graph_index,
|
||||
gid2.contact_graph_index,
|
||||
@@ -585,7 +644,8 @@ impl NarrowPhase {
|
||||
+ ComponentSetOption<ColliderParent>
|
||||
+ ComponentSet<ColliderGroups>
|
||||
+ ComponentSet<ColliderShape>
|
||||
+ ComponentSet<ColliderPosition>,
|
||||
+ ComponentSet<ColliderPosition>
|
||||
+ ComponentSet<ColliderMaterial>,
|
||||
{
|
||||
if modified_colliders.is_empty() {
|
||||
return;
|
||||
@@ -593,7 +653,6 @@ impl NarrowPhase {
|
||||
|
||||
let nodes = &self.intersection_graph.graph.nodes;
|
||||
let query_dispatcher = &*self.query_dispatcher;
|
||||
let active_hooks = hooks.active_hooks();
|
||||
|
||||
// TODO: don't iterate on all the edges.
|
||||
par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| {
|
||||
@@ -601,19 +660,21 @@ impl NarrowPhase {
|
||||
let handle2 = nodes[edge.target().index()].weight;
|
||||
|
||||
let co_parent1: Option<&ColliderParent> = colliders.get(handle1.0);
|
||||
let (co_changes1, co_groups1, co_shape1, co_pos1): (
|
||||
let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): (
|
||||
&ColliderChanges,
|
||||
&ColliderGroups,
|
||||
&ColliderShape,
|
||||
&ColliderPosition,
|
||||
&ColliderMaterial,
|
||||
) = colliders.index_bundle(handle1.0);
|
||||
|
||||
let co_parent2: Option<&ColliderParent> = colliders.get(handle2.0);
|
||||
let (co_changes2, co_groups2, co_shape2, co_pos2): (
|
||||
let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): (
|
||||
&ColliderChanges,
|
||||
&ColliderGroups,
|
||||
&ColliderShape,
|
||||
&ColliderPosition,
|
||||
&ColliderMaterial,
|
||||
) = colliders.index_bundle(handle2.0);
|
||||
|
||||
if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update()
|
||||
@@ -656,6 +717,8 @@ impl NarrowPhase {
|
||||
return;
|
||||
}
|
||||
|
||||
let active_hooks = co_material1.active_hooks | co_material2.active_hooks;
|
||||
|
||||
if !active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR)
|
||||
&& !status1.is_dynamic()
|
||||
&& !status2.is_dynamic()
|
||||
@@ -721,29 +784,28 @@ impl NarrowPhase {
|
||||
}
|
||||
|
||||
let query_dispatcher = &*self.query_dispatcher;
|
||||
let active_hooks = hooks.active_hooks();
|
||||
|
||||
// TODO: don't iterate on all the edges.
|
||||
par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
|
||||
let pair = &mut edge.weight;
|
||||
|
||||
let co_parent1: Option<&ColliderParent> = colliders.get(pair.pair.collider1.0);
|
||||
let co_parent1: Option<&ColliderParent> = colliders.get(pair.collider1.0);
|
||||
let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): (
|
||||
&ColliderChanges,
|
||||
&ColliderGroups,
|
||||
&ColliderShape,
|
||||
&ColliderPosition,
|
||||
&ColliderMaterial,
|
||||
) = colliders.index_bundle(pair.pair.collider1.0);
|
||||
) = colliders.index_bundle(pair.collider1.0);
|
||||
|
||||
let co_parent2: Option<&ColliderParent> = colliders.get(pair.pair.collider2.0);
|
||||
let co_parent2: Option<&ColliderParent> = colliders.get(pair.collider2.0);
|
||||
let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): (
|
||||
&ColliderChanges,
|
||||
&ColliderGroups,
|
||||
&ColliderShape,
|
||||
&ColliderPosition,
|
||||
&ColliderMaterial,
|
||||
) = colliders.index_bundle(pair.pair.collider2.0);
|
||||
) = colliders.index_bundle(pair.collider2.0);
|
||||
|
||||
if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update()
|
||||
{
|
||||
@@ -785,6 +847,7 @@ impl NarrowPhase {
|
||||
return;
|
||||
}
|
||||
|
||||
let active_hooks = co_material1.active_hooks | co_material2.active_hooks;
|
||||
if !active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR)
|
||||
&& !status1.is_dynamic()
|
||||
&& !status2.is_dynamic()
|
||||
@@ -800,8 +863,8 @@ impl NarrowPhase {
|
||||
colliders,
|
||||
rigid_body1: co_parent1.map(|p| p.handle),
|
||||
rigid_body2: co_parent2.map(|p| p.handle),
|
||||
collider1: pair.pair.collider1,
|
||||
collider2: pair.pair.collider2,
|
||||
collider1: pair.collider1,
|
||||
collider2: pair.collider2,
|
||||
};
|
||||
|
||||
if let Some(solver_flags) = hooks.filter_contact_pair(&context) {
|
||||
@@ -811,7 +874,7 @@ impl NarrowPhase {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
co_material1.solver_flags | co_material2.solver_flags
|
||||
SolverFlags::default()
|
||||
};
|
||||
|
||||
if !co_groups1.solver_groups.test(co_groups2.solver_groups) {
|
||||
@@ -896,12 +959,7 @@ impl NarrowPhase {
|
||||
}
|
||||
|
||||
// Apply the user-defined contact modification.
|
||||
if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS)
|
||||
&& manifold
|
||||
.data
|
||||
.solver_flags
|
||||
.contains(SolverFlags::MODIFY_SOLVER_CONTACTS)
|
||||
{
|
||||
if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS) {
|
||||
let mut modifiable_solver_contacts =
|
||||
std::mem::replace(&mut manifold.data.solver_contacts, Vec::new());
|
||||
let mut modifiable_user_data = manifold.data.user_data;
|
||||
@@ -912,8 +970,8 @@ impl NarrowPhase {
|
||||
colliders,
|
||||
rigid_body1: co_parent1.map(|p| p.handle),
|
||||
rigid_body2: co_parent2.map(|p| p.handle),
|
||||
collider1: pair.pair.collider1,
|
||||
collider2: pair.pair.collider2,
|
||||
collider1: pair.collider1,
|
||||
collider2: pair.collider2,
|
||||
manifold,
|
||||
solver_contacts: &mut modifiable_solver_contacts,
|
||||
normal: &mut modifiable_normal,
|
||||
@@ -931,13 +989,13 @@ impl NarrowPhase {
|
||||
if has_any_active_contact != pair.has_any_active_contact {
|
||||
if has_any_active_contact {
|
||||
events.handle_contact_event(ContactEvent::Started(
|
||||
pair.pair.collider1,
|
||||
pair.pair.collider2,
|
||||
pair.collider1,
|
||||
pair.collider2,
|
||||
));
|
||||
} else {
|
||||
events.handle_contact_event(ContactEvent::Stopped(
|
||||
pair.pair.collider1,
|
||||
pair.pair.collider2,
|
||||
pair.collider1,
|
||||
pair.collider2,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user