Files
rapier/src/geometry/collider_components.rs

380 lines
14 KiB
Rust

use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle, RigidBodyType};
use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape};
use crate::math::{Isometry, Real};
use crate::parry::partitioning::IndexedData;
use crate::pipeline::{ActiveEvents, ActiveHooks};
use std::ops::Deref;
/// The unique identifier of a collider added to a collider set.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct ColliderHandle(pub crate::data::arena::Index);
impl ColliderHandle {
/// Converts this handle into its (index, generation) components.
pub fn into_raw_parts(self) -> (u32, u32) {
self.0.into_raw_parts()
}
/// Reconstructs an handle from its (index, generation) components.
pub fn from_raw_parts(id: u32, generation: u32) -> Self {
Self(crate::data::arena::Index::from_raw_parts(id, generation))
}
/// An always-invalid collider handle.
pub fn invalid() -> Self {
Self(crate::data::arena::Index::from_raw_parts(
crate::INVALID_U32,
crate::INVALID_U32,
))
}
}
impl IndexedData for ColliderHandle {
fn default() -> Self {
Self(IndexedData::default())
}
fn index(&self) -> usize {
self.0.index()
}
}
bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Flags describing how the collider has been modified by the user.
pub struct ColliderChanges: u32 {
/// Flag indicating that any component of the collider has been modified.
const MODIFIED = 1 << 0;
/// Flag indicating that the `RigidBodyParent` component of the collider has been modified.
const PARENT = 1 << 1; // => BF & NF updates.
/// Flag indicating that the `RigidBodyPosition` component of the collider has been modified.
const POSITION = 1 << 2; // => BF & NF updates.
/// Flag indicating that the `RigidBodyGroups` component of the collider has been modified.
const GROUPS = 1 << 3; // => NF update.
/// Flag indicating that the `RigidBodyShape` component of the collider has been modified.
const SHAPE = 1 << 4; // => BF & NF update. NF pair workspace invalidation.
/// Flag indicating that the `RigidBodyType` component of the collider has been modified.
const TYPE = 1 << 5; // => NF update. NF pair invalidation.
}
}
impl Default for ColliderChanges {
fn default() -> Self {
ColliderChanges::empty()
}
}
impl ColliderChanges {
/// Do these changes justify a broad-phase update?
pub fn needs_broad_phase_update(self) -> bool {
self.intersects(
ColliderChanges::PARENT | ColliderChanges::POSITION | ColliderChanges::SHAPE,
)
}
/// Do these changes justify a narrow-phase update?
pub fn needs_narrow_phase_update(self) -> bool {
self.bits() > 1
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The type of collider.
pub enum ColliderType {
/// A collider that can generate contacts and contact events.
Solid,
/// A collider that can generate intersection and intersection events.
Sensor,
}
impl ColliderType {
/// Is this collider a sensor?
pub fn is_sensor(self) -> bool {
self == ColliderType::Sensor
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Data associated to a collider that takes part to a broad-phase algorithm.
pub struct ColliderBroadPhaseData {
pub(crate) proxy_index: SAPProxyIndex,
}
impl Default for ColliderBroadPhaseData {
fn default() -> Self {
ColliderBroadPhaseData {
proxy_index: crate::INVALID_U32,
}
}
}
/// The shape of a collider.
pub type ColliderShape = SharedShape;
#[derive(Clone)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The mass-properties of a collider.
pub enum ColliderMassProps {
/// The collider is given a density.
///
/// Its actual `MassProperties` are computed automatically with
/// the help of [`SharedShape::mass_properties`].
Density(Real),
/// The collider is given explicit mass-properties.
MassProperties(Box<MassProperties>),
}
impl Default for ColliderMassProps {
fn default() -> Self {
ColliderMassProps::Density(1.0)
}
}
impl From<MassProperties> for ColliderMassProps {
fn from(mprops: MassProperties) -> Self {
ColliderMassProps::MassProperties(Box::new(mprops))
}
}
impl ColliderMassProps {
/// The mass-properties of this collider.
///
/// If `self` is the `Density` variant, then this computes the mass-properties based
/// on the given shape.
///
/// If `self` is the `MassProperties` variant, then this returns the stored mass-properties.
pub fn mass_properties(&self, shape: &dyn Shape) -> MassProperties {
match self {
Self::Density(density) => shape.mass_properties(*density),
Self::MassProperties(mprops) => **mprops,
}
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Information about the rigid-body this collider is attached to.
pub struct ColliderParent {
/// Handle of the rigid-body this collider is attached to.
pub handle: RigidBodyHandle,
/// Const position of this collider relative to its parent rigid-body.
pub pos_wrt_parent: Isometry<Real>,
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The position of a collider.
pub struct ColliderPosition(pub Isometry<Real>);
impl AsRef<Isometry<Real>> for ColliderPosition {
#[inline]
fn as_ref(&self) -> &Isometry<Real> {
&self.0
}
}
impl Deref for ColliderPosition {
type Target = Isometry<Real>;
#[inline]
fn deref(&self) -> &Isometry<Real> {
&self.0
}
}
impl Default for ColliderPosition {
fn default() -> Self {
Self::identity()
}
}
impl ColliderPosition {
/// The identity position.
#[must_use]
pub fn identity() -> Self {
ColliderPosition(Isometry::identity())
}
}
impl<T> From<T> for ColliderPosition
where
Isometry<Real>: From<T>,
{
fn from(position: T) -> Self {
Self(position.into())
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The constraints solver-related properties of this collider (friction, restitution, etc.)
pub struct ColliderMaterial {
/// The friction coefficient of this collider.
///
/// The greater the value, the stronger the friction forces will be.
/// Should be `>= 0`.
pub friction: Real,
/// The restitution coefficient of this collider.
///
/// Increase this value to make contacts with this collider more "bouncy".
/// Should be `>= 0` and should generally not be greater than `1` (perfectly elastic
/// collision).
pub restitution: Real,
/// The rule applied to combine the friction coefficients of two colliders in contact.
pub friction_combine_rule: CoefficientCombineRule,
/// The rule applied to combine the restitution coefficients of two colliders.
pub restitution_combine_rule: CoefficientCombineRule,
}
impl ColliderMaterial {
/// Creates a new collider material with the given friction and restitution coefficients.
pub fn new(friction: Real, restitution: Real) -> Self {
Self {
friction,
restitution,
..Default::default()
}
}
}
impl Default for ColliderMaterial {
fn default() -> Self {
Self {
friction: 1.0,
restitution: 0.0,
friction_combine_rule: CoefficientCombineRule::default(),
restitution_combine_rule: CoefficientCombineRule::default(),
}
}
}
bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Flags affecting whether or not collision-detection happens between two colliders
/// depending on the type of rigid-bodies they are attached to.
pub struct ActiveCollisionTypes: u16 {
/// Enable collision-detection between a collider attached to a dynamic body
/// and another collider attached to a dynamic body.
const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
/// Enable collision-detection between a collider attached to a dynamic body
/// and another collider attached to a kinematic body.
const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
/// Enable collision-detection between a collider attached to a dynamic body
/// and another collider attached to a static body (or not attached to any body).
const DYNAMIC_STATIC = 0b0000_0000_0000_0010;
/// Enable collision-detection between a collider attached to a kinematic body
/// and another collider attached to a kinematic body.
const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
/// Enable collision-detection between a collider attached to a kinematic body
/// and another collider attached to a static body (or not attached to any body).
const KINEMATIC_STATIC = 0b0010_0010_0000_0000;
/// Enable collision-detection between a collider attached to a static body (or
/// not attached to any body) and another collider attached to a static body (or
/// not attached to any body).
const STATIC_STATIC = 0b0000_0000_0010_0000;
}
}
impl ActiveCollisionTypes {
/// Test whether contact should be computed between two rigid-bodies with the given types.
pub fn test(self, rb_type1: RigidBodyType, rb_type2: RigidBodyType) -> bool {
// NOTE: This test is quite complicated so here is an explanation.
// First, we associate the following bit masks:
// - DYNAMIC = 0001
// - STATIC = 0010
// - KINEMATIC = 1100
// These are equal to the bits indexed by `RigidBodyType as u32`.
// The bit masks defined by ActiveCollisionTypes are defined is such a way
// that the first part of the variant name (e.g. DYNAMIC_*) indicates which
// groups of four bits should be considered:
// - DYNAMIC_* = the first group of four bits.
// - STATIC_* = the second group of four bits.
// - KINEMATIC_* = the third and fourth groups of four bits.
// The second part of the variant name (e.g. *_DYNAMIC) indicates the value
// of the aforementioned groups of four bits.
// For example, DYNAMIC_STATIC means that the first group of four bits (because
// of DYNAMIC_*) must have the value 0010 (because of *_STATIC). That gives
// us 0b0000_0000_0000_0010 for the DYNAMIC_STATIC_VARIANT.
//
// The KINEMATIC_* is special because it occupies two groups of four bits. This is
// because it combines both KinematicPositionBased and KinematicVelocityBased.
//
// Now that we have a way of building these bit masks, let's see how we use them.
// Given a pair of rigid-body types, the first rigid-body type is used to select
// the group of four bits we want to test (the selection is done by to the
// `>> (rb_type1 as u32 * 4) & 0b0000_1111`) and the second rigid-body type is
// used to form the bit mask we test this group of four bits against.
// In other word, the selection of the group of four bits tells us "for this type
// of rigid-body I can have collision with rigid-body types with these bit representation".
// Then the `(1 << rb_type2)` gives us the bit-representation of the rigid-body type,
// which needs to be checked.
//
// Because that test must be symmetric, we perform two similar tests by swapping
// rb_type1 and rb_type2.
((self.bits >> (rb_type1 as u32 * 4)) & 0b0000_1111) & (1 << rb_type2 as u32) != 0
|| ((self.bits >> (rb_type2 as u32 * 4)) & 0b0000_1111) & (1 << rb_type1 as u32) != 0
}
}
impl Default for ActiveCollisionTypes {
fn default() -> Self {
ActiveCollisionTypes::DYNAMIC_DYNAMIC
| ActiveCollisionTypes::DYNAMIC_KINEMATIC
| ActiveCollisionTypes::DYNAMIC_STATIC
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// A set of flags for controlling collision/intersection filtering, modification, and events.
pub struct ColliderFlags {
/// Controls whether collision-detection happens between two colliders depending on
/// the type of the rigid-bodies they are attached to.
pub active_collision_types: ActiveCollisionTypes,
/// The groups controlling the pairs of colliders that can interact (generate
/// interaction events or contacts).
pub collision_groups: InteractionGroups,
/// The groups controlling the pairs of collider that have their contact
/// points taken into account for force computation.
pub solver_groups: InteractionGroups,
/// The physics hooks enabled for contact pairs and intersection pairs involving this collider.
pub active_hooks: ActiveHooks,
/// The events enabled for this collider.
pub active_events: ActiveEvents,
}
impl Default for ColliderFlags {
fn default() -> Self {
Self {
active_collision_types: ActiveCollisionTypes::default(),
collision_groups: InteractionGroups::all(),
solver_groups: InteractionGroups::all(),
active_hooks: ActiveHooks::empty(),
active_events: ActiveEvents::empty(),
}
}
}
impl From<ActiveHooks> for ColliderFlags {
fn from(active_hooks: ActiveHooks) -> Self {
Self {
active_hooks,
..Default::default()
}
}
}
impl From<ActiveEvents> for ColliderFlags {
fn from(active_events: ActiveEvents) -> Self {
Self {
active_events,
..Default::default()
}
}
}