aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2020-09-01 18:21:11 +0200
committerGitHub <noreply@github.com>2020-09-01 18:21:11 +0200
commitfef3a367d143bddde94e4f919a341cbf8d205293 (patch)
treec66a9aa0f8a4a0b6c54f069e291fa2f12cc16ea3 /src
parentcc05bad0410128b163e81e9f703ccb841f6a9a08 (diff)
parent763b9092422fd5677ffd47ec1b081951dc1c63e4 (diff)
downloadrapier-fef3a367d143bddde94e4f919a341cbf8d205293.tar.gz
rapier-fef3a367d143bddde94e4f919a341cbf8d205293.tar.bz2
rapier-fef3a367d143bddde94e4f919a341cbf8d205293.zip
Merge pull request #6 from dimforge/collider_removal
Add collider removal + fix rigid-bodies with multiple colliders
Diffstat (limited to 'src')
-rw-r--r--src/dynamics/mass_properties.rs190
-rw-r--r--src/dynamics/rigid_body.rs26
-rw-r--r--src/dynamics/solver/position_constraint.rs4
-rw-r--r--src/dynamics/solver/position_constraint_wide.rs7
-rw-r--r--src/dynamics/solver/position_ground_constraint.rs28
-rw-r--r--src/dynamics/solver/position_ground_constraint_wide.rs16
-rw-r--r--src/dynamics/solver/velocity_constraint.rs12
-rw-r--r--src/dynamics/solver/velocity_constraint_wide.rs24
-rw-r--r--src/dynamics/solver/velocity_ground_constraint.rs32
-rw-r--r--src/dynamics/solver/velocity_ground_constraint_wide.rs27
-rw-r--r--src/geometry/broad_phase_multi_sap.rs4
-rw-r--r--src/geometry/collider.rs42
-rw-r--r--src/geometry/collider_set.rs6
-rw-r--r--src/geometry/contact.rs24
-rw-r--r--src/geometry/contact_generator/ball_polygon_contact_generator.rs1
-rw-r--r--src/geometry/contact_generator/cuboid_polygon_contact_generator.rs1
-rw-r--r--src/geometry/narrow_phase.rs7
-rw-r--r--src/geometry/proximity_detector/ball_polygon_proximity_detector.rs1
-rw-r--r--src/geometry/proximity_detector/cuboid_polygon_proximity_detector.rs1
-rw-r--r--src/pipeline/physics_pipeline.rs24
20 files changed, 405 insertions, 72 deletions
diff --git a/src/dynamics/mass_properties.rs b/src/dynamics/mass_properties.rs
index cc2979c..22e7da5 100644
--- a/src/dynamics/mass_properties.rs
+++ b/src/dynamics/mass_properties.rs
@@ -1,7 +1,7 @@
use crate::math::{AngVector, AngularInertia, Isometry, Point, Rotation, Vector};
use crate::utils;
use num::Zero;
-use std::ops::{Add, AddAssign};
+use std::ops::{Add, AddAssign, Sub, SubAssign};
#[cfg(feature = "dim3")]
use {na::Matrix3, std::ops::MulAssign};
@@ -91,6 +91,18 @@ impl MassProperties {
}
#[cfg(feature = "dim3")]
+ /// Reconstructs the inverse angular inertia tensor of the rigid body from its principal inertia values and axii.
+ pub fn reconstruct_inverse_inertia_matrix(&self) -> Matrix3<f32> {
+ let inv_principal_inertia = self.inv_principal_inertia_sqrt.map(|e| e * e);
+ self.principal_inertia_local_frame.to_rotation_matrix()
+ * Matrix3::from_diagonal(&inv_principal_inertia)
+ * self
+ .principal_inertia_local_frame
+ .inverse()
+ .to_rotation_matrix()
+ }
+
+ #[cfg(feature = "dim3")]
/// Reconstructs the angular inertia tensor of the rigid body from its principal inertia values and axii.
pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> {
let principal_inertia = self.inv_principal_inertia_sqrt.map(|e| utils::inv(e * e));
@@ -125,6 +137,19 @@ impl MassProperties {
Matrix3::zeros()
}
}
+
+ /// Transform each element of the mass properties.
+ pub fn transform_by(&self, m: &Isometry<f32>) -> Self {
+ // NOTE: we don't apply the parallel axis theorem here
+ // because the center of mass is also transformed.
+ Self {
+ local_com: m * self.local_com,
+ inv_mass: self.inv_mass,
+ inv_principal_inertia_sqrt: self.inv_principal_inertia_sqrt,
+ #[cfg(feature = "dim3")]
+ principal_inertia_local_frame: m.rotation * self.principal_inertia_local_frame,
+ }
+ }
}
impl Zero for MassProperties {
@@ -143,6 +168,68 @@ impl Zero for MassProperties {
}
}
+impl Sub<MassProperties> for MassProperties {
+ type Output = Self;
+
+ #[cfg(feature = "dim2")]
+ fn sub(self, other: MassProperties) -> Self {
+ if self.is_zero() || other.is_zero() {
+ return self;
+ }
+
+ let m1 = utils::inv(self.inv_mass);
+ let m2 = utils::inv(other.inv_mass);
+ let inv_mass = utils::inv(m1 - m2);
+
+ let local_com = (self.local_com * m1 - other.local_com.coords * m2) * inv_mass;
+ let i1 = self.construct_shifted_inertia_matrix(local_com - self.local_com);
+ let i2 = other.construct_shifted_inertia_matrix(local_com - other.local_com);
+ let inertia = i1 - i2;
+ // NOTE: we drop the negative eigenvalues that may result from subtraction rounding errors.
+ let inv_principal_inertia_sqrt = utils::inv(inertia.max(0.0).sqrt());
+
+ Self {
+ local_com,
+ inv_mass,
+ inv_principal_inertia_sqrt,
+ }
+ }
+
+ #[cfg(feature = "dim3")]
+ fn sub(self, other: MassProperties) -> Self {
+ if self.is_zero() || other.is_zero() {
+ return self;
+ }
+
+ let m1 = utils::inv(self.inv_mass);
+ let m2 = utils::inv(other.inv_mass);
+ let inv_mass = utils::inv(m1 - m2);
+ let local_com = (self.local_com * m1 - other.local_com.coords * m2) * inv_mass;
+ let i1 = self.construct_shifted_inertia_matrix(local_com - self.local_com);
+ let i2 = other.construct_shifted_inertia_matrix(local_com - other.local_com);
+ let inertia = i1 - i2;
+ let eigen = inertia.symmetric_eigen();
+ let principal_inertia_local_frame =
+ Rotation::from_matrix_eps(&eigen.eigenvectors, 1.0e-6, 10, na::one());
+ let principal_inertia = eigen.eigenvalues;
+ // NOTE: we drop the negative eigenvalues that may result from subtraction rounding errors.
+ let inv_principal_inertia_sqrt = principal_inertia.map(|e| utils::inv(e.max(0.0).sqrt()));
+
+ Self {
+ local_com,
+ inv_mass,
+ inv_principal_inertia_sqrt,
+ principal_inertia_local_frame,
+ }
+ }
+}
+
+impl SubAssign<MassProperties> for MassProperties {
+ fn sub_assign(&mut self, rhs: MassProperties) {
+ *self = *self - rhs
+ }
+}
+
impl Add<MassProperties> for MassProperties {
type Output = Self;
@@ -186,7 +273,8 @@ impl Add<MassProperties> for MassProperties {
let i2 = other.construct_shifted_inertia_matrix(local_com - other.local_com);
let inertia = i1 + i2;
let eigen = inertia.symmetric_eigen();
- let principal_inertia_local_frame = Rotation::from_matrix(&eigen.eigenvectors);
+ let principal_inertia_local_frame =
+ Rotation::from_matrix_eps(&eigen.eigenvectors, 1.0e-6, 10, na::one());
let principal_inertia = eigen.eigenvalues;
let inv_principal_inertia_sqrt = principal_inertia.map(|e| utils::inv(e.sqrt()));
@@ -204,3 +292,101 @@ impl AddAssign<MassProperties> for MassProperties {
*self = *self + rhs
}
}
+
+impl approx::AbsDiffEq for MassProperties {
+ type Epsilon = f32;
+ fn default_epsilon() -> Self::Epsilon {
+ f32::default_epsilon()
+ }
+
+ fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
+ #[cfg(feature = "dim2")]
+ let inertia_is_ok = self
+ .inv_principal_inertia_sqrt
+ .abs_diff_eq(&other.inv_principal_inertia_sqrt, epsilon);
+
+ #[cfg(feature = "dim3")]
+ let inertia_is_ok = self
+ .reconstruct_inverse_inertia_matrix()
+ .abs_diff_eq(&other.reconstruct_inverse_inertia_matrix(), epsilon);
+
+ inertia_is_ok
+ && self.local_com.abs_diff_eq(&other.local_com, epsilon)
+ && self.inv_mass.abs_diff_eq(&other.inv_mass, epsilon)
+ && self
+ .inv_principal_inertia_sqrt
+ .abs_diff_eq(&other.inv_principal_inertia_sqrt, epsilon)
+ }
+}
+
+impl approx::RelativeEq for MassProperties {
+ fn default_max_relative() -> Self::Epsilon {
+ f32::default_max_relative()
+ }
+
+ fn relative_eq(
+ &self,
+ other: &Self,
+ epsilon: Self::Epsilon,
+ max_relative: Self::Epsilon,
+ ) -> bool {
+ #[cfg(feature = "dim2")]
+ let inertia_is_ok = self.inv_principal_inertia_sqrt.relative_eq(
+ &other.inv_principal_inertia_sqrt,
+ epsilon,
+ max_relative,
+ );
+
+ #[cfg(feature = "dim3")]
+ let inertia_is_ok = self.reconstruct_inverse_inertia_matrix().relative_eq(
+ &other.reconstruct_inverse_inertia_matrix(),
+ epsilon,
+ max_relative,
+ );
+
+ inertia_is_ok
+ && self
+ .local_com
+ .relative_eq(&other.local_com, epsilon, max_relative)
+ && self
+ .inv_mass
+ .relative_eq(&other.inv_mass, epsilon, max_relative)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::MassProperties;
+ use crate::geometry::ColliderBuilder;
+ use approx::assert_relative_eq;
+ use num::Zero;
+
+ #[test]
+ fn mass_properties_add_sub() {
+ // Check that addition and subtraction of mass properties behave as expected.
+ let c1 = ColliderBuilder::capsule_x(1.0, 2.0).build();
+ let c2 = ColliderBuilder::capsule_y(3.0, 4.0).build();
+ let c3 = ColliderBuilder::ball(5.0).build();
+
+ let m1 = c1.mass_properties();
+ let m2 = c2.mass_properties();
+ let m3 = c3.mass_properties();
+ let m1m2m3 = m1 + m2 + m3;
+
+ assert_relative_eq!(m1 + m2, m2 + m1, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m1, m2 + m3, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m2, m1 + m3, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m3, m1 + m2, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - (m1 + m2), m3, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - (m1 + m3), m2, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - (m2 + m3), m1, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m1 - m2, m3, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m1 - m3, m2, epsilon = 1.0e-6);
+ assert_relative_eq!(m1m2m3 - m2 - m3, m1, epsilon = 1.0e-6);
+ assert_relative_eq!(
+ m1m2m3 - m1 - m2 - m3,
+ MassProperties::zero(),
+ epsilon = 1.0e-6
+ );
+ }
+}
diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs
index 584dc96..a2fcacc 100644
--- a/src/dynamics/rigid_body.rs
+++ b/src/dynamics/rigid_body.rs
@@ -1,5 +1,5 @@
use crate::dynamics::MassProperties;
-use crate::geometry::{ColliderHandle, InteractionGraph, RigidBodyGraphIndex};
+use crate::geometry::{Collider, ColliderHandle, InteractionGraph, RigidBodyGraphIndex};
use crate::math::{AngVector, AngularInertia, Isometry, Point, Rotation, Translation, Vector};
use crate::utils::{WCross, WDot};
use num::Zero;
@@ -137,6 +137,28 @@ impl RigidBody {
crate::utils::inv(self.mass_properties.inv_mass)
}
+ /// Adds a collider to this rigid-body.
+ pub(crate) fn add_collider_internal(&mut self, handle: ColliderHandle, coll: &Collider) {
+ let mass_properties = coll
+ .mass_properties()
+ .transform_by(coll.position_wrt_parent());
+ self.colliders.push(handle);
+ self.mass_properties += mass_properties;
+ self.update_world_mass_properties();
+ }
+
+ /// Removes a collider from this rigid-body.
+ pub(crate) fn remove_collider_internal(&mut self, handle: ColliderHandle, coll: &Collider) {
+ if let Some(i) = self.colliders.iter().position(|e| *e == handle) {
+ self.colliders.swap_remove(i);
+ let mass_properties = coll
+ .mass_properties()
+ .transform_by(coll.position_wrt_parent());
+ self.mass_properties -= mass_properties;
+ self.update_world_mass_properties();
+ }
+ }
+
/// Put this rigid body to sleep.
///
/// A sleeping body no longer moves and is no longer simulated by the physics engine unless
@@ -171,7 +193,7 @@ impl RigidBody {
}
fn integrate_velocity(&self, dt: f32) -> Isometry<f32> {
- let com = &self.position * self.mass_properties.local_com; // FIXME: use non-origin center of masses.
+ let com = &self.position * self.mass_properties.local_com;
let shift = Translation::from(com.coords);
shift * Isometry::new(self.linvel * dt, self.angvel * dt) * shift.inverse()
}
diff --git a/src/dynamics/solver/position_constraint.rs b/src/dynamics/solver/position_constraint.rs
index 608a342..69fcf57 100644
--- a/src/dynamics/solver/position_constraint.rs
+++ b/src/dynamics/solver/position_constraint.rs
@@ -104,8 +104,8 @@ impl PositionConstraint {
let mut local_p2 = [Point::origin(); MAX_MANIFOLD_POINTS];
for l in 0..manifold_points.len() {
- local_p1[l] = manifold_points[l].local_p1 + shift1;
- local_p2[l] = manifold_points[l].local_p2 + shift2;
+ local_p1[l] = manifold.delta1 * (manifold_points[l].local_p1 + shift1);
+ local_p2[l] = manifold.delta2 * (manifold_points[l].local_p2 + shift2);
}
let constraint = PositionConstraint {
diff --git a/src/dynamics/solver/position_constraint_wide.rs b/src/dynamics/solver/position_constraint_wide.rs
index 8828c3d..0633926 100644
--- a/src/dynamics/solver/position_constraint_wide.rs
+++ b/src/dynamics/solver/position_constraint_wide.rs
@@ -51,6 +51,9 @@ impl WPositionConstraint {
let radius1 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius1; SIMD_WIDTH]);
let radius2 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius2; SIMD_WIDTH]);
+ let delta1 = Isometry::from(array![|ii| manifolds[ii].delta1; SIMD_WIDTH]);
+ let delta2 = Isometry::from(array![|ii| manifolds[ii].delta2; SIMD_WIDTH]);
+
let rb1 = array![|ii| rbs1[ii].active_set_offset; SIMD_WIDTH];
let rb2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
@@ -85,8 +88,8 @@ impl WPositionConstraint {
let local_p2 =
Point::from(array![|ii| manifold_points[ii][i].local_p2; SIMD_WIDTH]);
- constraint.local_p1[i] = local_p1 + shift1;
- constraint.local_p2[i] = local_p2 + shift2;
+ constraint.local_p1[i] = delta1 * (local_p1 + shift1);
+ constraint.local_p2[i] = delta2 * (local_p2 + shift2);
}
if push {
diff --git a/src/dynamics/solver/position_ground_constraint.rs b/src/dynamics/solver/position_ground_constraint.rs
index e6e83c6..dcd2d64 100644
--- a/src/dynamics/solver/position_ground_constraint.rs
+++ b/src/dynamics/solver/position_ground_constraint.rs
@@ -34,22 +34,30 @@ impl PositionGroundConstraint {
let local_n1;
let local_n2;
+ let delta1;
+ let delta2;
if flip {
std::mem::swap(&mut rb1, &mut rb2);
local_n1 = manifold.local_n2;
local_n2 = manifold.local_n1;
+ delta1 = &manifold.delta2;
+ delta2 = &manifold.delta1;
} else {
local_n1 = manifold.local_n1;
local_n2 = manifold.local_n2;
+ delta1 = &manifold.delta1;
+ delta2 = &manifold.delta2;
};
+ let coll_pos1 = rb1.position * delta1;
let shift1 = local_n1 * -manifold.kinematics.radius1;
let shift2 = local_n2 * -manifold.kinematics.radius2;
+ let n1 = coll_pos1 * local_n1;
let radius =
manifold.kinematics.radius1 + manifold.kinematics.radius2 /* - params.allowed_linear_error */;
- for (l, manifold_points) in manifold
+ for (l, manifold_contacts) in manifold
.active_contacts()
.chunks(MAX_MANIFOLD_POINTS)
.enumerate()
@@ -59,16 +67,16 @@ impl PositionGroundConstraint {
if flip {
// Don't forget that we already swapped rb1 and rb2 above.
- // So if we flip, only manifold_points[k].{local_p1,local_p2} have to
+ // So if we flip, only manifold_contacts[k].{local_p1,local_p2} have to
// be swapped.
- for k in 0..manifold_points.len() {
- p1[k] = rb1.predicted_position * (manifold_points[k].local_p2 + shift1);
- local_p2[k] = manifold_points[k].local_p1 + shift2;
+ for k in 0..manifold_contacts.len() {
+ p1[k] = coll_pos1 * (manifold_contacts[k].local_p2 + shift1);
+ local_p2[k] = delta2 * (manifold_contacts[k].local_p1 + shift2);
}
} else {
- for k in 0..manifold_points.len() {
- p1[k] = rb1.predicted_position * (manifold_points[k].local_p1 + shift1);
- local_p2[k] = manifold_points[k].local_p2 + shift2;
+ for k in 0..manifold_contacts.len() {
+ p1[k] = coll_pos1 * (manifold_contacts[k].local_p1 + shift1);
+ local_p2[k] = delta2 * (manifold_contacts[k].local_p2 + shift2);
}
}
@@ -76,11 +84,11 @@ impl PositionGroundConstraint {
rb2: rb2.active_set_offset,
p1,
local_p2,
- n1: rb1.predicted_position * local_n1,
+ n1,
radius,
im2: rb2.mass_properties.inv_mass,
ii2: rb2.world_inv_inertia_sqrt.squared(),
- num_contacts: manifold_points.len() as u8,
+ num_contacts: manifold_contacts.len() as u8,
erp: params.erp,
max_linear_correction: params.max_linear_correction,
};
diff --git a/src/dynamics/solver/position_ground_constraint_wide.rs b/src/dynamics/solver/position_ground_constraint_wide.rs
index faa928b..e423c0a 100644
--- a/src/dynamics/solver/position_ground_constraint_wide.rs
+++ b/src/dynamics/solver/position_ground_constraint_wide.rs
@@ -54,16 +54,24 @@ impl WPositionGroundConstraint {
array![|ii| if flipped[ii] { manifolds[ii].local_n1 } else { manifolds[ii].local_n2 }; SIMD_WIDTH],
);
+ let delta1 = Isometry::from(
+ array![|ii| if flipped[ii] { manifolds[ii].delta2 } else { manifolds[ii].delta1 }; SIMD_WIDTH],
+ );
+ let delta2 = Isometry::from(
+ array![|ii| if flipped[ii] { manifolds[ii].delta1 } else { manifolds[ii].delta2 }; SIMD_WIDTH],
+ );
+
let radius1 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius1; SIMD_WIDTH]);
let radius2 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius2; SIMD_WIDTH]);
- let position1 = Isometry::from(array![|ii| rbs1[ii].predicted_position; SIMD_WIDTH]);
+ let coll_pos1 =
+ delta1 * Isometry::from(array![|ii| rbs1[ii].predicted_position; SIMD_WIDTH]);
let rb2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
let radius = radius1 + radius2 /*- SimdFloat::splat(params.allowed_linear_error)*/;
- let n1 = position1 * local_n1;
+ let n1 = coll_pos1 * local_n1;
for l in (0..manifolds[0].num_active_contacts()).step_by(MAX_MANIFOLD_POINTS) {
let manifold_points = array![|ii| &manifolds[ii].active_contacts()[l..]; SIMD_WIDTH];
@@ -90,8 +98,8 @@ impl WPositionGroundConstraint {
array![|ii| if flipped[ii] { manifold_points[ii][i].local_p1 } else { manifold_points[ii][i].local_p2 }; SIMD_WIDTH],
);
- constraint.p1[i] = position1 * local_p1 - n1 * radius1;
- constraint.local_p2[i] = local_p2 - local_n2 * radius2;
+ constraint.p1[i] = coll_pos1 * local_p1 - n1 * radius1;
+ constraint.local_p2[i] = delta2 * (local_p2 - local_n2 * radius2);
}
if push {
diff --git a/src/dynamics/solver/velocity_constraint.rs b/src/dynamics/solver/velocity_constraint.rs
index 9212e89..190076d 100644
--- a/src/dynamics/solver/velocity_constraint.rs
+++ b/src/dynamics/solver/velocity_constraint.rs
@@ -148,7 +148,9 @@ impl VelocityConstraint {
let rb2 = &bodies[manifold.body_pair.body2];
let mj_lambda1 = rb1.active_set_offset;
let mj_lambda2 = rb2.active_set_offset;
- let force_dir1 = rb1.position * (-manifold.local_n1);
+ let pos_coll1 = rb1.position * manifold.delta1;
+ let pos_coll2 = rb2.position * manifold.delta2;
+ let force_dir1 = pos_coll1 * (-manifold.local_n1);
let warmstart_coeff = manifold.warmstart_multiplier * params.warmstart_coeff;
for (l, manifold_points) in manifold
@@ -215,10 +217,8 @@ impl VelocityConstraint {
for k in 0..manifold_points.len() {
let manifold_point = &manifold_points[k];
- let dp1 = (rb1.position * manifold_point.local_p1).coords
- - rb1.position.translation.vector;
- let dp2 = (rb2.position * manifold_point.local_p2).coords
- - rb2.position.translation.vector;
+ let dp1 = (pos_coll1 * manifold_point.local_p1) - rb1.world_com;
+ let dp2 = (pos_coll2 * manifold_point.local_p2) - rb2.world_com;
let vel1 = rb1.linvel + rb1.angvel.gcross(dp1);
let vel2 = rb2.linvel + rb2.angvel.gcross(dp2);
@@ -355,7 +355,7 @@ impl VelocityConstraint {
}
}
- // Solve penetration.
+ // Solve non-penetration.
for i in 0..self.num_contacts as usize {
let elt = &mut self.elements[i].normal_part;
let dimpulse = self.dir1.dot(&mj_lambda1.linear) + elt.gcross1.gdot(mj_lambda1.angular)
diff --git a/src/dynamics/solver/velocity_constraint_wide.rs b/src/dynamics/solver/velocity_constraint_wide.rs
index 8f387a5..f515d5e 100644
--- a/src/dynamics/solver/velocity_constraint_wide.rs
+++ b/src/dynamics/solver/velocity_constraint_wide.rs
@@ -72,6 +72,9 @@ impl WVelocityConstraint {
let rbs1 = array![|ii| &bodies[manifolds[ii].body_pair.body1]; SIMD_WIDTH];
let rbs2 = array![|ii| &bodies[manifolds[ii].body_pair.body2]; SIMD_WIDTH];
+ let delta1 = Isometry::from(array![|ii| manifolds[ii].delta1; SIMD_WIDTH]);
+ let delta2 = Isometry::from(array![|ii| manifolds[ii].delta2; SIMD_WIDTH]);
+
let im1 = SimdFloat::from(array![|ii| rbs1[ii].mass_properties.inv_mass; SIMD_WIDTH]);
let ii1: AngularInertia<SimdFloat> =
AngularInertia::from(array![|ii| rbs1[ii].world_inv_inertia_sqrt; SIMD_WIDTH]);
@@ -79,7 +82,8 @@ impl WVelocityConstraint {
let linvel1 = Vector::from(array![|ii| rbs1[ii].linvel; SIMD_WIDTH]);
let angvel1 = AngVector::<SimdFloat>::from(array![|ii| rbs1[ii].angvel; SIMD_WIDTH]);
- let position1 = Isometry::from(array![|ii| rbs1[ii].position; SIMD_WIDTH]);
+ let pos1 = Isometry::from(array![|ii| rbs1[ii].position; SIMD_WIDTH]);
+ let world_com1 = Point::from(array![|ii| rbs1[ii].world_com; SIMD_WIDTH]);
let im2 = SimdFloat::from(array![|ii| rbs2[ii].mass_properties.inv_mass; SIMD_WIDTH]);
let ii2: AngularInertia<SimdFloat> =
@@ -88,9 +92,13 @@ impl WVelocityConstraint {
let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]);
let angvel2 = AngVector::<SimdFloat>::from(array![|ii| rbs2[ii].angvel; SIMD_WIDTH]);
- let position2 = Isometry::from(array![|ii| rbs2[ii].position; SIMD_WIDTH]);
+ let pos2 = Isometry::from(array![|ii| rbs2[ii].position; SIMD_WIDTH]);
+ let world_com2 = Point::from(array![|ii| rbs2[ii].world_com; SIMD_WIDTH]);
+
+ let coll_pos1 = pos1 * delta1;
+ let coll_pos2 = pos2 * delta2;
- let force_dir1 = position1 * -Vector::from(array![|ii| manifolds[ii].local_n1; SIMD_WIDTH]);
+ let force_dir1 = coll_pos1 * -Vector::from(array![|ii| manifolds[ii].local_n1; SIMD_WIDTH]);
let mj_lambda1 = array![|ii| rbs1[ii].active_set_offset; SIMD_WIDTH];
let mj_lambda2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
@@ -118,11 +126,11 @@ impl WVelocityConstraint {
};
for k in 0..num_points {
- // FIXME: can we avoid the multiplications by position1/position2 here?
+ // FIXME: can we avoid the multiplications by coll_pos1/coll_pos2 here?
// By working as much as possible in local-space.
- let p1 = position1
+ let p1 = coll_pos1
* Point::from(array![|ii| manifold_points[ii][k].local_p1; SIMD_WIDTH]);
- let p2 = position2
+ let p2 = coll_pos2
* Point::from(array![|ii| manifold_points[ii][k].local_p2; SIMD_WIDTH]);
let dist = SimdFloat::from(array![|ii| manifold_points[ii][k].dist; SIMD_WIDTH]);
@@ -130,8 +138,8 @@ impl WVelocityConstraint {
let impulse =
SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]);
- let dp1 = p1.coords - position1.translation.vector;
- let dp2 = p2.coords - position2.translation.vector;
+ let dp1 = p1 - world_com1;
+ let dp2 = p2 - world_com2;
let vel1 = linvel1 + angvel1.gcross(dp1);
let vel2 = linvel2 + angvel2.gcross(dp2);
diff --git a/src/dynamics/solver/velocity_ground_constraint.rs b/src/dynamics/solver/velocity_ground_constraint.rs
index 457c3b3..d9229ff 100644
--- a/src/dynamics/solver/velocity_ground_constraint.rs
+++ b/src/dynamics/solver/velocity_ground_constraint.rs
@@ -66,20 +66,22 @@ impl VelocityGroundConstraint {
let mut rb1 = &bodies[manifold.body_pair.body1];
let mut rb2 = &bodies[manifold.body_pair.body2];
let flipped = !rb2.is_dynamic();
+ let force_dir1;
+ let coll_pos1;
+ let coll_pos2;
if flipped {
+ coll_pos1 = rb2.position * manifold.delta2;
+ coll_pos2 = rb1.position * manifold.delta1;
+ force_dir1 = coll_pos1 * (-manifold.local_n2);
std::mem::swap(&mut rb1, &mut rb2);
+ } else {
+ coll_pos1 = rb1.position * manifold.delta1;
+ coll_pos2 = rb2.position * manifold.delta2;
+ force_dir1 = coll_pos1 * (-manifold.local_n1);
}
let mj_lambda2 = rb2.active_set_offset;
- let force_dir1 = if flipped {
- // NOTE: we already swapped rb1 and rb2
- // so we multiply by rb1.position.
- rb1.position * (-manifold.local_n2)
- } else {
- rb1.position * (-manifold.local_n1)
- };
-
let warmstart_coeff = manifold.warmstart_multiplier * params.warmstart_coeff;
for (l, manifold_points) in manifold
@@ -144,19 +146,19 @@ impl VelocityGroundConstraint {
let manifold_point = &manifold_points[k];
let (p1, p2) = if flipped {
// NOTE: we already swapped rb1 and rb2
- // so we multiply by rb2.position.
+ // so we multiply by coll_pos1/coll_pos2.
(
- rb1.position * manifold_point.local_p2,
- rb2.position * manifold_point.local_p1,
+ coll_pos1 * manifold_point.local_p2,
+ coll_pos2 * manifold_point.local_p1,
)
} else {
(
- rb1.position * manifold_point.local_p1,
- rb2.position * manifold_point.local_p2,
+ coll_pos1 * manifold_point.local_p1,
+ coll_pos2 * manifold_point.local_p2,
)
};
- let dp2 = p2.coords - rb2.position.translation.vector;
- let dp1 = p1.coords - rb1.position.translation.vector;
+ let dp2 = p2 - rb2.world_com;
+ let dp1 = p1 - rb1.world_com;
let vel1 = rb1.linvel + rb1.angvel.gcross(dp1);
let vel2 = rb2.linvel + rb2.angvel.gcross(dp2);
diff --git a/src/dynamics/solver/velocity_ground_constraint_wide.rs b/src/dynamics/solver/velocity_ground_constraint_wide.rs
index ec9e186..18e9257 100644
--- a/src/dynamics/solver/velocity_ground_constraint_wide.rs
+++ b/src/dynamics/solver/velocity_ground_constraint_wide.rs
@@ -86,10 +86,23 @@ impl WVelocityGroundConstraint {
let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]);
let angvel2 = AngVector::<SimdFloat>::from(array![|ii| rbs2[ii].angvel; SIMD_WIDTH]);
- let position1 = Isometry::from(array![|ii| rbs1[ii].position; SIMD_WIDTH]);
- let position2 = Isometry::from(array![|ii| rbs2[ii].position; SIMD_WIDTH]);
+ let pos1 = Isometry::from(array![|ii| rbs1[ii].position; SIMD_WIDTH]);
+ let pos2 = Isometry::from(array![|ii| rbs2[ii].position; SIMD_WIDTH]);
- let force_dir1 = position1
+ let delta1 = Isometry::from(
+ array![|ii| if flipped[ii] { manifolds[ii].delta2 } else { manifolds[ii].delta1 }; SIMD_WIDTH],
+ );
+ let delta2 = Isometry::from(
+ array![|ii| if flipped[ii] { manifolds[ii].delta1 } else { manifolds[ii].delta2 }; SIMD_WIDTH],
+ );
+
+ let coll_pos1 = pos1 * delta1;
+ let coll_pos2 = pos2 * delta2;
+
+ let world_com1 = Point::from(array![|ii| rbs1[ii].world_com; SIMD_WIDTH]);
+ let world_com2 = Point::from(array![|ii| rbs2[ii].world_com; SIMD_WIDTH]);
+
+ let force_dir1 = coll_pos1
* -Vector::from(
array![|ii| if flipped[ii] { manifolds[ii].local_n2 } else { manifolds[ii].local_n1 }; SIMD_WIDTH],
);
@@ -117,11 +130,11 @@ impl WVelocityGroundConstraint {
};
for k in 0..num_points {
- let p1 = position1
+ let p1 = coll_pos1
* Point::from(
array![|ii| if flipped[ii] { manifold_points[ii][k].local_p2 } else { manifold_points[ii][k].local_p1 }; SIMD_WIDTH],
);
- let p2 = position2
+ let p2 = coll_pos2
* Point::from(
array![|ii| if flipped[ii] { manifold_points[ii][k].local_p1 } else { manifold_points[ii][k].local_p2 }; SIMD_WIDTH],
);
@@ -130,8 +143,8 @@ impl WVelocityGroundConstraint {
let impulse =
SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]);
- let dp1 = p1.coords - position1.translation.vector;
- let dp2 = p2.coords - position2.translation.vector;
+ let dp1 = p1 - world_com1;
+ let dp2 = p2 - world_com2;
let vel1 = linvel1 + angvel1.gcross(dp1);
let vel2 = linvel2 + angvel2.gcross(dp2);
diff --git a/src/geometry/broad_phase_multi_sap.rs b/src/geometry/broad_phase_multi_sap.rs
index 0505e21..054fccf 100644
--- a/src/geometry/broad_phase_multi_sap.rs
+++ b/src/geometry/broad_phase_multi_sap.rs
@@ -662,7 +662,7 @@ mod test {
let rb = RigidBodyBuilder::new_dynamic().build();
let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb);
- let hco = colliders.insert(co, hrb, &mut bodies);
+ colliders.insert(co, hrb, &mut bodies);
broad_phase.update_aabbs(0.0, &bodies, &mut colliders);
@@ -681,7 +681,7 @@ mod test {
let rb = RigidBodyBuilder::new_dynamic().build();
let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb);
- let hco = colliders.insert(co, hrb, &mut bodies);
+ colliders.insert(co, hrb, &mut bodies);
// Make sure the proxy handles is recycled properly.
broad_phase.update_aabbs(0.0, &bodies, &mut colliders);
diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs
index 2457212..aed76c8 100644
--- a/src/geometry/collider.rs
+++ b/src/geometry/collider.rs
@@ -3,7 +3,7 @@ use crate::geometry::{
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon,
Proximity, Triangle, Trimesh,
};
-use crate::math::{Isometry, Point, Vector};
+use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
use na::Point3;
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
use num::Zero;
@@ -150,6 +150,7 @@ impl Collider {