Add comments.

This commit is contained in:
Crozet Sébastien
2021-04-30 11:37:58 +02:00
parent ac8ec8e351
commit 2dfbd9ae92
16 changed files with 440 additions and 164 deletions

View File

@@ -770,13 +770,13 @@ impl<T> Arena<T> {
/// other kinds of bit-efficient indexing.
///
/// You should use the `get` method instead most of the time.
pub fn get_unknown_gen(&self, i: usize) -> Option<(&T, Index)> {
match self.items.get(i) {
pub fn get_unknown_gen(&self, i: u32) -> Option<(&T, Index)> {
match self.items.get(i as usize) {
Some(Entry::Occupied { generation, value }) => Some((
value,
Index {
generation: *generation,
index: i as u32,
index: i,
},
)),
_ => None,
@@ -793,13 +793,13 @@ impl<T> Arena<T> {
/// other kinds of bit-efficient indexing.
///
/// You should use the `get_mut` method instead most of the time.
pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut T, Index)> {
match self.items.get_mut(i) {
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut T, Index)> {
match self.items.get_mut(i as usize) {
Some(Entry::Occupied { generation, value }) => Some((
value,
Index {
generation: *generation,
index: i as u32,
index: i,
},
)),
_ => None,

View File

@@ -5,30 +5,47 @@ use crate::data::Index;
// fn get(&self, handle: Index) -> Option<&T>;
// }
/// A set of optional elements of type `T`.
pub trait ComponentSetOption<T>: Sync {
/// Get the element associated to the given `handle`, if there is one.
fn get(&self, handle: Index) -> Option<&T>;
}
/// A set of elements of type `T`.
pub trait ComponentSet<T>: ComponentSetOption<T> {
/// The estimated number of elements in this set.
///
/// This value is typically used for preallocating some arrays for
/// better performances.
fn size_hint(&self) -> usize;
// TODO ECS: remove this, its only needed by the query pipeline update
// which should only take the modified colliders into account.
/// Iterate through all the elements on this set.
fn for_each(&self, f: impl FnMut(Index, &T));
/// Get the element associated to the given `handle`.
fn index(&self, handle: Index) -> &T {
self.get(handle).unwrap()
}
}
/// A set of mutable elements of type `T`.
pub trait ComponentSetMut<T>: ComponentSet<T> {
/// Applies the given closure to the element associated to the given `handle`.
///
/// Return `None` if the element doesn't exist.
fn map_mut_internal<Result>(
&mut self,
handle: crate::data::Index,
f: impl FnOnce(&mut T) -> Result,
) -> Option<Result>;
/// Set the value of this element.
fn set_internal(&mut self, handle: crate::data::Index, val: T);
}
/// Helper trait to address multiple elements at once.
pub trait BundleSet<'a, T> {
/// Access multiple elements from this set.
fn index_bundle(&'a self, handle: Index) -> T;
}

View File

@@ -6,6 +6,8 @@ use crate::dynamics::{
use crate::geometry::{ColliderParent, InteractionGraph, NarrowPhase};
use crate::math::Real;
/// Structure responsible for maintaining the set of active rigid-bodies, and
/// putting non-moving rigid-bodies to sleep to save computation times.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct IslandManager {
pub(crate) active_dynamic_set: Vec<RigidBodyHandle>,
@@ -19,6 +21,7 @@ pub struct IslandManager {
}
impl IslandManager {
/// Creates a new empty island manager.
pub fn new() -> Self {
Self {
active_dynamic_set: vec![],
@@ -34,6 +37,7 @@ impl IslandManager {
self.active_islands.len() - 1
}
/// Update this data-structure after one or multiple rigid-bodies have been removed for `bodies`.
pub fn cleanup_removed_rigid_bodies(
&mut self,
bodies: &mut impl ComponentSetMut<RigidBodyIds>,
@@ -59,7 +63,7 @@ impl IslandManager {
}
}
pub fn rigid_body_removed(
pub(crate) fn rigid_body_removed(
&mut self,
removed_handle: RigidBodyHandle,
removed_ids: &RigidBodyIds,

View File

@@ -94,7 +94,7 @@ impl JointSet {
///
/// Using this is discouraged in favor of `self.get(handle)` which does not
/// suffer form the ABA problem.
pub fn get_unknown_gen(&self, i: usize) -> Option<(&Joint, JointHandle)> {
pub fn get_unknown_gen(&self, i: u32) -> Option<(&Joint, JointHandle)> {
let (id, handle) = self.joint_ids.get_unknown_gen(i)?;
Some((
self.joint_graph.graph.edge_weight(*id)?,
@@ -111,7 +111,7 @@ impl JointSet {
///
/// Using this is discouraged in favor of `self.get_mut(handle)` which does not
/// suffer form the ABA problem.
pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut Joint, JointHandle)> {
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Joint, JointHandle)> {
let (id, handle) = self.joint_ids.get_unknown_gen(i)?;
Some((
self.joint_graph.graph.edge_weight_mut(*id)?,

View File

@@ -7,8 +7,8 @@ use crate::geometry::{
Collider, ColliderHandle, ColliderMassProperties, ColliderParent, ColliderPosition,
ColliderShape,
};
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Translation, Vector};
use crate::utils::{self, WAngularInertia, WCross};
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector};
use crate::utils::{self, WCross};
use na::ComplexField;
use num::Zero;
@@ -18,21 +18,21 @@ use num::Zero;
/// To create a new rigid-body, use the `RigidBodyBuilder` structure.
#[derive(Debug, Clone)]
pub struct RigidBody {
pub rb_pos: RigidBodyPosition, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_mprops: RigidBodyMassProps, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_vels: RigidBodyVelocity, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_damping: RigidBodyDamping, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_forces: RigidBodyForces, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_ccd: RigidBodyCcd, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_ids: RigidBodyIds, // TODO ECS: public only for initial tests with bevy_rapier.
pub rb_colliders: RigidBodyColliders, // TODO ECS: public only for initial tests with bevy_rapier.
pub(crate) rb_pos: RigidBodyPosition,
pub(crate) rb_mprops: RigidBodyMassProps,
pub(crate) rb_vels: RigidBodyVelocity,
pub(crate) rb_damping: RigidBodyDamping,
pub(crate) rb_forces: RigidBodyForces,
pub(crate) rb_ccd: RigidBodyCcd,
pub(crate) rb_ids: RigidBodyIds,
pub(crate) rb_colliders: RigidBodyColliders,
/// Whether or not this rigid-body is sleeping.
pub rb_activation: RigidBodyActivation, // TODO ECS: public only for initial tests with bevy_rapier.
pub changes: RigidBodyChanges, // TODO ECS: public only for initial tests with bevy_rapier.
pub(crate) rb_activation: RigidBodyActivation,
pub(crate) changes: RigidBodyChanges,
/// The status of the body, governing how it is affected by external forces.
pub rb_type: RigidBodyType, // TODO ECS: public only for initial tests with bevy_rapier
pub(crate) rb_type: RigidBodyType,
/// The dominance group this rigid-body is part of.
pub rb_dominance: RigidBodyDominance,
pub(crate) rb_dominance: RigidBodyDominance,
/// User-defined data associated to this rigid-body.
pub user_data: u128,
}
@@ -61,61 +61,48 @@ impl RigidBody {
self.rb_ids = Default::default();
}
pub fn user_data(&self) -> u128 {
self.user_data
}
pub fn set_user_data(&mut self, data: u128) {
self.user_data = data;
}
#[inline]
pub fn rb_activation(&self) -> &RigidBodyActivation {
/// The activation status of this rigid-body.
pub fn activation(&self) -> &RigidBodyActivation {
&self.rb_activation
}
#[inline]
/// Mutable reference to the activation status of this rigid-body.
pub fn activation_mut(&mut self) -> &mut RigidBodyActivation {
self.changes |= RigidBodyChanges::SLEEP;
&mut self.rb_activation
}
#[inline]
pub(crate) fn changes(&self) -> RigidBodyChanges {
self.changes
}
#[inline]
pub(crate) fn changes_mut_internal(&mut self) -> &mut RigidBodyChanges {
&mut self.changes
}
/// The linear damping coefficient of this rigid-body.
#[inline]
pub fn linear_damping(&self) -> Real {
self.rb_damping.linear_damping
}
/// Sets the linear damping coefficient of this rigid-body.
#[inline]
pub fn set_linear_damping(&mut self, damping: Real) {
self.rb_damping.linear_damping = damping;
}
/// The angular damping coefficient of this rigid-body.
#[inline]
pub fn angular_damping(&self) -> Real {
self.rb_damping.angular_damping
}
/// Sets the angular damping coefficient of this rigid-body.
#[inline]
pub fn set_angular_damping(&mut self, damping: Real) {
self.rb_damping.angular_damping = damping
}
/// The status of this rigid-body.
pub fn rb_type(&self) -> RigidBodyType {
/// The type of this rigid-body.
pub fn body_type(&self) -> RigidBodyType {
self.rb_type
}
/// Sets the status of this rigid-body.
pub fn set_rb_type(&mut self, status: RigidBodyType) {
/// Sets the type of this rigid-body.
pub fn set_body_type(&mut self, status: RigidBodyType) {
if status != self.rb_type {
self.changes.insert(RigidBodyChanges::TYPE);
self.rb_type = status;
@@ -336,22 +323,6 @@ impl RigidBody {
!self.rb_vels.linvel.is_zero() || !self.rb_vels.angvel.is_zero()
}
/// Computes the predict position of this rigid-body after `dt` seconds, taking
/// into account its velocities and external forces applied to it.
pub fn predict_position_using_velocity_and_forces(&self, dt: Real) -> Isometry<Real> {
let dlinvel = self.rb_forces.force * (self.rb_mprops.effective_inv_mass * dt);
let dangvel = self
.rb_mprops
.effective_world_inv_inertia_sqrt
.transform_vector(self.rb_forces.torque * dt);
let linvel = self.rb_vels.linvel + dlinvel;
let angvel = self.rb_vels.angvel + dangvel;
let com = self.rb_pos.position * self.rb_mprops.mass_properties.local_com;
let shift = Translation::from(com.coords);
shift * Isometry::new(linvel * dt, angvel * dt) * shift.inverse() * self.rb_pos.position
}
/// The linear velocity of this rigid-body.
pub fn linvel(&self) -> &Vector<Real> {
&self.rb_vels.linvel
@@ -567,30 +538,13 @@ impl RigidBody {
impl RigidBody {
/// The velocity of the given world-space point on this rigid-body.
pub fn velocity_at_point(&self, point: &Point<Real>) -> Vector<Real> {
let dpt = point - self.rb_mprops.world_com;
self.rb_vels.linvel + self.rb_vels.angvel.gcross(dpt)
self.rb_vels
.velocity_at_point(point, &self.rb_mprops.world_com)
}
/// The kinetic energy of this body.
pub fn kinetic_energy(&self) -> Real {
let mut energy = (self.mass() * self.rb_vels.linvel.norm_squared()) / 2.0;
#[cfg(feature = "dim2")]
if !self.rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
let inertia_sqrt = 1.0 / self.rb_mprops.effective_world_inv_inertia_sqrt;
energy += (inertia_sqrt * self.rb_vels.angvel).powi(2) / 2.0;
}
#[cfg(feature = "dim3")]
if !self.rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
let inertia_sqrt = self
.rb_mprops
.effective_world_inv_inertia_sqrt
.inverse_unchecked();
energy += (inertia_sqrt * self.rb_vels.angvel).norm_squared() / 2.0;
}
energy
self.rb_vels.kinetic_energy(&self.rb_mprops)
}
/// The potential energy of this body in a gravity field.
@@ -894,39 +848,6 @@ impl RigidBodyBuilder {
self
}
pub fn components(
&self,
) -> (
RigidBodyPosition,
RigidBodyMassProps,
RigidBodyVelocity,
RigidBodyDamping,
RigidBodyForces,
RigidBodyCcd,
RigidBodyIds,
RigidBodyColliders,
RigidBodyActivation,
RigidBodyChanges,
RigidBodyType,
RigidBodyDominance,
) {
let rb = self.build();
(
rb.rb_pos,
rb.rb_mprops,
rb.rb_vels,
rb.rb_damping,
rb.rb_forces,
rb.rb_ccd,
rb.rb_ids,
rb.rb_colliders,
rb.rb_activation,
rb.changes,
rb.rb_type,
rb.rb_dominance,
)
}
/// Build a new rigid-body with the parameters configured with this builder.
pub fn build(&self) -> RigidBody {
let mut rb = RigidBody::new();

View File

@@ -6,7 +6,7 @@ use crate::geometry::{
};
use crate::math::{AngVector, AngularInertia, Isometry, Point, Real, Translation, Vector};
use crate::parry::partitioning::IndexedData;
use crate::utils::WDot;
use crate::utils::{WCross, WDot};
use num::Zero;
/// The unique handle of a rigid body added to a `RigidBodySet`.
@@ -69,14 +69,17 @@ pub enum RigidBodyType {
}
impl RigidBodyType {
/// Is this rigid-body static (i.e. cannot move)?
pub fn is_static(self) -> bool {
self == RigidBodyType::Static
}
/// Is this rigid-body dynamic (i.e. can move and be affected by forces)?
pub fn is_dynamic(self) -> bool {
self == RigidBodyType::Dynamic
}
/// Is this rigid-body kinematic (i.e. can move but is unaffected by forces)?
pub fn is_kinematic(self) -> bool {
self == RigidBodyType::Kinematic
}
@@ -86,10 +89,15 @@ bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Flags describing how the rigid-body has been modified by the user.
pub struct RigidBodyChanges: u32 {
/// Flag indicating that any component of this rigid-body has been modified.
const MODIFIED = 1 << 0;
/// Flag indicating that the `RigidBodyPosition` component of this rigid-body has been modified.
const POSITION = 1 << 1;
/// Flag indicating that the `RigidBodyActivation` component of this rigid-body has been modified.
const SLEEP = 1 << 2;
/// Flag indicating that the `RigidBodyColliders` component of this rigid-body has been modified.
const COLLIDERS = 1 << 3;
/// Flag indicating that the `RigidBodyType` component of this rigid-body has been modified.
const TYPE = 1 << 4;
}
}
@@ -102,6 +110,7 @@ impl Default for RigidBodyChanges {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// The position of this rigid-body.
pub struct RigidBodyPosition {
/// The world-space position of the rigid-body.
pub position: Isometry<Real>,
@@ -127,6 +136,8 @@ impl Default for RigidBodyPosition {
}
impl RigidBodyPosition {
/// Computes the velocity need to travel from `self.position` to `self.next_position` in
/// a time equal to `1.0 / inv_dt`.
#[must_use]
pub fn interpolate_velocity(&self, inv_dt: Real) -> RigidBodyVelocity {
let dpos = self.next_position * self.position.inverse();
@@ -143,6 +154,9 @@ impl RigidBodyPosition {
RigidBodyVelocity { linvel, angvel }
}
/// Compute new positions after integrating the given forces and velocities.
///
/// This uses a symplectic Euler integration scheme.
#[must_use]
pub fn integrate_forces_and_velocities(
&self,
@@ -173,16 +187,23 @@ bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Flags affecting the behavior of the constraints solver for a given contact manifold.
pub struct RigidBodyMassPropsFlags: u8 {
/// Flag indicating that the rigid-body cannot translate along any direction.
const TRANSLATION_LOCKED = 1 << 0;
/// Flag indicating that the rigid-body cannot rotate along the `X` axis.
const ROTATION_LOCKED_X = 1 << 1;
/// Flag indicating that the rigid-body cannot rotate along the `X` axis.
const ROTATION_LOCKED_Y = 1 << 2;
/// Flag indicating that the rigid-body cannot rotate along the `X` axis.
const ROTATION_LOCKED_Z = 1 << 3;
/// Combination of flags indicating that the rigid-body cannot rotate along any axis.
const ROTATION_LOCKED = Self::ROTATION_LOCKED_X.bits | Self::ROTATION_LOCKED_Y.bits | Self::ROTATION_LOCKED_Z.bits;
}
}
// TODO: split this into "LocalMassProps" and `WorldMassProps"?
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// The mass properties of this rigid-bodies.
pub struct RigidBodyMassProps {
/// Flags for locking rotation and translation.
pub flags: RigidBodyMassPropsFlags,
@@ -219,16 +240,20 @@ impl From<RigidBodyMassPropsFlags> for RigidBodyMassProps {
}
impl RigidBodyMassProps {
/// The mass of the rigid-body.
#[must_use]
pub fn with_translations_locked(mut self) -> Self {
self.flags |= RigidBodyMassPropsFlags::TRANSLATION_LOCKED;
self
pub fn mass(&self) -> Real {
crate::utils::inv(self.mass_properties.inv_mass)
}
/// The effective mass (that takes the potential translation locking into account) of
/// this rigid-body.
#[must_use]
pub fn effective_mass(&self) -> Real {
crate::utils::inv(self.effective_inv_mass)
}
/// Update the world-space mass properties of `self`, taking into account the new position.
pub fn update_world_mass_properties(&mut self, position: &Isometry<Real>) {
self.world_com = self.mass_properties.world_com(&position);
self.effective_inv_mass = self.mass_properties.inv_mass;
@@ -286,6 +311,7 @@ impl RigidBodyMassProps {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// The velocities of this rigid-body.
pub struct RigidBodyVelocity {
/// The linear velocity of the rigid-body.
pub linvel: Vector<Real>,
@@ -300,6 +326,7 @@ impl Default for RigidBodyVelocity {
}
impl RigidBodyVelocity {
/// Velocities set to zero.
#[must_use]
pub fn zero() -> Self {
Self {
@@ -308,11 +335,16 @@ impl RigidBodyVelocity {
}
}
/// The approximate kinetic energy of this rigid-body.
///
/// This approximation does not take the rigid-body's mass and angular inertia
/// into account.
#[must_use]
pub fn pseudo_kinetic_energy(&self) -> Real {
self.linvel.norm_squared() + self.angvel.gdot(self.angvel)
}
/// Returns the update velocities after applying the given damping.
#[must_use]
pub fn apply_damping(&self, dt: Real, damping: &RigidBodyDamping) -> Self {
RigidBodyVelocity {
@@ -321,6 +353,15 @@ impl RigidBodyVelocity {
}
}
/// The velocity of the given world-space point on this rigid-body.
#[must_use]
pub fn velocity_at_point(&self, point: &Point<Real>, world_com: &Point<Real>) -> Vector<Real> {
let dpt = point - world_com;
self.linvel + self.angvel.gcross(dpt)
}
/// Integrate the velocities in `self` to compute obtain new positions when moving from the given
/// inital position `init_pos`.
#[must_use]
pub fn integrate(
&self,
@@ -336,14 +377,81 @@ impl RigidBodyVelocity {
result
}
/// Are these velocities exactly equal to zero?
#[must_use]
pub fn is_zero(&self) -> bool {
self.linvel.is_zero() && self.angvel.is_zero()
}
/// The kinetic energy of this rigid-body.
#[must_use]
pub fn kinetic_energy(&self, rb_mprops: &RigidBodyMassProps) -> Real {
let mut energy = (rb_mprops.mass() * self.linvel.norm_squared()) / 2.0;
#[cfg(feature = "dim2")]
if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
let inertia_sqrt = 1.0 / rb_mprops.effective_world_inv_inertia_sqrt;
energy += (inertia_sqrt * self.angvel).powi(2) / 2.0;
}
#[cfg(feature = "dim3")]
if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
let inertia_sqrt = rb_mprops
.effective_world_inv_inertia_sqrt
.inverse_unchecked();
energy += (inertia_sqrt * self.angvel).norm_squared() / 2.0;
}
energy
}
/// Applies an impulse at the center-of-mass of this rigid-body.
/// The impulse is applied right away, changing the linear velocity.
/// This does nothing on non-dynamic bodies.
pub fn apply_impulse(&mut self, rb_mprops: &RigidBodyMassProps, impulse: Vector<Real>) {
self.linvel += impulse * rb_mprops.effective_inv_mass;
}
/// Applies an angular impulse at the center-of-mass of this rigid-body.
/// The impulse is applied right away, changing the angular velocity.
/// This does nothing on non-dynamic bodies.
#[cfg(feature = "dim2")]
pub fn apply_torque_impulse(&mut self, rb_mprops: &RigidBodyMassProps, torque_impulse: Real) {
self.angvel += rb_mprops.effective_world_inv_inertia_sqrt
* (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse);
}
/// Applies an angular impulse at the center-of-mass of this rigid-body.
/// The impulse is applied right away, changing the angular velocity.
/// This does nothing on non-dynamic bodies.
#[cfg(feature = "dim3")]
pub fn apply_torque_impulse(
&mut self,
rb_mprops: &RigidBodyMassProps,
torque_impulse: Vector<Real>,
) {
self.angvel += rb_mprops.effective_world_inv_inertia_sqrt
* (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse);
}
/// Applies an impulse at the given world-space point of this rigid-body.
/// The impulse is applied right away, changing the linear and/or angular velocities.
/// This does nothing on non-dynamic bodies.
pub fn apply_impulse_at_point(
&mut self,
rb_mprops: &RigidBodyMassProps,
impulse: Vector<Real>,
point: Point<Real>,
) {
let torque_impulse = (point - rb_mprops.world_com).gcross(impulse);
self.apply_impulse(rb_mprops, impulse);
self.apply_torque_impulse(rb_mprops, torque_impulse);
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// Damping factors to progressively slow down a rigid-body.
pub struct RigidBodyDamping {
/// Damping factor for gradually slowing down the translational motion of the rigid-body.
pub linear_damping: Real,
@@ -362,11 +470,14 @@ impl Default for RigidBodyDamping {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// The user-defined external forces applied to this rigid-body.
pub struct RigidBodyForces {
/// Accumulation of external forces (only for dynamic bodies).
pub force: Vector<Real>,
/// Accumulation of external torques (only for dynamic bodies).
pub torque: AngVector<Real>,
/// Gravity is multiplied by this scaling factor before it's
/// applied to this rigid-body.
pub gravity_scale: Real,
}
@@ -381,6 +492,7 @@ impl Default for RigidBodyForces {
}
impl RigidBodyForces {
/// Integrate these forces to compute new velocities.
#[must_use]
pub fn integrate(
&self,
@@ -398,17 +510,41 @@ impl RigidBodyForces {
}
}
pub fn add_linear_acceleration(&mut self, gravity: &Vector<Real>, mass: Real) {
/// Adds to `self` the gravitational force that would result in a gravitational acceleration
/// equal to `gravity`.
pub fn add_gravity_acceleration(&mut self, gravity: &Vector<Real>, mass: Real) {
self.force += gravity * self.gravity_scale * mass;
}
/// Applies a force at the given world-space point of the rigid-body with the given mass properties.
pub fn apply_force_at_point(
&mut self,
rb_mprops: &RigidBodyMassProps,
force: Vector<Real>,
point: Point<Real>,
) {
self.force += force;
self.torque += (point - rb_mprops.world_com).gcross(force);
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// Information used for Continuous-Collision-Detection.
pub struct RigidBodyCcd {
/// The distance used by the CCD solver to decide if a movement would
/// result in a tunnelling problem.
pub ccd_thickness: Real,
/// The max distance between this rigid-body's center of mass and its
/// furthest collider point.
pub ccd_max_dist: Real,
/// Is CCD active for this rigid-body?
///
/// If `self.ccd_enabled` is `true`, then this is automatically set to
/// `true` when the CCD solver detects that the rigid-body is moving fast
/// enough to potential cause a tunneling problem.
pub ccd_active: bool,
/// Is CCD enabled for this rigid-body?
pub ccd_enabled: bool,
}
@@ -424,6 +560,8 @@ impl Default for RigidBodyCcd {
}
impl RigidBodyCcd {
/// The maximum velocity any point of any collider attached to this rigid-body
/// moving with the given velocity can have.
pub fn max_point_velocity(&self, vels: &RigidBodyVelocity) -> Real {
#[cfg(feature = "dim2")]
return vels.linvel.norm() + vels.angvel.abs() * self.ccd_max_dist;
@@ -431,6 +569,7 @@ impl RigidBodyCcd {
return vels.linvel.norm() + vels.angvel.norm() * self.ccd_max_dist;
}
/// Is this rigid-body moving fast enough so that it may cause a tunneling problem?
pub fn is_moving_fast(
&self,
dt: Real,
@@ -463,12 +602,13 @@ impl RigidBodyCcd {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// Internal identifiers used by the physics engine.
pub struct RigidBodyIds {
pub joint_graph_index: RigidBodyGraphIndex,
pub active_island_id: usize,
pub active_set_id: usize,
pub active_set_offset: usize,
pub active_set_timestamp: u32,
pub(crate) joint_graph_index: RigidBodyGraphIndex,
pub(crate) active_island_id: usize,
pub(crate) active_set_id: usize,
pub(crate) active_set_offset: usize,
pub(crate) active_set_timestamp: u32,
}
impl Default for RigidBodyIds {
@@ -485,6 +625,11 @@ impl Default for RigidBodyIds {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
/// The set of colliders attached to this rigid-bodies.
///
/// This should not be modified manually unless you really know what
/// you are doing (for example if you are trying to integrate Rapier
/// to a game engine using its component-based interface).
pub struct RigidBodyColliders(pub Vec<ColliderHandle>);
impl Default for RigidBodyColliders {
@@ -494,6 +639,7 @@ impl Default for RigidBodyColliders {
}
impl RigidBodyColliders {
/// Detach a collider from this rigid-body.
pub fn detach_collider(
&mut self,
rb_changes: &mut RigidBodyChanges,
@@ -508,6 +654,7 @@ impl RigidBodyColliders {
}
}
/// Attach a collider to this rigid-body.
pub fn attach_collider(
&mut self,
rb_changes: &mut RigidBodyChanges,
@@ -541,6 +688,7 @@ impl RigidBodyColliders {
rb_mprops.update_world_mass_properties(&rb_pos.position);
}
/// Update the positions of all the colliders attached to this rigid-body.
pub fn update_positions<Colliders>(
&self,
colliders: &mut Colliders,
@@ -574,6 +722,7 @@ impl RigidBodyColliders {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Copy)]
/// The dominance groups of a rigid-body.
pub struct RigidBodyDominance(pub i8);
impl Default for RigidBodyDominance {
@@ -583,6 +732,7 @@ impl Default for RigidBodyDominance {
}
impl RigidBodyDominance {
/// The actually dominance group of this rigid-body, after taking into account its type.
pub fn effective_group(&self, status: &RigidBodyType) -> i16 {
if status.is_dynamic() {
self.0 as i16
@@ -643,6 +793,7 @@ impl RigidBodyActivation {
self.energy != 0.0
}
/// Wakes up this rigid-body.
#[inline]
pub fn wake_up(&mut self, strong: bool) {
self.sleeping = false;
@@ -651,6 +802,7 @@ impl RigidBodyActivation {
}
}
/// Put this rigid-body to sleep.
#[inline]
pub fn sleep(&mut self) {
self.energy = 0.0;

View File

@@ -125,7 +125,7 @@ impl RigidBodySet {
// Make sure the internal links are reset, they may not be
// if this rigid-body was obtained by cloning another one.
rb.reset_internal_references();
rb.changes_mut_internal().set(RigidBodyChanges::all(), true);
rb.changes.set(RigidBodyChanges::all(), true);
let handle = RigidBodyHandle(self.bodies.insert(rb));
self.modified_bodies.push(handle);
@@ -170,7 +170,7 @@ impl RigidBodySet {
///
/// Using this is discouraged in favor of `self.get(handle)` which does not
/// suffer form the ABA problem.
pub fn get_unknown_gen(&self, i: usize) -> Option<(&RigidBody, RigidBodyHandle)> {
pub fn get_unknown_gen(&self, i: u32) -> Option<(&RigidBody, RigidBodyHandle)> {
self.bodies
.get_unknown_gen(i)
.map(|(b, h)| (b, RigidBodyHandle(h)))
@@ -186,7 +186,7 @@ impl RigidBodySet {
/// Using this is discouraged in favor of `self.get_mut(handle)` which does not
/// suffer form the ABA problem.
#[cfg(not(feature = "dev-remove-slow-accessors"))]
pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut RigidBody, RigidBodyHandle)> {
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut RigidBody, RigidBodyHandle)> {
let (rb, handle) = self.bodies.get_unknown_gen_mut(i)?;
let handle = RigidBodyHandle(handle);
Self::mark_as_modified(handle, rb, &mut self.modified_bodies);
@@ -203,8 +203,8 @@ impl RigidBodySet {
rb: &mut RigidBody,
modified_bodies: &mut Vec<RigidBodyHandle>,
) {
if !rb.changes().contains(RigidBodyChanges::MODIFIED) {
*rb.changes_mut_internal() = RigidBodyChanges::MODIFIED;
if !rb.changes.contains(RigidBodyChanges::MODIFIED) {
rb.changes = RigidBodyChanges::MODIFIED;
modified_bodies.push(handle);
}
}

View File

@@ -7,7 +7,7 @@ use crate::geometry::{
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
use crate::parry::transformation::vhacd::VHACDParameters;
use na::Unit;
use parry::bounding_volume::{BoundingVolume, AABB};
use parry::bounding_volume::AABB;
use parry::shape::Shape;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
@@ -16,22 +16,21 @@ use parry::shape::Shape;
///
/// To build a new collider, use the `ColliderBuilder` structure.
pub struct Collider {
pub co_type: ColliderType,
pub co_shape: ColliderShape, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_mprops: ColliderMassProperties, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_changes: ColliderChanges, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_parent: ColliderParent, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_pos: ColliderPosition, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_material: ColliderMaterial, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_groups: ColliderGroups, // TODO ECS: this is public only for our bevy_rapier experiments.
pub co_bf_data: ColliderBroadPhaseData, // TODO ECS: this is public only for our bevy_rapier experiments.
pub(crate) co_type: ColliderType,
pub(crate) co_shape: ColliderShape,
pub(crate) co_mprops: ColliderMassProperties,
pub(crate) co_changes: ColliderChanges,
pub(crate) co_parent: ColliderParent,
pub(crate) co_pos: ColliderPosition,
pub(crate) co_material: ColliderMaterial,
pub(crate) co_groups: ColliderGroups,
pub(crate) co_bf_data: ColliderBroadPhaseData,
/// User-defined data associated to this rigid-body.
pub user_data: u128,
}
impl Collider {
// TODO ECS: exists only for our bevy_ecs tests.
pub fn reset_internal_references(&mut self) {
pub(crate) fn reset_internal_references(&mut self) {
self.co_parent.handle = RigidBodyHandle::invalid();
self.co_bf_data.proxy_index = crate::INVALID_U32;
self.co_changes = ColliderChanges::all();
@@ -140,6 +139,7 @@ impl Collider {
}
}
/// The material (friction and restitution properties) of this collider.
pub fn material(&self) -> &ColliderMaterial {
&self.co_material
}
@@ -178,11 +178,11 @@ impl Collider {
self.co_shape.compute_aabb(&self.co_pos)
}
/// Compute the axis-aligned bounding box of this collider.
/// Compute the axis-aligned bounding box of this collider moving from its current position
/// to the given `next_position`
pub fn compute_swept_aabb(&self, next_position: &Isometry<Real>) -> AABB {
let aabb1 = self.co_shape.compute_aabb(&self.co_pos);
let aabb2 = self.co_shape.compute_aabb(next_position);
aabb1.merged(&aabb2)
self.co_shape
.compute_swept_aabb(&self.co_pos, next_position)
}
/// Compute the local-space mass properties of this collider.

View File

@@ -44,12 +44,18 @@ 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 {
const MODIFIED = 1 << 0;
const PARENT = 1 << 1; // => BF & NF updates.
const POSITION = 1 << 2; // => BF & NF updates.
const GROUPS = 1 << 3; // => NF update.
const SHAPE = 1 << 4; // => BF & NF update. NF pair workspace invalidation.
const TYPE = 1 << 5; // => NF update. NF pair invalidation.
/// 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.
}
}
@@ -60,12 +66,14 @@ impl Default for ColliderChanges {
}
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
}
@@ -73,12 +81,16 @@ impl ColliderChanges {
#[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
}
@@ -86,6 +98,7 @@ impl ColliderType {
#[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,
}
@@ -98,13 +111,19 @@ impl Default for ColliderBroadPhaseData {
}
}
/// 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 ColliderMassProperties {
/// `MassProperties` are computed with the help of [`SharedShape::mass_properties`].
/// 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>),
}
@@ -115,6 +134,12 @@ impl Default for ColliderMassProperties {
}
impl ColliderMassProperties {
/// 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),
@@ -125,13 +150,17 @@ impl ColliderMassProperties {
#[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 {
@@ -156,8 +185,9 @@ impl Default for ColliderPosition {
}
impl ColliderPosition {
/// The identity position.
#[must_use]
fn identity() -> Self {
pub fn identity() -> Self {
ColliderPosition(Isometry::identity())
}
}
@@ -173,8 +203,13 @@ where
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The groups of this collider, for filtering contact and solver pairs.
pub struct ColliderGroups {
/// 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,
}
@@ -189,15 +224,30 @@ impl Default for ColliderGroups {
#[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,
/// 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,
}
impl ColliderMaterial {
/// Creates a new collider material with the given friction and restitution coefficients.
pub fn new(friction: Real, restitution: Real) -> Self {
Self {
friction,

View File

@@ -197,7 +197,7 @@ impl ColliderSet {
///
/// Using this is discouraged in favor of `self.get(handle)` which does not
/// suffer form the ABA problem.
pub fn get_unknown_gen(&self, i: usize) -> Option<(&Collider, ColliderHandle)> {
pub fn get_unknown_gen(&self, i: u32) -> Option<(&Collider, ColliderHandle)> {
self.colliders
.get_unknown_gen(i)
.map(|(c, h)| (c, ColliderHandle(h)))
@@ -213,7 +213,7 @@ impl ColliderSet {
/// Using this is discouraged in favor of `self.get_mut(handle)` which does not
/// suffer form the ABA problem.
#[cfg(not(feature = "dev-remove-slow-accessors"))]
pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut Collider, ColliderHandle)> {
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Collider, ColliderHandle)> {
let (collider, handle) = self.colliders.get_unknown_gen_mut(i)?;
let handle = ColliderHandle(handle);
Self::mark_as_modified(handle, collider, &mut self.modified_colliders);

View File

@@ -9,7 +9,7 @@
//! are compliant with the IEEE 754-2008 floating point standard.
#![deny(bare_trait_objects)]
// #![warn(missing_docs)] // TODO: re-enable this
#![warn(missing_docs)]
#[cfg(all(feature = "dim2", feature = "f32"))]
pub extern crate parry2d as parry;

View File

@@ -271,7 +271,7 @@ impl PhysicsPipeline {
})
.unwrap();
bodies.map_mut_internal(handle.0, |forces: &mut RigidBodyForces| {
forces.add_linear_acceleration(&gravity, effective_inv_mass)
forces.add_gravity_acceleration(&gravity, effective_inv_mass)
});
}
self.counters.stages.update_time.pause();
@@ -442,6 +442,10 @@ impl PhysicsPipeline {
}
}
/// Executes one timestep of the physics simulation.
///
/// This is the same as `self.step_generic`, except that it is specialized
/// to work with `RigidBodySet` and `ColliderSet`.
#[cfg(feature = "default-sets")]
pub fn step(
&mut self,