Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add InteractionGroups::test_or, increase to 64 bits #170

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 51 additions & 16 deletions src/geometry/interaction_groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,45 @@
#[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 (the 32 left-most bits of `self.0`).
/// - The interaction mask (the 32 right-most bits of `self.0`).
///
/// An interaction is allowed between two filters `a` and `b` when two conditions
/// are met simultaneously:
/// are met simultaneously for [`Self::test_and`] or individually for [`Self::test_or`]:
/// - 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`.
///
/// In other words, interactions are allowed between two filter iff. the following condition is met:
/// In other words, interactions are allowed between two filter iff. the following condition is met
/// for [`Self::test_and`]:
/// ```ignore
/// ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
/// ((self.0 >> 32) & rhs.0) != 0 && ((rhs.0 >> 32) & self.0) != 0
/// ```
pub struct InteractionGroups(pub u32);
/// or for [`Self::test_or`]:
/// ```ignore
/// ((self.0 >> 32) & rhs.0) != 0 || ((rhs.0 >> 32) & self.0) != 0
/// ```
pub struct InteractionGroups(pub u64);

#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
/// Specifies which method should be used to test interactions
pub enum InteractionTestMode {
/// Use [`InteractionGroups::test_and`].
AND,
/// Use [`InteractionGroups::test_or`].
OR,
}

impl InteractionGroups {
/// Initializes with the given interaction groups and interaction mask.
pub const fn new(groups: u16, masks: u16) -> Self {
pub const fn new(groups: u32, masks: u32) -> Self {
Self::none().with_groups(groups).with_mask(masks)
}

/// Allow interaction with everything.
pub const fn all() -> Self {
Self(u32::MAX)
Self(u64::MAX)
}

/// Prevent all interactions.
Expand All @@ -35,22 +50,42 @@ impl InteractionGroups {
}

/// 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_groups(self, groups: u32) -> Self {
Self((self.0 & 0x0000_0000_ffff_ffff) | ((groups as u64) << 32))
}

/// 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_mask(self, mask: u32) -> Self {
Self((self.0 & 0xffff_ffff_0000_0000) | (mask as u64))
}

/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// 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.
/// with the mask of `rhs`, **and** vice-versa.
#[inline]
pub const fn test_and(self, rhs: Self) -> bool {
((self.0 >> 32) & rhs.0) != 0 && ((rhs.0 >> 32) & self.0) != 0
}

/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
/// with the mask of `rhs`, **or** vice-versa.
#[inline]
pub const fn test_or(self, rhs: Self) -> bool {
((self.0 >> 32) & rhs.0) != 0 || ((rhs.0 >> 32) & self.0) != 0
}

/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// See [`InteractionTestMode`] for more info.
#[inline]
pub const fn test(self, rhs: Self) -> bool {
((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
pub const fn test(self, rhs: Self, mode: InteractionTestMode) -> bool {
match mode {
InteractionTestMode::AND => self.test_and(rhs),
InteractionTestMode::OR => self.test_or(rhs),
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use self::contact_pair::{ContactPair, SolverContact, SolverFlags};
pub use self::interaction_graph::{
ColliderGraphIndex, InteractionGraph, RigidBodyGraphIndex, TemporaryInteractionIndex,
};
pub use self::interaction_groups::InteractionGroups;
pub use self::interaction_groups::{InteractionGroups, InteractionTestMode};
pub use self::narrow_phase::NarrowPhase;

pub use parry::query::TrackedContact;
Expand Down
44 changes: 40 additions & 4 deletions src/geometry/narrow_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::geometry::collider::ColliderChanges;
use crate::geometry::{
BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ColliderPair, ColliderSet,
ContactData, ContactEvent, ContactManifold, ContactManifoldData, ContactPair, InteractionGraph,
IntersectionEvent, RemovedCollider, SolverContact, SolverFlags,
InteractionTestMode, IntersectionEvent, RemovedCollider, SolverContact, SolverFlags,
};
use crate::math::{Real, Vector};
use crate::pipeline::{
Expand Down Expand Up @@ -55,6 +55,8 @@ pub struct NarrowPhase {
intersection_graph: InteractionGraph<ColliderHandle, bool>,
graph_indices: Coarena<ColliderGraphIndices>,
removed_colliders: Option<Subscription<RemovedCollider>>,
collision_interaction_test_mode: InteractionTestMode,
solver_interaction_test_mode: InteractionTestMode,
}

pub(crate) type ContactManifoldIndex = usize;
Expand All @@ -76,6 +78,8 @@ impl NarrowPhase {
intersection_graph: InteractionGraph::new(),
graph_indices: Coarena::new(),
removed_colliders: None,
collision_interaction_test_mode: InteractionTestMode::AND,
solver_interaction_test_mode: InteractionTestMode::OR,
}
}

Expand Down Expand Up @@ -502,6 +506,7 @@ impl NarrowPhase {
let nodes = &self.intersection_graph.graph.nodes;
let query_dispatcher = &*self.query_dispatcher;
let active_hooks = hooks.active_hooks();
let collision_interaction_test_mode = self.collision_interaction_test_mode;

// TODO: don't iterate on all the edges.
par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| {
Expand All @@ -528,7 +533,10 @@ impl NarrowPhase {
return;
}

if !co1.collision_groups.test(co2.collision_groups) {
if !co1
.collision_groups
.test(co2.collision_groups, collision_interaction_test_mode)
{
// The intersection is not allowed.
return;
}
Expand Down Expand Up @@ -588,6 +596,8 @@ impl NarrowPhase {

let query_dispatcher = &*self.query_dispatcher;
let active_hooks = hooks.active_hooks();
let collision_interaction_test_mode = self.collision_interaction_test_mode;
let solver_interaction_test_mode = self.solver_interaction_test_mode;

// TODO: don't iterate on all the edges.
par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
Expand All @@ -613,7 +623,10 @@ impl NarrowPhase {
return;
}

if !co1.collision_groups.test(co2.collision_groups) {
if !co1
.collision_groups
.test(co2.collision_groups, collision_interaction_test_mode)
{
// The collision is not allowed.
return;
}
Expand Down Expand Up @@ -647,7 +660,10 @@ impl NarrowPhase {
co1.solver_flags | co2.solver_flags
};

if !co1.solver_groups.test(co2.solver_groups) {
if !co1
.collision_groups
.test(co2.solver_groups, solver_interaction_test_mode)
{
solver_flags.remove(SolverFlags::COMPUTE_IMPULSES);
}

Expand Down Expand Up @@ -808,4 +824,24 @@ impl NarrowPhase {
}
}
}

/// The test mode used to test the solver groups
pub fn solver_interaction_test_mode(&self) -> InteractionTestMode {
self.solver_interaction_test_mode
}

/// The test mode used to test the collision groups
pub fn collision_interaction_test_mode(&self) -> InteractionTestMode {
self.collision_interaction_test_mode
}

/// Sets the test mode used to test the solver groups
pub fn set_solver_interaction_test_mode(&mut self, mode: InteractionTestMode) {
self.solver_interaction_test_mode = mode;
}

/// Sets the test mode used to test the collision groups
pub fn set_collision_interaction_test_mode(&mut self, mode: InteractionTestMode) {
self.collision_interaction_test_mode = mode;
}
}
32 changes: 26 additions & 6 deletions src/pipeline/query_pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::dynamics::RigidBodySet;
use crate::geometry::{
Collider, ColliderHandle, ColliderSet, InteractionGroups, PointProjection, Ray,
RayIntersection, SimdQuadTree, AABB,
Collider, ColliderHandle, ColliderSet, InteractionGroups, InteractionTestMode, PointProjection,
Ray, RayIntersection, SimdQuadTree, AABB,
};
use crate::math::{Isometry, Point, Real, Vector};
use parry::query::details::{
Expand Down Expand Up @@ -30,6 +30,7 @@ pub struct QueryPipeline {
quadtree: SimdQuadTree<ColliderHandle>,
tree_built: bool,
dilation_factor: Real,
interaction_test_mode: InteractionTestMode,
}

struct QueryPipelineAsCompositeShape<'a> {
Expand Down Expand Up @@ -65,7 +66,9 @@ impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> {
mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape),
) {
if let Some(collider) = self.colliders.get(shape_id) {
if collider.collision_groups.test(self.query_groups)
if collider
.collision_groups
.test(self.query_groups, self.query_pipeline.interaction_test_mode)
&& self.filter.map(|f| f(shape_id, collider)).unwrap_or(true)
{
f(Some(collider.position()), collider.shape())
Expand Down Expand Up @@ -125,6 +128,7 @@ impl QueryPipeline {
quadtree: SimdQuadTree::new(),
tree_built: false,
dilation_factor: 0.01,
interaction_test_mode: InteractionTestMode::AND,
}
}

Expand Down Expand Up @@ -313,7 +317,9 @@ impl QueryPipeline {
) {
let mut leaf_callback = &mut |handle: &ColliderHandle| {
if let Some(coll) = colliders.get(*handle) {
if coll.collision_groups.test(query_groups)
if coll
.collision_groups
.test(query_groups, self.interaction_test_mode)
&& filter.map(|f| f(*handle, coll)).unwrap_or(true)
{
if let Some(hit) =
Expand Down Expand Up @@ -418,7 +424,9 @@ impl QueryPipeline {
) {
let mut leaf_callback = &mut |handle: &ColliderHandle| {
if let Some(coll) = colliders.get(*handle) {
if coll.collision_groups.test(query_groups)
if coll
.collision_groups
.test(query_groups, self.interaction_test_mode)
&& filter.map(|f| f(*handle, coll)).unwrap_or(true)
&& coll.shape().contains_point(coll.position(), point)
{
Expand Down Expand Up @@ -588,7 +596,9 @@ impl QueryPipeline {

let mut leaf_callback = &mut |handle: &ColliderHandle| {
if let Some(coll) = colliders.get(*handle) {
if coll.collision_groups.test(query_groups)
if coll
.collision_groups
.test(query_groups, self.interaction_test_mode)
&& filter.map(|f| f(*handle, coll)).unwrap_or(true)
{
let pos12 = inv_shape_pos * coll.position();
Expand All @@ -607,4 +617,14 @@ impl QueryPipeline {

self.quadtree.traverse_depth_first(&mut visitor);
}

/// The test mode used to test for intersection
pub fn interaction_test_mode(&self) -> InteractionTestMode {
self.interaction_test_mode
}

/// Sets the test mode used to test for intersections
pub fn set_interaction_test_mode(&mut self, mode: InteractionTestMode) {
self.interaction_test_mode = mode;
}
}