aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data/coarena.rs8
-rw-r--r--src/dynamics/ccd/ccd_solver.rs97
-rw-r--r--src/dynamics/ccd/toi_entry.rs26
-rw-r--r--src/dynamics/integration_parameters.rs13
-rw-r--r--src/dynamics/island_manager.rs22
-rw-r--r--src/dynamics/joint/fixed_joint.rs10
-rw-r--r--src/dynamics/rigid_body.rs204
-rw-r--r--src/dynamics/rigid_body_components.rs64
-rw-r--r--src/dynamics/solver/island_solver.rs4
-rw-r--r--src/dynamics/solver/joint_constraint/ball_position_constraint.rs8
-rw-r--r--src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs6
-rw-r--r--src/dynamics/solver/joint_constraint/fixed_position_constraint.rs40
-rw-r--r--src/dynamics/solver/joint_constraint/fixed_velocity_constraint.rs12
-rw-r--r--src/dynamics/solver/joint_constraint/fixed_velocity_constraint_wide.rs24
-rw-r--r--src/dynamics/solver/joint_constraint/generic_position_constraint.rs6
-rw-r--r--src/dynamics/solver/joint_constraint/revolute_position_constraint.rs6
-rw-r--r--src/dynamics/solver/parallel_island_solver.rs2
-rw-r--r--src/geometry/broad_phase_multi_sap/broad_phase.rs4
-rw-r--r--src/geometry/collider.rs266
-rw-r--r--src/geometry/collider_components.rs171
-rw-r--r--src/geometry/collider_set.rs58
-rw-r--r--src/geometry/contact_pair.rs16
-rw-r--r--src/geometry/interaction_groups.rs54
-rw-r--r--src/geometry/narrow_phase.rs328
-rw-r--r--src/lib.rs9
-rw-r--r--src/pipeline/collision_pipeline.rs10
-rw-r--r--src/pipeline/event_handler.rs25
-rw-r--r--src/pipeline/mod.rs6
-rw-r--r--src/pipeline/physics_hooks.rs69
-rw-r--r--src/pipeline/physics_pipeline.rs56
-rw-r--r--src/pipeline/query_pipeline.rs42
-rw-r--r--src/pipeline/user_changes.rs3
32 files changed, 1111 insertions, 558 deletions
diff --git a/src/data/coarena.rs b/src/data/coarena.rs
index cd64910..ac6e43f 100644
--- a/src/data/coarena.rs
+++ b/src/data/coarena.rs
@@ -13,6 +13,14 @@ impl<T> Coarena<T> {
Self { data: Vec::new() }
}
+ /// Gets a specific element from the coarena without specifying its generation number.
+ ///
+ /// It is strongly encouraged to use `Coarena::get` instead of this method because this method
+ /// can suffer from the ABA problem.
+ pub fn get_unknown_gen(&self, index: u32) -> Option<&T> {
+ self.data.get(index as usize).map(|(_, t)| t)
+ }
+
/// Gets a specific element from the coarena, if it exists.
pub fn get(&self, index: Index) -> Option<&T> {
let (i, g) = index.into_raw_parts();
diff --git a/src/dynamics/ccd/ccd_solver.rs b/src/dynamics/ccd/ccd_solver.rs
index b348283..7e95f08 100644
--- a/src/dynamics/ccd/ccd_solver.rs
+++ b/src/dynamics/ccd/ccd_solver.rs
@@ -10,6 +10,7 @@ use crate::geometry::{
use crate::math::Real;
use crate::parry::utils::SortedPair;
use crate::pipeline::{EventHandler, QueryPipeline, QueryPipelineMode};
+use crate::prelude::{ActiveEvents, ColliderFlags};
use parry::query::{DefaultQueryDispatcher, QueryDispatcher};
use parry::utils::hashmap::HashMap;
use std::collections::BinaryHeap;
@@ -66,7 +67,7 @@ impl CCDSolver {
&RigidBodyCcd,
&RigidBodyMassProps,
) = bodies.index_bundle(handle.0);
- let local_com = &mprops.mass_properties.local_com;
+ let local_com = &mprops.local_mprops.local_com;
let min_toi = (ccd.ccd_thickness
* 0.15
@@ -139,7 +140,8 @@ impl CCDSolver {
Colliders: ComponentSetOption<ColliderParent>
+ ComponentSet<ColliderPosition>
+ ComponentSet<ColliderShape>
- + ComponentSet<ColliderType>,
+ + ComponentSet<ColliderType>
+ + ComponentSet<ColliderFlags>,
{
// Update the query pipeline.
self.query_pipeline.update_with_mode(
@@ -200,16 +202,21 @@ impl CCDSolver {
{
let co_parent1: Option<&ColliderParent> = colliders.get(ch1.0);
let co_parent2: Option<&ColliderParent> = colliders.get(ch2.0);
- let c1: (_, _, _) = colliders.index_bundle(ch1.0);
- let c2: (_, _, _) = colliders.index_bundle(ch2.0);
+ let c1: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch1.0);
+ let c2: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch2.0);
let co_type1: &ColliderType = colliders.index(ch1.0);
let co_type2: &ColliderType = colliders.index(ch1.0);
let bh1 = co_parent1.map(|p| p.handle);
let bh2 = co_parent2.map(|p| p.handle);
- if bh1 == bh2 || (co_type1.is_sensor() || co_type2.is_sensor()) {
- // Ignore self-intersection and sensors.
+ // Ignore self-intersection and sensors and apply collision groups filter.
+ if bh1 == bh2 // Ignore self-intersection.
+ || (co_type1.is_sensor() || co_type2.is_sensor()) // Ignore sensors.
+ || !c1.3.collision_groups.test(c2.3.collision_groups) // Apply collision groups.
+ || !c1.3.solver_groups.test(c2.3.solver_groups)
+ // Apply solver groups.
+ {
return true;
}
@@ -225,8 +232,8 @@ impl CCDSolver {
self.query_pipeline.query_dispatcher(),
*ch1,
*ch2,
- (c1.0, c1.1, c1.2, co_parent1),
- (c2.0, c2.1, c2.2, co_parent2),
+ (c1.0, c1.1, c1.2, c1.3, co_parent1),
+ (c2.0, c2.1, c2.2, c2.3, co_parent2),
Some((rb_pos1, rb_vels1, rb_mprops1, rb_ccd1)),
b2,
None,
@@ -272,7 +279,9 @@ impl CCDSolver {
Colliders: ComponentSetOption<ColliderParent>
+ ComponentSet<ColliderPosition>
+ ComponentSet<ColliderShape>
- + ComponentSet<ColliderType>,
+ + ComponentSet<ColliderType>
+ + ComponentSet<ColliderFlags>
+ + ComponentSet<ColliderFlags>,
{
let mut frozen = HashMap::<_, Real>::default();
let mut all_toi = BinaryHeap::new();
@@ -334,14 +343,15 @@ impl CCDSolver {
{
let co_parent1: Option<&ColliderParent> = colliders.get(ch1.0);
let co_parent2: Option<&ColliderParent> = colliders.get(ch2.0);
- let c1: (_, _, _) = colliders.index_bundle(ch1.0);
- let c2: (_, _, _) = colliders.index_bundle(ch2.0);
+ let c1: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch1.0);
+ let c2: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch2.0);
let bh1 = co_parent1.map(|p| p.handle);
let bh2 = co_parent2.map(|p| p.handle);
- if bh1 == bh2 {
- // Ignore self-intersection.
+ // Ignore self-intersections and apply groups filter.
+ if bh1 == bh2 || !c1.3.collision_groups.test(c2.3.collision_groups)
+ {
return true;
}
@@ -358,8 +368,8 @@ impl CCDSolver {
self.query_pipeline.query_dispatcher(),
*ch1,
*ch2,
- (c1.0, c1.1, c1.2, co_parent1),
- (c2.0, c2.1, c2.2, co_parent2),
+ (c1.0, c1.1, c1.2, c1.3, co_parent1),
+ (c2.0, c2.1, c2.2, c2.3, co_parent2),
b1,
b2,
None,
@@ -398,7 +408,7 @@ impl CCDSolver {
// NOTE: all static bodies (and kinematic bodies?) should be considered as "frozen", this
// may avoid some resweeps.
- let mut intersections_to_check = vec![];
+ let mut pseudo_intersections_to_check = vec![];
while let Some(toi) = all_toi.pop() {
assert!(toi.toi <= dt);
@@ -420,7 +430,7 @@ impl CCDSolver {
continue;
}
- if toi.is_intersection_test {
+ if toi.is_pseudo_intersection_test {
// NOTE: this test is redundant with the previous `if !should_freeze && ...`
// but let's keep it to avoid tricky regressions if we end up swapping both
// `if` for some reasons in the future.
@@ -428,7 +438,7 @@ impl CCDSolver {
// This is only an intersection so we don't have to freeze and there is no
// need to resweep. However we will need to see if we have to generate
// intersection events, so push the TOI for further testing.
- intersections_to_check.push(toi);
+ pseudo_intersections_to_check.push(toi);
}
continue;
}
@@ -460,14 +470,14 @@ impl CCDSolver {
.colliders_with_aabb_intersecting_aabb(&aabb, |ch2| {
let co_parent1: Option<&ColliderParent> = colliders.get(ch1.0);
let co_parent2: Option<&ColliderParent> = colliders.get(ch2.0);
- let c1: (_, _, _) = colliders.index_bundle(ch1.0);
- let c2: (_, _, _) = colliders.index_bundle(ch2.0);
+ let c1: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch1.0);
+ let c2: (_, _, _, &ColliderFlags) = colliders.index_bundle(ch2.0);
let bh1 = co_parent1.map(|p| p.handle);
let bh2 = co_parent2.map(|p| p.handle);
- if bh1 == bh2 {
- // Ignore self-intersection.
+ // Ignore self-intersection and apply groups filter.
+ if bh1 == bh2 || !c1.3.collision_groups.test(c2.3.collision_groups) {
return true;
}
@@ -496,8 +506,8 @@ impl CCDSolver {
self.query_pipeline.query_dispatcher(),
*ch1,
*ch2,
- (c1.0, c1.1, c1.2, co_parent1),
- (c2.0, c2.1, c2.2, co_parent2),
+ (c1.0, c1.1, c1.2, c1.3, co_parent1),
+ (c2.0, c2.1, c2.2, c2.3, co_parent2),
b1,
b2,
frozen1.copied(),
@@ -514,7 +524,7 @@ impl CCDSolver {
}
}
- for toi in intersections_to_check {
+ for toi in pseudo_intersections_to_check {
// See if the intersection is still active once the bodies
// reach their final positions.
// - If the intersection is still active, don't report it yet. It will be
@@ -522,10 +532,29 @@ impl CCDSolver {
// - If the intersection isn't active anymore, and it wasn't intersecting
// before, then we need to generate one interaction-start and one interaction-stop
// events because it will never be detected by the narrow-phase because of tunneling.
- let (co_pos1, co_shape1): (&ColliderPosition, &ColliderShape) =
- colliders.index_bundle(toi.c1.0);
- let (co_pos2, co_shape2): (&ColliderPosition, &ColliderShape) =
- colliders.index_bundle(toi.c2.0);
+ let (co_type1, co_pos1, co_shape1, co_flags1): (
+ &ColliderType,
+ &ColliderPosition,
+ &ColliderShape,
+ &ColliderFlags,
+ ) = colliders.index_bundle(toi.c1.0);
+ let (co_type2, co_pos2, co_shape2, co_flags2): (
+ &ColliderType,
+ &ColliderPosition,
+ &ColliderShape,
+ &ColliderFlags,
+ ) = colliders.index_bundle(toi.c2.0);
+
+ if !co_type1.is_sensor() && !co_type2.is_sensor() {
+ // TODO: this happens if we found a TOI between two non-sensor
+ // colliders with mismatching solver_flags. It is not clear
+ // what we should do in this case: we could report a
+ // contact started/contact stopped event for example. But in
+ // that case, what contact pair should be pass to these events?
+ // For now we just ignore this special case. Let's wait for an actual
+ // use-case to come up before we determine what we want to do here.
+ continue;
+ }
let co_next_pos1 = if let Some(b1) = toi.b1 {
let co_parent1: &ColliderParent = colliders.get(toi.c1.0).unwrap();
@@ -535,7 +564,7 @@ impl CCDSolver {
&RigidBodyMassProps,
) = bodies.index_bundle(b1.0);
- let local_com1 = &rb_mprops1.mass_properties.local_com;
+ let local_com1 = &rb_mprops1.local_mprops.local_com;
let frozen1 = frozen.get(&b1);
let pos1 = frozen1
.map(|t| rb_vels1.integrate(*t, &rb_pos1.position, local_com1))
@@ -553,7 +582,7 @@ impl CCDSolver {
&RigidBodyMassProps,
) = bodies.index_bundle(b2.0);
- let local_com2 = &rb_mprops2.mass_properties.local_com;
+ let local_com2 = &rb_mprops2.local_mprops.local_com;
let frozen2 = frozen.get(&b2);
let pos2 = frozen2
.map(|t| rb_vels2.integrate(*t, &rb_pos2.position, local_com2))
@@ -575,7 +604,11 @@ impl CCDSolver {
.intersection_test(&next_coll_pos12, co_shape1.as_ref(), co_shape2.as_ref())
.unwrap_or(false);
- if !intersect_before && !intersect_after {
+ if !intersect_before
+ && !intersect_after
+ && (co_flags1.active_events | co_flags2.active_events)
+ .contains(ActiveEvents::INTERSECTION_EVENTS)
+ {
// Emit one intersection-started and one intersection-stopped event.
events.handle_intersection_event(IntersectionEvent::new(toi.c1, toi.c2, true));
events.handle_intersection_event(IntersectionEvent::new(toi.c1, toi.c2, false));
diff --git a/src/dynamics/ccd/toi_entry.rs b/src/dynamics/ccd/toi_entry.rs
index 4637940..f937979 100644
--- a/src/dynamics/ccd/toi_entry.rs
+++ b/src/dynamics/ccd/toi_entry.rs
@@ -2,7 +2,7 @@ use crate::dynamics::{
RigidBodyCcd, RigidBodyHandle, RigidBodyMassProps, RigidBodyPosition, RigidBodyVelocity,
};
use crate::geometry::{
- ColliderHandle, ColliderParent, ColliderPosition, ColliderShape, ColliderType,
+ ColliderFlags, ColliderHandle, ColliderParent, ColliderPosition, ColliderShape, ColliderType,
};
use crate::math::Real;
use parry::query::{NonlinearRigidMotion, QueryDispatcher};
@@ -14,7 +14,9 @@ pub struct TOIEntry {
pub b1: Option<RigidBodyHandle>,
pub c2: ColliderHandle,
pub b2: Option<RigidBodyHandle>,
- pub is_intersection_test: bool,
+ // We call this "pseudo" intersection because this also
+ // includes colliders pairs with mismatching solver_groups.
+ pub is_pseudo_intersection_test: bool,
pub timestamp: usize,
}
@@ -25,7 +27,7 @@ impl TOIEntry {
b1: Option<RigidBodyHandle>,
c2: ColliderHandle,
b2: Option<RigidBodyHandle>,
- is_intersection_test: bool,
+ is_pseudo_intersection_test: bool,
timestamp: usize,
) -> Self {
Self {
@@ -34,7 +36,7 @@ impl TOIEntry {
b1,
c2,
b2,
- is_intersection_test,
+ is_pseudo_intersection_test,
timestamp,
}
}
@@ -47,12 +49,14 @@ impl TOIEntry {
&ColliderType,
&ColliderShape,
&ColliderPosition,
+ &ColliderFlags,
Option<&ColliderParent>,
),
c2: (
&ColliderType,
&ColliderShape,
&ColliderPosition,
+ &ColliderFlags,
Option<&ColliderParent>,
),
b1: Option<(
@@ -78,8 +82,8 @@ impl TOIEntry {
return None;
}
- let (co_type1, co_shape1, co_pos1, co_parent1) = c1;
- let (co_type2, co_shape2, co_pos2, co_parent2) = c2;
+ let (co_type1, co_shape1, co_pos1, co_flags1, co_parent1) = c1;
+ let (co_type2, co_shape2, co_pos2, co_flags2, co_parent2) = c2;
let linvel1 =
frozen1.is_none() as u32 as Real * b1.map(|b| b.1.linvel).unwrap_or(na::zero());
@@ -104,7 +108,9 @@ impl TOIEntry {
// keep it since more conservatism is good at this stage.
let thickness = (co_shape1.0.ccd_thickness() + co_shape2.0.ccd_thickness())
+ smallest_contact_dist.max(0.0);
- let is_intersection_test = co_type1.is_sensor() || co_type2.is_sensor();
+ let is_pseudo_intersection_test = co_type1.is_sensor()
+ || co_type2.is_sensor()
+ || !co_flags1.solver_groups.test(co_flags2.solver_groups);
if (end_time - start_time) * vel12 < thickness {
return None;
@@ -135,7 +141,7 @@ impl TOIEntry {
// If the TOI search involves two non-sensor colliders then
// we don't want to stop the TOI search at the first penetration
// because the colliders may be in a separating trajectory.
- let stop_at_penetration = is_intersection_test;
+ let stop_at_penetration = is_pseudo_intersection_test;
let res_toi = query_dispatcher
.nonlinear_time_of_impact(
@@ -157,7 +163,7 @@ impl TOIEntry {
co_parent1.map(|p| p.handle),
ch2,
co_parent2.map(|p| p.handle),
- is_intersection_test,
+ is_pseudo_intersection_test,
0,
))
}
@@ -173,7 +179,7 @@ impl TOIEntry {
if ccd.ccd_active {
NonlinearRigidMotion::new(
poss.position,
- mprops.mass_properties.local_com,
+ mprops.local_mprops.local_com,
vels.linvel,
vels.angvel,
)
diff --git a/src/dynamics/integration_parameters.rs b/src/dynamics/integration_parameters.rs
index e039bfc..4725319 100644
--- a/src/dynamics/integration_parameters.rs
+++ b/src/dynamics/integration_parameters.rs
@@ -10,7 +10,7 @@ pub struct IntegrationParameters {
///
/// When CCD with multiple substeps is enabled, the timestep is subdivided
/// into smaller pieces. This timestep subdivision won't generate timestep
- /// lengths smaller than `min_dt`.
+ /// lengths smaller than `min_ccd_dt`.
///
/// Setting this to a large value will reduce the opportunity to performing
/// CCD substepping, resulting in potentially more time dropped by the
@@ -18,17 +18,6 @@ pub struct IntegrationParameters {
/// to numerical instabilities.
pub min_ccd_dt: Real,
- // /// If `true` and if rapier is compiled with the `parallel` feature, this will enable rayon-based multithreading (default: `true`).
- // ///
- // /// This parameter is ignored if rapier is not compiled with is `parallel` feature.
- // /// Refer to rayon's documentation regarding how to configure the number of threads with either
- // /// `rayon::ThreadPoolBuilder::new().num_threads(4).build_global().unwrap()` or `ThreadPool::install`.
- // /// Note that using only one thread with `multithreading_enabled` set to `true` will result on a slower
- // /// simulation than setting `multithreading_enabled` to `false`.
- // pub multithreading_enabled: bool,
- // /// If `true`, the world's `step` method will stop right after resolving exactly one CCD event (default: `false`).
- // /// This allows the user to take action during a timestep, in-between two CCD events.
- // pub return_after_ccd_substep: bool,
/// The Error Reduction Parameter in `[0, 1]` is the proportion of
/// the positional error to be corrected at each time step (default: `0.2`).
pub erp: Real,
diff --git a/src/dynamics/island_manager.rs b/src/dynamics/island_manager.rs
index b79cdb2..34fa3bd 100644
--- a/src/dynamics/island_manager.rs
+++ b/src/dynamics/island_manager.rs
@@ -229,19 +229,17 @@ impl IslandManager {
stack: &mut Vec<RigidBodyHandle>,
) {
for collider_handle in &rb_colliders.0 {
- if let Some(contacts) = narrow_phase.contacts_with(*collider_handle) {
- for inter in contacts {
- for manifold in &inter.2.manifolds {
- if !manifold.data.solver_contacts.is_empty() {
- let other = crate::utils::select_other(
- (inter.0, inter.1),
- *collider_handle,
- );
- if let Some(other_body) = colliders.get(other.0) {
- stack.push(other_body.handle);
- }
- break;
+ for inter in narrow_phase.contacts_with(*collider_handle) {
+ for manifold in &inter.manifolds {
+ if !manifold.data.solver_contacts.is_empty() {
+ let other = crate::utils::select_other(
+ (inter.collider1, inter.collider2),
+ *collider_handle,
+ );
+ if let Some(other_body) = colliders.get(other.0) {
+ stack.push(other_body.handle);
}
+ break;
}
}
}
diff --git a/src/dynamics/joint/fixed_joint.rs b/src/dynamics/joint/fixed_joint.rs
index 2917757..3f87e8d 100644
--- a/src/dynamics/joint/fixed_joint.rs
+++ b/src/dynamics/joint/fixed_joint.rs
@@ -8,10 +8,10 @@ use crate::math::{Isometry, Real, SpacialVector};
pub struct FixedJoint {
/// The frame of reference for the first body affected by this joint, expressed in the local frame
/// of the first body.
- pub local_anchor1: Isometry<Real>,
+ pub local_frame1: Isometry<Real>,
/// The frame of reference for the second body affected by this joint, expressed in the local frame
/// of the first body.
- pub local_anchor2: Isometry<Real>,
+ pub local_frame2: Isometry<Real>,
/// The impulse applied to the first body affected by this joint.
///
/// The impulse applied to the second body affected by this joint is given by `-impulse`.
@@ -23,10 +23,10 @@ pub struct FixedJoint {
impl FixedJoint {
/// Creates a new fixed joint from the frames of reference of both bodies.
- pub fn new(local_anchor1: Isometry<Real>, local_anchor2: Isometry<Real>) -> Self {
+ pub fn new(local_frame1: Isometry<Real>, local_frame2: Isometry<Real>) -> Self {
Self {
- local_anchor1,
- local_anchor2,
+ local_frame1,
+ local_frame2,
impulse: SpacialVector::zeros(),
}
}
diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs
index 824ec92..63c2221 100644
--- a/src/dynamics/rigid_body.rs
+++ b/src/dynamics/rigid_body.rs
@@ -4,8 +4,7 @@ use crate::dynamics::{
RigidBodyMassPropsFlags, RigidBodyPosition, RigidBodyType, RigidBodyVelocity,
};
use crate::geometry::{
- Collider, ColliderHandle, ColliderMassProperties, ColliderParent, ColliderPosition,
- ColliderShape,
+ Collider, ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition, ColliderShape,
};
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector};
use crate::utils::{self, WCross};
@@ -48,7 +47,7 @@ impl RigidBody {
rb_ccd: RigidBodyCcd::default(),
rb_ids: RigidBodyIds::default(),
rb_colliders: RigidBodyColliders::default(),
- rb_activation: RigidBodyActivation::new_active(),
+ rb_activation: RigidBodyActivation::active(),
changes: RigidBodyChanges::all(),
rb_type: RigidBodyType::Dynamic,
rb_dominance: RigidBodyDominance::default(),
@@ -112,7 +111,7 @@ impl RigidBody {
/// The mass properties of this rigid-body.
#[inline]
pub fn mass_properties(&self) -> &MassProperties {
- &self.rb_mprops.mass_properties
+ &self.rb_mprops.local_mprops
}
/// The dominance group of this rigid-body.
@@ -124,6 +123,72 @@ impl RigidBody {
self.rb_dominance.effective_group(&self.rb_type)
}
+ #[inline]
+ /// Locks or unlocks all the rotations of this rigid-body.
+ pub fn lock_rotations(&mut self, locked: bool, wake_up: bool) {
+ if self.is_dynamic() {
+ if wake_up {
+ self.wake_up(true);
+ }
+
+ self.rb_mprops
+ .flags
+ .set(RigidBodyMassPropsFlags::ROTATION_LOCKED_X, locked);
+ self.rb_mprops
+ .flags
+ .set(RigidBodyMassPropsFlags::ROTATION_LOCKED_Y, locked);
+ self.rb_mprops
+ .flags
+ .set(RigidBodyMassPropsFlags::ROTATION_LOCKED_Z, locked);
+ self.update_world_mass_properties();
+ }
+ }
+
+ #[inline]
+ /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
+ pub fn restrict_rotations(
+ &mut self,
+ allow_rotations_x: bool,
+ allow_rotations_y: bool,
+ allow_rotations_z: bool,
+ wake_up: bool,
+ ) {
+ if self.is_dynamic() {
+ if wake_up {
+ self.wake_up(true);
+ }
+
+ self.rb_mprops.flags.set(
+ RigidBodyMassPropsFlags::ROTATION_LOCKED_X,
+ allow_rotations_x,
+ );
+ self.rb_mprops.flags.set(
+ RigidBodyMassPropsFlags::ROTATION_LOCKED_Y,
+ allow_rotations_y,
+ );
+ self.rb_mprops.flags.set(
+ RigidBodyMassPropsFlags::ROTATION_LOCKED_Z,
+ allow_rotations_z,
+ );
+ self.update_world_mass_properties();
+ }
+ }
+
+ #[inline]
+ /// Locks or unlocks all the rotations of this rigid-body.
+ pub fn lock_translations(&mut self, locked: bool, wake_up: bool) {
+ if self.is_dynamic() {
+ if wake_up {
+ self.wake_up(true);
+ }
+
+ self.rb_mprops
+ .flags
+ .set(RigidBodyMassPropsFlags::TRANSLATION_LOCKED, locked);
+ self.update_world_mass_properties();
+ }
+ }
+
/// Are the translations of this rigid-body locked?
pub fn is_translation_locked(&self) -> bool {
self.rb_mprops
@@ -190,7 +255,7 @@ impl RigidBody {
self.wake_up(true);
}
- self.rb_mprops.mass_properties = props;
+ self.rb_mprops.local_mprops = props;
self.update_world_mass_properties();
}
@@ -210,7 +275,7 @@ impl RigidBody {
///
/// A kinematic body can move freely but is not affected by forces.
pub fn is_kinematic(&self) -> bool {
- self.rb_type == RigidBodyType::Kinematic
+ self.rb_type.is_kinematic()
}
/// Is this rigid body static?
@@ -224,7 +289,7 @@ impl RigidBody {
///
/// Returns zero if this rigid body has an infinite mass.
pub fn mass(&self) -> Real {
- utils::inv(self.rb_mprops.mass_properties.inv_mass)
+ utils::inv(self.rb_mprops.local_mprops.inv_mass)
}
/// The predicted position of this rigid-body.
@@ -251,6 +316,16 @@ impl RigidBody {
self.rb_forces.gravity_scale = scale;
}
+ /// The dominance group of this rigid-body.
+ pub fn dominance_group(&self) -> i8 {
+ self.rb_dominance.0
+ }
+
+ /// The dominance group of this rigid-body.
+ pub fn set_dominance_group(&mut self, dominance: i8) {
+ self.rb_dominance.0 = dominance
+ }
+
/// Adds a collider to this rigid-body.
// TODO ECS: we keep this public for now just to simply our experiments on bevy_rapier.
pub fn add_collider(
@@ -259,7 +334,7 @@ impl RigidBody {
co_parent: &ColliderParent,
co_pos: &mut ColliderPosition,
co_shape: &ColliderShape,
- co_mprops: &ColliderMassProperties,
+ co_mprops: &ColliderMassProps,
) {
self.rb_colliders.attach_collider(
&mut self.changes,
@@ -279,10 +354,11 @@ impl RigidBody {
if let Some(i) = self.rb_colliders.0.iter().position(|e| *e == handle) {
self.changes.set(RigidBodyChanges::COLLIDERS, true);
self.rb_colliders.0.swap_remove(i);
+
let mass_properties = coll
.mass_properties()
- .transform_by(coll.position_wrt_parent());
- self.rb_mprops.mass_properties -= mass_properties;
+ .transform_by(coll.position_wrt_parent().unwrap());
+ self.rb_mprops.local_mprops -= mass_properties;
self.update_world_mass_properties();
}
}
@@ -384,6 +460,45 @@ impl RigidBody {
&self.rb_pos.position
}
+ /// The translational part of this rigid-body's position.
+ #[inline]
+ pub fn translation(&self) -> &Vector<Real> {
+ &self.rb_pos.position.translation.vector
+ }
+
+ /// Sets the translational part of this rigid-body's position.
+ #[inline]
+ pub fn set_translation(&mut self, translation: Vector<Real>, wake_up: bool) {
+ self.changes.insert(RigidBodyChanges::POSITION);
+ self.rb_pos.position.translation.vector = translation;
+ self.rb_pos.next_position.translation.vector = translation;
+
+ // TODO: Do we really need to check that the body isn't dynamic?
+ if wake_up && self.is_dynamic() {
+ self.wake_up(true)
+ }
+ }
+
+ /// The translational part of this rigid-body's position.
+ #[inline]
+ pub fn rotation(&self) -> &Rotation<Real> {
+ &self.rb_pos.position.rotation