Merge pull request #6 from dimforge/collider_removal

Add collider removal + fix rigid-bodies with multiple colliders
This commit is contained in:
Sébastien Crozet
2020-09-01 18:21:11 +02:00
committed by GitHub
30 changed files with 634 additions and 86 deletions

82
.circleci/config.yml Normal file
View File

@@ -0,0 +1,82 @@
version: 2.1
executors:
rust-executor:
docker:
- image: rust:latest
jobs:
check-fmt:
executor: rust-executor
steps:
- checkout
- run:
name: install rustfmt
command: rustup component add rustfmt
- run:
name: check formatting
command: cargo fmt -- --check
build-native:
executor: rust-executor
steps:
- checkout
- run: apt-get update
- run: apt-get install -y cmake libxcb-composite0-dev
- run:
name: build rapier2d
command: cargo build --verbose -p rapier2d;
- run:
name: build rapier3d
command: cargo build --verbose -p rapier3d;
- run:
name: build rapier2d SIMD
command: cd build/rapier2d; cargo build --verbose --features simd-stable;
- run:
name: build rapier3d SIMD
command: cd build/rapier3d; cargo build --verbose --features simd-stable;
- run:
name: build rapier2d SIMD Parallel
command: cd build/rapier2d; cargo build --verbose --features simd-stable --features parallel;
- run:
name: build rapier3d SIMD Parallel
command: cd build/rapier3d; cargo build --verbose --features simd-stable --features parallel;
- run:
name: test
command: cargo test
- run:
name: check rapier_testbed2d
command: cargo check --verbose -p rapier_testbed2d;
- run:
name: check rapier_testbed3d
command: cargo check --verbose -p rapier_testbed3d;
- run:
name: check rapier-examples-2d
command: cargo check -j 1 --verbose -p rapier-examples-2d;
- run:
name: check rapier-examples-3d
command: cargo check -j 1 --verbose -p rapier-examples-3d;
build-wasm:
executor: rust-executor
steps:
- checkout
- run:
name: install cargo-web
command: cargo install -f cargo-web;
- run:
name: build rapier2d
command: cd build/rapier2d && cargo web build --verbose --features wasm-bindgen --target wasm32-unknown-unknown;
- run:
name: build rapier3d
command: cd build/rapier3d && cargo web build --verbose --features wasm-bindgen --target wasm32-unknown-unknown;
workflows:
version: 2
build:
jobs:
- check-fmt
- build-native:
requires:
- check-fmt
- build-wasm:
requires:
- check-fmt

View File

@@ -10,3 +10,10 @@ debug = false
codegen-units = 1 codegen-units = 1
#opt-level = 1 #opt-level = 1
#lto = true #lto = true
#[profile.dev.package.rapier3d]
#opt-level = 3
#
#[profile.dev.package.kiss3d]
#opt-level = 3

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "nphysics-examples-2d" name = "rapier-examples-2d"
version = "0.1.0" version = "0.1.0"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Sébastien Crozet <developer@crozet.re>" ]
edition = "2018" edition = "2018"

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "nphysics-examples-3d" name = "rapier-examples-3d"
version = "0.1.0" version = "0.1.0"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Sébastien Crozet <developer@crozet.re>" ]
edition = "2018" edition = "2018"
@@ -24,4 +24,4 @@ path = "../build/rapier3d"
[[bin]] [[bin]]
name = "all_examples3" name = "all_examples3"
path = "./all_examples3.rs" path = "./all_examples3.rs"

View File

@@ -14,6 +14,7 @@ mod add_remove3;
mod balls3; mod balls3;
mod boxes3; mod boxes3;
mod capsules3; mod capsules3;
mod compound3;
mod debug_boxes3; mod debug_boxes3;
mod debug_triangle3; mod debug_triangle3;
mod domino3; mod domino3;
@@ -71,6 +72,7 @@ pub fn main() {
("Balls", balls3::init_world), ("Balls", balls3::init_world),
("Boxes", boxes3::init_world), ("Boxes", boxes3::init_world),
("Capsules", capsules3::init_world), ("Capsules", capsules3::init_world),
("Compound", compound3::init_world),
("Domino", domino3::init_world), ("Domino", domino3::init_world),
("Heightfield", heightfield3::init_world), ("Heightfield", heightfield3::init_world),
("Joints", joints3::init_world), ("Joints", joints3::init_world),

76
examples3d/compound3.rs Normal file
View File

@@ -0,0 +1,76 @@
use na::Point3;
use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
use rapier3d::geometry::{ColliderBuilder, ColliderSet};
use rapier_testbed3d::Testbed;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let joints = JointSet::new();
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::new_static()
.translation(0.0, -ground_height, 0.0)
.build();
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).build();
colliders.insert(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let rad = 0.2;
let shift = rad * 4.0 + rad;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
for j in 0usize..25 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift * 5.0 - centerx + offset;
let y = j as f32 * (shift * 5.0) + centery + 3.0;
let z = k as f32 * shift * 2.0 - centerz + offset;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y, z).build();
let handle = bodies.insert(rigid_body);
let collider1 = ColliderBuilder::cuboid(rad * 10.0, rad, rad).build();
let collider2 = ColliderBuilder::cuboid(rad, rad * 10.0, rad)
.translation(rad * 10.0, rad * 10.0, 0.0)
.build();
let collider3 = ColliderBuilder::cuboid(rad, rad * 10.0, rad)
.translation(-rad * 10.0, rad * 10.0, 0.0)
.build();
colliders.insert(collider1, handle, &mut bodies);
colliders.insert(collider2, handle, &mut bodies);
colliders.insert(collider3, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, joints);
testbed.look_at(Point3::new(100.0, 100.0, 100.0), Point3::origin());
}
fn main() {
let testbed = Testbed::from_builders(0, vec![("Boxes", init_world)]);
testbed.run()
}

3
rustfmt.toml Normal file
View File

@@ -0,0 +1,3 @@
#indent_style = "Block"
#where_single_line = true
#brace_style = "PreferSameLine"

View File

@@ -1,7 +1,7 @@
use crate::math::{AngVector, AngularInertia, Isometry, Point, Rotation, Vector}; use crate::math::{AngVector, AngularInertia, Isometry, Point, Rotation, Vector};
use crate::utils; use crate::utils;
use num::Zero; use num::Zero;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign, Sub, SubAssign};
#[cfg(feature = "dim3")] #[cfg(feature = "dim3")]
use {na::Matrix3, std::ops::MulAssign}; use {na::Matrix3, std::ops::MulAssign};
@@ -90,6 +90,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")] #[cfg(feature = "dim3")]
/// Reconstructs the angular inertia tensor of the rigid body from its principal inertia values and axii. /// Reconstructs the angular inertia tensor of the rigid body from its principal inertia values and axii.
pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> { pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> {
@@ -125,6 +137,19 @@ impl MassProperties {
Matrix3::zeros() 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 { 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 { impl Add<MassProperties> for MassProperties {
type Output = Self; 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 i2 = other.construct_shifted_inertia_matrix(local_com - other.local_com);
let inertia = i1 + i2; let inertia = i1 + i2;
let eigen = inertia.symmetric_eigen(); 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 principal_inertia = eigen.eigenvalues;
let inv_principal_inertia_sqrt = principal_inertia.map(|e| utils::inv(e.sqrt())); 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 *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
);
}
}

View File

@@ -1,5 +1,5 @@
use crate::dynamics::MassProperties; 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::math::{AngVector, AngularInertia, Isometry, Point, Rotation, Translation, Vector};
use crate::utils::{WCross, WDot}; use crate::utils::{WCross, WDot};
use num::Zero; use num::Zero;
@@ -137,6 +137,28 @@ impl RigidBody {
crate::utils::inv(self.mass_properties.inv_mass) 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. /// Put this rigid body to sleep.
/// ///
/// A sleeping body no longer moves and is no longer simulated by the physics engine unless /// 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> { 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); let shift = Translation::from(com.coords);
shift * Isometry::new(self.linvel * dt, self.angvel * dt) * shift.inverse() shift * Isometry::new(self.linvel * dt, self.angvel * dt) * shift.inverse()
} }

View File

@@ -104,8 +104,8 @@ impl PositionConstraint {
let mut local_p2 = [Point::origin(); MAX_MANIFOLD_POINTS]; let mut local_p2 = [Point::origin(); MAX_MANIFOLD_POINTS];
for l in 0..manifold_points.len() { for l in 0..manifold_points.len() {
local_p1[l] = manifold_points[l].local_p1 + shift1; local_p1[l] = manifold.delta1 * (manifold_points[l].local_p1 + shift1);
local_p2[l] = manifold_points[l].local_p2 + shift2; local_p2[l] = manifold.delta2 * (manifold_points[l].local_p2 + shift2);
} }
let constraint = PositionConstraint { let constraint = PositionConstraint {

View File

@@ -51,6 +51,9 @@ impl WPositionConstraint {
let radius1 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius1; 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 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 rb1 = array![|ii| rbs1[ii].active_set_offset; SIMD_WIDTH];
let rb2 = array![|ii| rbs2[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 = let local_p2 =
Point::from(array![|ii| manifold_points[ii][i].local_p2; SIMD_WIDTH]); Point::from(array![|ii| manifold_points[ii][i].local_p2; SIMD_WIDTH]);
constraint.local_p1[i] = local_p1 + shift1; constraint.local_p1[i] = delta1 * (local_p1 + shift1);
constraint.local_p2[i] = local_p2 + shift2; constraint.local_p2[i] = delta2 * (local_p2 + shift2);
} }
if push { if push {

View File

@@ -34,22 +34,30 @@ impl PositionGroundConstraint {
let local_n1; let local_n1;
let local_n2; let local_n2;
let delta1;
let delta2;
if flip { if flip {
std::mem::swap(&mut rb1, &mut rb2); std::mem::swap(&mut rb1, &mut rb2);
local_n1 = manifold.local_n2; local_n1 = manifold.local_n2;
local_n2 = manifold.local_n1; local_n2 = manifold.local_n1;
delta1 = &manifold.delta2;
delta2 = &manifold.delta1;
} else { } else {
local_n1 = manifold.local_n1; local_n1 = manifold.local_n1;
local_n2 = manifold.local_n2; 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 shift1 = local_n1 * -manifold.kinematics.radius1;
let shift2 = local_n2 * -manifold.kinematics.radius2; let shift2 = local_n2 * -manifold.kinematics.radius2;
let n1 = coll_pos1 * local_n1;
let radius = let radius =
manifold.kinematics.radius1 + manifold.kinematics.radius2 /* - params.allowed_linear_error */; manifold.kinematics.radius1 + manifold.kinematics.radius2 /* - params.allowed_linear_error */;
for (l, manifold_points) in manifold for (l, manifold_contacts) in manifold
.active_contacts() .active_contacts()
.chunks(MAX_MANIFOLD_POINTS) .chunks(MAX_MANIFOLD_POINTS)
.enumerate() .enumerate()
@@ -59,16 +67,16 @@ impl PositionGroundConstraint {
if flip { if flip {
// Don't forget that we already swapped rb1 and rb2 above. // 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. // be swapped.
for k in 0..manifold_points.len() { for k in 0..manifold_contacts.len() {
p1[k] = rb1.predicted_position * (manifold_points[k].local_p2 + shift1); p1[k] = coll_pos1 * (manifold_contacts[k].local_p2 + shift1);
local_p2[k] = manifold_points[k].local_p1 + shift2; local_p2[k] = delta2 * (manifold_contacts[k].local_p1 + shift2);
} }
} else { } else {
for k in 0..manifold_points.len() { for k in 0..manifold_contacts.len() {
p1[k] = rb1.predicted_position * (manifold_points[k].local_p1 + shift1); p1[k] = coll_pos1 * (manifold_contacts[k].local_p1 + shift1);
local_p2[k] = manifold_points[k].local_p2 + shift2; local_p2[k] = delta2 * (manifold_contacts[k].local_p2 + shift2);
} }
} }
@@ -76,11 +84,11 @@ impl PositionGroundConstraint {
rb2: rb2.active_set_offset, rb2: rb2.active_set_offset,
p1, p1,
local_p2, local_p2,
n1: rb1.predicted_position * local_n1, n1,
radius, radius,
im2: rb2.mass_properties.inv_mass, im2: rb2.mass_properties.inv_mass,
ii2: rb2.world_inv_inertia_sqrt.squared(), ii2: rb2.world_inv_inertia_sqrt.squared(),
num_contacts: manifold_points.len() as u8, num_contacts: manifold_contacts.len() as u8,
erp: params.erp, erp: params.erp,
max_linear_correction: params.max_linear_correction, max_linear_correction: params.max_linear_correction,
}; };

View File

@@ -54,16 +54,24 @@ impl WPositionGroundConstraint {
array![|ii| if flipped[ii] { manifolds[ii].local_n1 } else { manifolds[ii].local_n2 }; SIMD_WIDTH], 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 radius1 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius1; SIMD_WIDTH]);
let radius2 = SimdFloat::from(array![|ii| manifolds[ii].kinematics.radius2; 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 rb2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
let radius = radius1 + radius2 /*- SimdFloat::splat(params.allowed_linear_error)*/; 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) { 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]; 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], 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.p1[i] = coll_pos1 * local_p1 - n1 * radius1;
constraint.local_p2[i] = local_p2 - local_n2 * radius2; constraint.local_p2[i] = delta2 * (local_p2 - local_n2 * radius2);
} }
if push { if push {

View File

@@ -148,7 +148,9 @@ impl VelocityConstraint {
let rb2 = &bodies[manifold.body_pair.body2]; let rb2 = &bodies[manifold.body_pair.body2];
let mj_lambda1 = rb1.active_set_offset; let mj_lambda1 = rb1.active_set_offset;
let mj_lambda2 = rb2.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; let warmstart_coeff = manifold.warmstart_multiplier * params.warmstart_coeff;
for (l, manifold_points) in manifold for (l, manifold_points) in manifold
@@ -215,10 +217,8 @@ impl VelocityConstraint {
for k in 0..manifold_points.len() { for k in 0..manifold_points.len() {
let manifold_point = &manifold_points[k]; let manifold_point = &manifold_points[k];
let dp1 = (rb1.position * manifold_point.local_p1).coords let dp1 = (pos_coll1 * manifold_point.local_p1) - rb1.world_com;
- rb1.position.translation.vector; let dp2 = (pos_coll2 * manifold_point.local_p2) - rb2.world_com;
let dp2 = (rb2.position * manifold_point.local_p2).coords
- rb2.position.translation.vector;
let vel1 = rb1.linvel + rb1.angvel.gcross(dp1); let vel1 = rb1.linvel + rb1.angvel.gcross(dp1);
let vel2 = rb2.linvel + rb2.angvel.gcross(dp2); 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 { for i in 0..self.num_contacts as usize {
let elt = &mut self.elements[i].normal_part; let elt = &mut self.elements[i].normal_part;
let dimpulse = self.dir1.dot(&mj_lambda1.linear) + elt.gcross1.gdot(mj_lambda1.angular) let dimpulse = self.dir1.dot(&mj_lambda1.linear) + elt.gcross1.gdot(mj_lambda1.angular)

View File

@@ -72,6 +72,9 @@ impl WVelocityConstraint {
let rbs1 = array![|ii| &bodies[manifolds[ii].body_pair.body1]; SIMD_WIDTH]; 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 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 im1 = SimdFloat::from(array![|ii| rbs1[ii].mass_properties.inv_mass; SIMD_WIDTH]);
let ii1: AngularInertia<SimdFloat> = let ii1: AngularInertia<SimdFloat> =
AngularInertia::from(array![|ii| rbs1[ii].world_inv_inertia_sqrt; SIMD_WIDTH]); 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 linvel1 = Vector::from(array![|ii| rbs1[ii].linvel; SIMD_WIDTH]);
let angvel1 = AngVector::<SimdFloat>::from(array![|ii| rbs1[ii].angvel; 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 im2 = SimdFloat::from(array![|ii| rbs2[ii].mass_properties.inv_mass; SIMD_WIDTH]);
let ii2: AngularInertia<SimdFloat> = let ii2: AngularInertia<SimdFloat> =
@@ -88,9 +92,13 @@ impl WVelocityConstraint {
let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]); let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]);
let angvel2 = AngVector::<SimdFloat>::from(array![|ii| rbs2[ii].angvel; 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 force_dir1 = position1 * -Vector::from(array![|ii| manifolds[ii].local_n1; SIMD_WIDTH]); let coll_pos1 = pos1 * delta1;
let coll_pos2 = pos2 * delta2;
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_lambda1 = array![|ii| rbs1[ii].active_set_offset; SIMD_WIDTH];
let mj_lambda2 = array![|ii| rbs2[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 { 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. // 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]); * 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]); * 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]); let dist = SimdFloat::from(array![|ii| manifold_points[ii][k].dist; SIMD_WIDTH]);
@@ -130,8 +138,8 @@ impl WVelocityConstraint {
let impulse = let impulse =
SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]); SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]);
let dp1 = p1.coords - position1.translation.vector; let dp1 = p1 - world_com1;
let dp2 = p2.coords - position2.translation.vector; let dp2 = p2 - world_com2;
let vel1 = linvel1 + angvel1.gcross(dp1); let vel1 = linvel1 + angvel1.gcross(dp1);
let vel2 = linvel2 + angvel2.gcross(dp2); let vel2 = linvel2 + angvel2.gcross(dp2);

View File

@@ -66,20 +66,22 @@ impl VelocityGroundConstraint {
let mut rb1 = &bodies[manifold.body_pair.body1]; let mut rb1 = &bodies[manifold.body_pair.body1];
let mut rb2 = &bodies[manifold.body_pair.body2]; let mut rb2 = &bodies[manifold.body_pair.body2];
let flipped = !rb2.is_dynamic(); let flipped = !rb2.is_dynamic();
let force_dir1;
let coll_pos1;
let coll_pos2;
if flipped { 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); 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 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; let warmstart_coeff = manifold.warmstart_multiplier * params.warmstart_coeff;
for (l, manifold_points) in manifold for (l, manifold_points) in manifold
@@ -144,19 +146,19 @@ impl VelocityGroundConstraint {
let manifold_point = &manifold_points[k]; let manifold_point = &manifold_points[k];
let (p1, p2) = if flipped { let (p1, p2) = if flipped {
// NOTE: we already swapped rb1 and rb2 // 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, coll_pos1 * manifold_point.local_p2,
rb2.position * manifold_point.local_p1, coll_pos2 * manifold_point.local_p1,
) )
} else { } else {
( (
rb1.position * manifold_point.local_p1, coll_pos1 * manifold_point.local_p1,
rb2.position * manifold_point.local_p2, coll_pos2 * manifold_point.local_p2,
) )
}; };
let dp2 = p2.coords - rb2.position.translation.vector; let dp2 = p2 - rb2.world_com;
let dp1 = p1.coords - rb1.position.translation.vector; let dp1 = p1 - rb1.world_com;
let vel1 = rb1.linvel + rb1.angvel.gcross(dp1); let vel1 = rb1.linvel + rb1.angvel.gcross(dp1);
let vel2 = rb2.linvel + rb2.angvel.gcross(dp2); let vel2 = rb2.linvel + rb2.angvel.gcross(dp2);

View File

@@ -86,10 +86,23 @@ impl WVelocityGroundConstraint {
let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]); let linvel2 = Vector::from(array![|ii| rbs2[ii].linvel; SIMD_WIDTH]);
let angvel2 = AngVector::<SimdFloat>::from(array![|ii| rbs2[ii].angvel; 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 pos1 = Isometry::from(array![|ii| rbs1[ii].position; 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 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( * -Vector::from(
array![|ii| if flipped[ii] { manifolds[ii].local_n2 } else { manifolds[ii].local_n1 }; SIMD_WIDTH], 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 { for k in 0..num_points {
let p1 = position1 let p1 = coll_pos1
* Point::from( * Point::from(
array![|ii| if flipped[ii] { manifold_points[ii][k].local_p2 } else { manifold_points[ii][k].local_p1 }; SIMD_WIDTH], 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( * Point::from(
array![|ii| if flipped[ii] { manifold_points[ii][k].local_p1 } else { manifold_points[ii][k].local_p2 }; SIMD_WIDTH], 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 = let impulse =
SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]); SimdFloat::from(array![|ii| manifold_points[ii][k].impulse; SIMD_WIDTH]);
let dp1 = p1.coords - position1.translation.vector; let dp1 = p1 - world_com1;
let dp2 = p2.coords - position2.translation.vector; let dp2 = p2 - world_com2;
let vel1 = linvel1 + angvel1.gcross(dp1); let vel1 = linvel1 + angvel1.gcross(dp1);
let vel2 = linvel2 + angvel2.gcross(dp2); let vel2 = linvel2 + angvel2.gcross(dp2);

View File

@@ -662,7 +662,7 @@ mod test {
let rb = RigidBodyBuilder::new_dynamic().build(); let rb = RigidBodyBuilder::new_dynamic().build();
let co = ColliderBuilder::ball(0.5).build(); let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb); 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); broad_phase.update_aabbs(0.0, &bodies, &mut colliders);
@@ -681,7 +681,7 @@ mod test {
let rb = RigidBodyBuilder::new_dynamic().build(); let rb = RigidBodyBuilder::new_dynamic().build();
let co = ColliderBuilder::ball(0.5).build(); let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb); 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. // Make sure the proxy handles is recycled properly.
broad_phase.update_aabbs(0.0, &bodies, &mut colliders); broad_phase.update_aabbs(0.0, &bodies, &mut colliders);

View File

@@ -3,7 +3,7 @@ use crate::geometry::{
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon, Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon,
Proximity, Triangle, Trimesh, Proximity, Triangle, Trimesh,
}; };
use crate::math::{Isometry, Point, Vector}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
use na::Point3; use na::Point3;
use ncollide::bounding_volume::{HasBoundingVolume, AABB}; use ncollide::bounding_volume::{HasBoundingVolume, AABB};
use num::Zero; use num::Zero;
@@ -150,6 +150,7 @@ impl Collider {
} }
/// The position of this collider expressed in the local-space of the rigid-body it is attached to. /// The position of this collider expressed in the local-space of the rigid-body it is attached to.
#[deprecated(note = "use `.position_wrt_parent()` instead.")]
pub fn delta(&self) -> &Isometry<f32> { pub fn delta(&self) -> &Isometry<f32> {
&self.delta &self.delta
} }
@@ -159,6 +160,11 @@ impl Collider {
&self.position &self.position
} }
/// The position of this collider wrt the body it is attached to.
pub fn position_wrt_parent(&self) -> &Isometry<f32> {
&self.delta
}
/// The density of this collider. /// The density of this collider.
pub fn density(&self) -> f32 { pub fn density(&self) -> f32 {
self.density self.density
@@ -347,7 +353,41 @@ impl ColliderBuilder {
self self
} }
/// Sets the initial translation of the collider to be created,
/// relative to the rigid-body it is attached to.
#[cfg(feature = "dim2")]
pub fn translation(mut self, x: f32, y: f32) -> Self {
self.delta.translation.x = x;
self.delta.translation.y = y;
self
}
/// Sets the initial translation of the collider to be created,
/// relative to the rigid-body it is attached to.
#[cfg(feature = "dim3")]
pub fn translation(mut self, x: f32, y: f32, z: f32) -> Self {
self.delta.translation.x = x;
self.delta.translation.y = y;
self.delta.translation.z = z;
self
}
/// Sets the initial orientation of the collider to be created,
/// relative to the rigid-body it is attached to.
pub fn rotation(mut self, angle: AngVector<f32>) -> Self {
self.delta.rotation = Rotation::new(angle);
self
}
/// Sets the initial position (translation and orientation) of the collider to be created,
/// relative to the rigid-body it is attached to.
pub fn position(mut self, pos: Isometry<f32>) -> Self {
self.delta = pos;
self
}
/// Set the position of this collider in the local-space of the rigid-body it is attached to. /// Set the position of this collider in the local-space of the rigid-body it is attached to.
#[deprecated(note = "Use `.position` instead.")]
pub fn delta(mut self, delta: Isometry<f32>) -> Self { pub fn delta(mut self, delta: Isometry<f32>) -> Self {
self.delta = delta; self.delta = delta;
self self

View File

@@ -47,7 +47,6 @@ impl ColliderSet {
parent_handle: RigidBodyHandle, parent_handle: RigidBodyHandle,
bodies: &mut RigidBodySet, bodies: &mut RigidBodySet,
) -> ColliderHandle { ) -> ColliderHandle {
let mass_properties = coll.mass_properties();
coll.parent = parent_handle; coll.parent = parent_handle;
let parent = bodies let parent = bodies
.get_mut_internal(parent_handle) .get_mut_internal(parent_handle)
@@ -55,9 +54,8 @@ impl ColliderSet {
coll.position = parent.position * coll.delta; coll.position = parent.position * coll.delta;
coll.predicted_position = parent.predicted_position * coll.delta; coll.predicted_position = parent.predicted_position * coll.delta;
let handle = self.colliders.insert(coll); let handle = self.colliders.insert(coll);
parent.colliders.push(handle); let coll = self.colliders.get(handle).unwrap();
parent.mass_properties += mass_properties; parent.add_collider_internal(handle, &coll);
parent.update_world_mass_properties();
bodies.activate(parent_handle); bodies.activate(parent_handle);
handle handle
} }

View File

@@ -273,16 +273,21 @@ pub struct ContactManifold {
/// The pair of subshapes involved in this contact manifold. /// The pair of subshapes involved in this contact manifold.
pub subshape_index_pair: (usize, usize), pub subshape_index_pair: (usize, usize),
pub(crate) warmstart_multiplier: f32, pub(crate) warmstart_multiplier: f32,
// We put the friction and restitution here because // The two following are set by the constraints solver.
// this avoids reading the colliders inside of the pub(crate) constraint_index: usize,
pub(crate) position_constraint_index: usize,
// We put the following fields here to avoids reading the colliders inside of the
// contact preparation method. // contact preparation method.
/// The friction coefficient for of all the contacts on this contact manifold. /// The friction coefficient for of all the contacts on this contact manifold.
pub friction: f32, pub friction: f32,
/// The restitution coefficient for all the contacts on this contact manifold. /// The restitution coefficient for all the contacts on this contact manifold.
pub restitution: f32, pub restitution: f32,
// The following are set by the constraints solver. /// The relative position between the first collider and its parent at the time the
pub(crate) constraint_index: usize, /// contact points were generated.
pub(crate) position_constraint_index: usize, pub delta1: Isometry<f32>,
/// The relative position between the second collider and its parent at the time the
/// contact points were generated.
pub delta2: Isometry<f32>,
} }
impl ContactManifold { impl ContactManifold {
@@ -290,6 +295,8 @@ impl ContactManifold {
pair: ColliderPair, pair: ColliderPair,
subshapes: (usize, usize), subshapes: (usize, usize),
body_pair: BodyPair, body_pair: BodyPair,
delta1: Isometry<f32>,
delta2: Isometry<f32>,
friction: f32, friction: f32,
restitution: f32, restitution: f32,
) -> ContactManifold { ) -> ContactManifold {
@@ -308,6 +315,8 @@ impl ContactManifold {
warmstart_multiplier: Self::min_warmstart_multiplier(), warmstart_multiplier: Self::min_warmstart_multiplier(),
friction, friction,
restitution, restitution,
delta1,
delta2,
constraint_index: 0, constraint_index: 0,
position_constraint_index: 0, position_constraint_index: 0,
} }
@@ -329,6 +338,8 @@ impl ContactManifold {
warmstart_multiplier: self.warmstart_multiplier, warmstart_multiplier: self.warmstart_multiplier,
friction: self.friction, friction: self.friction,
restitution: self.restitution, restitution: self.restitution,
delta1: self.delta1,
delta2: self.delta2,
constraint_index: self.constraint_index, constraint_index: self.constraint_index,
position_constraint_index: self.position_constraint_index, position_constraint_index: self.position_constraint_index,
} }
@@ -349,6 +360,8 @@ impl ContactManifold {
pair, pair,
(subshape1, subshape2), (subshape1, subshape2),
BodyPair::new(coll1.parent, coll2.parent), BodyPair::new(coll1.parent, coll2.parent),
*coll1.position_wrt_parent(),
*coll2.position_wrt_parent(),
(coll1.friction + coll2.friction) * 0.5, (coll1.friction + coll2.friction) * 0.5,
(coll1.restitution + coll2.restitution) * 0.5, (coll1.restitution + coll2.restitution) * 0.5,
) )
@@ -391,6 +404,7 @@ impl ContactManifold {
self.pair = self.pair.swap(); self.pair = self.pair.swap();
self.body_pair = self.body_pair.swap(); self.body_pair = self.body_pair.swap();
self.subshape_index_pair = (self.subshape_index_pair.1, self.subshape_index_pair.0); self.subshape_index_pair = (self.subshape_index_pair.1, self.subshape_index_pair.0);
std::mem::swap(&mut self.delta1, &mut self.delta2);
} }
pub(crate) fn update_warmstart_multiplier(&mut self) { pub(crate) fn update_warmstart_multiplier(&mut self) {

View File

@@ -96,7 +96,7 @@ impl NarrowPhase {
} }
// We have to manage the fact that one other collider will // We have to manage the fact that one other collider will
// hive its graph index changed because of the node's swap-remove. // have its graph index changed because of the node's swap-remove.
if let Some(replacement) = self if let Some(replacement) = self
.proximity_graph .proximity_graph
.remove_node(proximity_graph_id) .remove_node(proximity_graph_id)
@@ -129,6 +129,11 @@ impl NarrowPhase {
if let (Some(co1), Some(co2)) = if let (Some(co1), Some(co2)) =
colliders.get2_mut_internal(pair.collider1, pair.collider2) colliders.get2_mut_internal(pair.collider1, pair.collider2)
{ {
if co1.parent == co2.parent {
// Same parents. Ignore collisions.
continue;
}
if co1.is_sensor() || co2.is_sensor() { if co1.is_sensor() || co2.is_sensor() {
let gid1 = co1.proximity_graph_index; let gid1 = co1.proximity_graph_index;
let gid2 = co2.proximity_graph_index; let gid2 = co2.proximity_graph_index;

View File

@@ -7,7 +7,8 @@ use crate::dynamics::{IntegrationParameters, JointSet, RigidBody, RigidBodyHandl
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
use crate::dynamics::{JointGraphEdge, ParallelIslandSolver as IslandSolver}; use crate::dynamics::{JointGraphEdge, ParallelIslandSolver as IslandSolver};
use crate::geometry::{ use crate::geometry::{
BroadPhase, BroadPhasePairEvent, ColliderPair, ColliderSet, ContactManifoldIndex, NarrowPhase, BroadPhase, BroadPhasePairEvent, Collider, ColliderHandle, ColliderPair, ColliderSet,
ContactManifoldIndex, NarrowPhase,
}; };
use crate::math::Vector; use crate::math::Vector;
use crate::pipeline::EventHandler; use crate::pipeline::EventHandler;
@@ -245,6 +246,27 @@ impl PhysicsPipeline {
self.counters.step_completed(); self.counters.step_completed();
} }
/// Remove a collider and all its associated data.
pub fn remove_collider(
&mut self,
handle: ColliderHandle,
broad_phase: &mut BroadPhase,
narrow_phase: &mut NarrowPhase,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
) -> Option<Collider> {
broad_phase.remove_colliders(&[handle], colliders);
narrow_phase.remove_colliders(&[handle], colliders, bodies);
let collider = colliders.remove_internal(handle)?;
if let Some(parent) = bodies.get_mut_internal(collider.parent) {
parent.remove_collider_internal(handle, &collider);
bodies.wake_up(collider.parent);
}
Some(collider)
}
/// Remove a rigid-body and all its associated data. /// Remove a rigid-body and all its associated data.
pub fn remove_rigid_body( pub fn remove_rigid_body(
&mut self, &mut self,

View File

@@ -13,7 +13,7 @@ use rapier::dynamics::{
IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet, IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet,
}; };
use rapier::geometry::{Collider, ColliderSet, Shape}; use rapier::geometry::{Collider, ColliderSet, Shape};
use rapier::math::{Isometry, Vector}; use rapier::math::Vector;
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "dim3")] #[cfg(feature = "dim3")]
use {ncollide::shape::TriMesh, nphysics::joint::BallConstraint}; use {ncollide::shape::TriMesh, nphysics::joint::BallConstraint};
@@ -165,7 +165,7 @@ impl NPhysicsWorld {
for coll_handle in rb.colliders() { for coll_handle in rb.colliders() {
let collider = &mut colliders[*coll_handle]; let collider = &mut colliders[*coll_handle];
collider.set_position_debug(pos * collider.delta()); collider.set_position_debug(pos * collider.position_wrt_parent());
} }
} }
} }
@@ -176,7 +176,7 @@ fn nphysics_collider_from_rapier_collider(
is_dynamic: bool, is_dynamic: bool,
) -> Option<ColliderDesc<f32>> { ) -> Option<ColliderDesc<f32>> {
let margin = ColliderDesc::<f32>::default_margin(); let margin = ColliderDesc::<f32>::default_margin();
let mut pos = Isometry::identity(); let mut pos = *collider.position_wrt_parent();
let shape = match collider.shape() { let shape = match collider.shape() {
Shape::Cuboid(cuboid) => { Shape::Cuboid(cuboid) => {
@@ -184,7 +184,7 @@ fn nphysics_collider_from_rapier_collider(
} }
Shape::Ball(ball) => ShapeHandle::new(Ball::new(ball.radius - margin)), Shape::Ball(ball) => ShapeHandle::new(Ball::new(ball.radius - margin)),
Shape::Capsule(capsule) => { Shape::Capsule(capsule) => {
pos = capsule.transform_wrt_y(); pos *= capsule.transform_wrt_y();
ShapeHandle::new(Capsule::new(capsule.half_height(), capsule.radius)) ShapeHandle::new(Capsule::new(capsule.half_height(), capsule.radius))
} }
Shape::HeightField(heightfield) => ShapeHandle::new(heightfield.clone()), Shape::HeightField(heightfield) => ShapeHandle::new(heightfield.clone()),

View File

@@ -225,6 +225,28 @@ impl PhysxWorld {
} }
} }
// Update mass properties.
for (rapier_handle, physx_handle) in rapier2physx.iter() {
let rb = &bodies[*rapier_handle];
if let Some(rp) = scene.get_dynamic_mut(*physx_handle) {
let densities: Vec<_> = rb
.colliders()
.iter()
.map(|h| colliders[*h].density())
.collect();
unsafe {
physx_sys::PxRigidBodyExt_updateMassAndInertia_mut(
rp.as_ptr_mut().ptr as *mut physx_sys::PxRigidBody,
densities.as_ptr(),
densities.len() as u32,
std::ptr::null(),
false,
);
}
}
}
let mut res = Self { let mut res = Self {
physics, physics,
cooking, cooking,
@@ -390,7 +412,7 @@ impl PhysxWorld {
for coll_handle in rb.colliders() { for coll_handle in rb.colliders() {
let collider = &mut colliders[*coll_handle]; let collider = &mut colliders[*coll_handle];
collider.set_position_debug(iso * collider.delta()); collider.set_position_debug(iso * collider.position_wrt_parent());
} }
} }
} }
@@ -399,7 +421,7 @@ impl PhysxWorld {
fn physx_collider_from_rapier_collider( fn physx_collider_from_rapier_collider(
collider: &Collider, collider: &Collider,
) -> Option<(ColliderDesc, Isometry3<f32>)> { ) -> Option<(ColliderDesc, Isometry3<f32>)> {
let mut local_pose = Isometry3::identity(); let mut local_pose = *collider.position_wrt_parent();
let desc = match collider.shape() { let desc = match collider.shape() {
Shape::Cuboid(cuboid) => ColliderDesc::Box( Shape::Cuboid(cuboid) => ColliderDesc::Box(
cuboid.half_extents.x, cuboid.half_extents.x,
@@ -416,7 +438,7 @@ fn physx_collider_from_rapier_collider(
} }
let rot = UnitQuaternion::rotation_between(&Vector3::x(), &dir); let rot = UnitQuaternion::rotation_between(&Vector3::x(), &dir);
local_pose = local_pose *=
Translation3::from(center.coords) * rot.unwrap_or(UnitQuaternion::identity()); Translation3::from(center.coords) * rot.unwrap_or(UnitQuaternion::identity());
ColliderDesc::Capsule(capsule.radius, capsule.height()) ColliderDesc::Capsule(capsule.radius, capsule.height())
} }

View File

@@ -791,6 +791,29 @@ impl Testbed {
.state .state
.action_flags .action_flags
.set(TestbedActionFlags::EXAMPLE_CHANGED, true), .set(TestbedActionFlags::EXAMPLE_CHANGED, true),
WindowEvent::Key(Key::C, Action::Release, _) => {
// Delete 1 collider of 10% of the remaining dynamic bodies.
let mut colliders: Vec<_> = self
.physics
.bodies
.iter()
.filter(|e| e.1.is_dynamic())
.filter(|e| !e.1.colliders().is_empty())
.map(|e| e.1.colliders().to_vec())
.collect();
colliders.sort_by_key(|co| -(co.len() as isize));
let num_to_delete = (colliders.len() / 10).max(1);
for to_delete in &colliders[..num_to_delete] {
self.physics.pipeline.remove_collider(
to_delete[0],
&mut self.physics.broad_phase,
&mut self.physics.narrow_phase,
&mut self.physics.bodies,
&mut self.physics.colliders,
);
}
}
WindowEvent::Key(Key::D, Action::Release, _) => { WindowEvent::Key(Key::D, Action::Release, _) => {
// Delete 10% of the remaining dynamic bodies. // Delete 10% of the remaining dynamic bodies.
let dynamic_bodies: Vec<_> = self let dynamic_bodies: Vec<_> = self
@@ -1539,7 +1562,7 @@ impl State for Testbed {
} }
if self.state.flags.contains(TestbedStateFlags::CONTACT_POINTS) { if self.state.flags.contains(TestbedStateFlags::CONTACT_POINTS) {
draw_contacts(window, &self.physics.narrow_phase, &self.physics.bodies); draw_contacts(window, &self.physics.narrow_phase, &self.physics.colliders);
} }
if self.state.running == RunMode::Step { if self.state.running == RunMode::Step {
@@ -1634,7 +1657,7 @@ Hashes at frame: {}
} }
} }
fn draw_contacts(window: &mut Window, nf: &NarrowPhase, bodies: &RigidBodySet) { fn draw_contacts(window: &mut Window, nf: &NarrowPhase, colliders: &ColliderSet) {
for (_, _, pair) in nf.contact_graph().interaction_pairs() { for (_, _, pair) in nf.contact_graph().interaction_pairs() {
for manifold in &pair.manifolds { for manifold in &pair.manifolds {
for pt in manifold.all_contacts() { for pt in manifold.all_contacts() {
@@ -1643,8 +1666,8 @@ fn draw_contacts(window: &mut Window, nf: &NarrowPhase, bodies: &RigidBodySet) {
} else { } else {
Point3::new(1.0, 0.0, 0.0) Point3::new(1.0, 0.0, 0.0)
}; };
let pos1 = bodies[manifold.body_pair.body1].position; let pos1 = colliders[manifold.pair.collider1].position();
let pos2 = bodies[manifold.body_pair.body2].position; let pos2 = colliders[manifold.pair.collider2].position();
let start = pos1 * pt.local_p1; let start = pos1 * pt.local_p1;
let end = pos2 * pt.local_p2; let end = pos2 * pt.local_p2;
let n = pos1 * manifold.local_n1; let n = pos1 * manifold.local_n1;