Allow several rules for combining friction/restitution coefficients.
This commit is contained in:
34
src/dynamics/coefficient_combine_rule.rs
Normal file
34
src/dynamics/coefficient_combine_rule.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use crate::math::Real;
|
||||||
|
|
||||||
|
/// Rules used to combine two coefficients.
|
||||||
|
///
|
||||||
|
/// This is used to determine the effective restitution and
|
||||||
|
/// friction coefficients for a contact between two colliders.
|
||||||
|
/// Each collider has its combination rule of type
|
||||||
|
/// `CoefficientCombineRule`. And the rule
|
||||||
|
/// actually used is given by `max(first_combine_rule as usize, second_combine_rule as usize)`.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
|
pub enum CoefficientCombineRule {
|
||||||
|
/// The two coefficients are averaged.
|
||||||
|
Average = 0,
|
||||||
|
/// The smallest coefficient is chosen.
|
||||||
|
Min,
|
||||||
|
/// The two coefficients are multiplied.
|
||||||
|
Multiply,
|
||||||
|
/// The greatest coefficient is chosen.
|
||||||
|
Max,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CoefficientCombineRule {
|
||||||
|
pub(crate) fn combine(coeff1: Real, coeff2: Real, rule_value1: u8, rule_value2: u8) -> Real {
|
||||||
|
let effective_rule = rule_value1.max(rule_value2);
|
||||||
|
|
||||||
|
match effective_rule {
|
||||||
|
0 => (coeff1 + coeff1) / 2.0,
|
||||||
|
1 => coeff1.min(coeff2),
|
||||||
|
2 => coeff1 * coeff2,
|
||||||
|
_ => coeff1.max(coeff2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ pub use self::rigid_body::{ActivationStatus, BodyStatus, RigidBody, RigidBodyBui
|
|||||||
pub use self::rigid_body_set::{BodyPair, RigidBodyHandle, RigidBodySet};
|
pub use self::rigid_body_set::{BodyPair, RigidBodyHandle, RigidBodySet};
|
||||||
pub use cdl::mass_properties::MassProperties;
|
pub use cdl::mass_properties::MassProperties;
|
||||||
// #[cfg(not(feature = "parallel"))]
|
// #[cfg(not(feature = "parallel"))]
|
||||||
|
pub use self::coefficient_combine_rule::CoefficientCombineRule;
|
||||||
pub(crate) use self::joint::JointGraphEdge;
|
pub(crate) use self::joint::JointGraphEdge;
|
||||||
pub(crate) use self::rigid_body::RigidBodyChanges;
|
pub(crate) use self::rigid_body::RigidBodyChanges;
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
@@ -18,6 +19,7 @@ pub(crate) use self::solver::IslandSolver;
|
|||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
pub(crate) use self::solver::ParallelIslandSolver;
|
pub(crate) use self::solver::ParallelIslandSolver;
|
||||||
|
|
||||||
|
mod coefficient_combine_rule;
|
||||||
mod integration_parameters;
|
mod integration_parameters;
|
||||||
mod joint;
|
mod joint;
|
||||||
mod rigid_body;
|
mod rigid_body;
|
||||||
|
|||||||
@@ -62,8 +62,10 @@ pub struct RigidBody {
|
|||||||
pub(crate) mass_properties: MassProperties,
|
pub(crate) mass_properties: MassProperties,
|
||||||
/// The world-space center of mass of the rigid-body.
|
/// The world-space center of mass of the rigid-body.
|
||||||
pub world_com: Point<Real>,
|
pub world_com: Point<Real>,
|
||||||
|
/// The inverse mass taking into account translation locking.
|
||||||
pub effective_inv_mass: Real,
|
pub effective_inv_mass: Real,
|
||||||
/// The square-root of the inverse angular inertia tensor of the rigid-body.
|
/// The square-root of the world-space inverse angular inertia tensor of the rigid-body,
|
||||||
|
/// taking into account rotation locking.
|
||||||
pub effective_world_inv_inertia_sqrt: AngularInertia<Real>,
|
pub effective_world_inv_inertia_sqrt: AngularInertia<Real>,
|
||||||
/// The linear velocity of the rigid-body.
|
/// The linear velocity of the rigid-body.
|
||||||
pub(crate) linvel: Vector<Real>,
|
pub(crate) linvel: Vector<Real>,
|
||||||
|
|||||||
@@ -1,309 +1,44 @@
|
|||||||
use crate::dynamics::{MassProperties, RigidBodyHandle};
|
use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle};
|
||||||
use crate::geometry::InteractionGroups;
|
use crate::geometry::{ColliderShape, InteractionGroups};
|
||||||
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector};
|
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector};
|
||||||
use cdl::bounding_volume::AABB;
|
use cdl::bounding_volume::AABB;
|
||||||
use cdl::shape::{
|
use cdl::shape::Shape;
|
||||||
Ball, Capsule, Compound, Cuboid, HalfSpace, HeightField, RoundCuboid, RoundShape,
|
|
||||||
RoundTriangle, Segment, Shape, ShapeType, TriMesh, Triangle,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
use cdl::shape::{
|
|
||||||
Cone, ConvexPolyhedron, Cylinder, RoundCone, RoundConvexPolyhedron, RoundCylinder,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
use cdl::shape::{ConvexPolygon, RoundConvexPolygon};
|
use cdl::shape::{ConvexPolygon, RoundConvexPolygon};
|
||||||
use std::ops::Deref;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
// TODO: move this to its own file.
|
bitflags::bitflags! {
|
||||||
/// The shape of a collider.
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
#[derive(Clone)]
|
/// Flags affecting the behavior of the constraints solver for a given contact manifold.
|
||||||
pub struct ColliderShape(pub Arc<dyn Shape>);
|
pub(crate) struct ColliderFlags: u8 {
|
||||||
|
const SENSOR = 1 << 0;
|
||||||
impl Deref for ColliderShape {
|
const FRICTION_COMBINE_RULE_01 = 1 << 1;
|
||||||
type Target = dyn Shape;
|
const FRICTION_COMBINE_RULE_10 = 1 << 2;
|
||||||
fn deref(&self) -> &dyn Shape {
|
const RESTITUTION_COMBINE_RULE_01 = 1 << 3;
|
||||||
&*self.0
|
const RESTITUTION_COMBINE_RULE_10 = 1 << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColliderShape {
|
impl ColliderFlags {
|
||||||
/// Initialize a compound shape defined by its subshapes.
|
pub fn is_sensor(self) -> bool {
|
||||||
pub fn compound(shapes: Vec<(Isometry<Real>, ColliderShape)>) -> Self {
|
self.contains(ColliderFlags::SENSOR)
|
||||||
let raw_shapes = shapes.into_iter().map(|s| (s.0, s.1 .0)).collect();
|
|
||||||
let compound = Compound::new(raw_shapes);
|
|
||||||
ColliderShape(Arc::new(compound))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a ball shape defined by its radius.
|
pub fn friction_combine_rule_value(self) -> u8 {
|
||||||
pub fn ball(radius: Real) -> Self {
|
(self.bits & 0b0000_0110) >> 1
|
||||||
ColliderShape(Arc::new(Ball::new(radius)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a cylindrical shape defined by its half-height
|
pub fn restitution_combine_rule_value(self) -> u8 {
|
||||||
/// (along along the y axis) and its radius.
|
(self.bits & 0b0001_1000) >> 3
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn cylinder(half_height: Real, radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(Cylinder::new(half_height, radius)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a rounded cylindrical shape defined by its half-height
|
pub fn with_friction_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
|
||||||
/// (along along the y axis), its radius, and its roundedness (the
|
self.bits = (self.bits & !0b0000_0110) | ((rule as u8) << 1);
|
||||||
/// radius of the sphere used for dilating the cylinder).
|
self
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: Cylinder::new(half_height, radius),
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a rounded cone shape defined by its half-height
|
pub fn with_restitution_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
|
||||||
/// (along along the y axis), its radius, and its roundedness (the
|
self.bits = (self.bits & !0b0001_1000) | ((rule as u8) << 3);
|
||||||
/// radius of the sphere used for dilating the cylinder).
|
self
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: Cone::new(half_height, radius),
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a cone shape defined by its half-height
|
|
||||||
/// (along along the y axis) and its basis radius.
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn cone(half_height: Real, radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(Cone::new(half_height, radius)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a cuboid shape defined by its half-extents.
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
pub fn cuboid(hx: Real, hy: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(Cuboid::new(Vector::new(hx, hy))))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a round cuboid shape defined by its half-extents and border radius.
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
pub fn round_cuboid(hx: Real, hy: Real, border_radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: Cuboid::new(Vector::new(hx, hy)),
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a cuboid shape defined by its half-extents.
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn cuboid(hx: Real, hy: Real, hz: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(Cuboid::new(Vector::new(hx, hy, hz))))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a round cuboid shape defined by its half-extents and border radius.
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn round_cuboid(hx: Real, hy: Real, hz: Real, border_radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: Cuboid::new(Vector::new(hx, hy, hz)),
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a capsule shape from its endpoints and radius.
|
|
||||||
pub fn capsule(a: Point<Real>, b: Point<Real>, radius: Real) -> Self {
|
|
||||||
ColliderShape(Arc::new(Capsule::new(a, b, radius)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a segment shape from its endpoints.
|
|
||||||
pub fn segment(a: Point<Real>, b: Point<Real>) -> Self {
|
|
||||||
ColliderShape(Arc::new(Segment::new(a, b)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes a triangle shape.
|
|
||||||
pub fn triangle(a: Point<Real>, b: Point<Real>, c: Point<Real>) -> Self {
|
|
||||||
ColliderShape(Arc::new(Triangle::new(a, b, c)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes a triangle mesh shape defined by its vertex and index buffers.
|
|
||||||
pub fn trimesh(vertices: Vec<Point<Real>>, indices: Vec<[u32; 3]>) -> Self {
|
|
||||||
ColliderShape(Arc::new(TriMesh::new(vertices, indices)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn convex_hull(points: &[Point<Real>]) -> Option<Self> {
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
return ConvexPolygon::from_convex_hull(points).map(|ch| ColliderShape(Arc::new(ch)));
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
return ConvexPolyhedron::from_convex_hull(points).map(|ch| ColliderShape(Arc::new(ch)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
pub fn convex_polyline(points: Vec<Point<Real>>) -> Option<Self> {
|
|
||||||
ConvexPolygon::from_convex_polyline(points).map(|ch| ColliderShape(Arc::new(ch)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn convex_mesh(points: Vec<Point<Real>>, indices: &[[u32; 3]]) -> Option<Self> {
|
|
||||||
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| ColliderShape(Arc::new(ch)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn round_convex_hull(points: &[Point<Real>], border_radius: Real) -> Option<Self> {
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
return ConvexPolygon::from_convex_hull(points).map(|ch| {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: ch,
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
return ConvexPolyhedron::from_convex_hull(points).map(|ch| {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: ch,
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
pub fn round_convex_polyline(points: Vec<Point<Real>>, border_radius: Real) -> Option<Self> {
|
|
||||||
ConvexPolygon::from_convex_polyline(points).map(|ch| {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: ch,
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn round_convex_mesh(
|
|
||||||
points: Vec<Point<Real>>,
|
|
||||||
indices: &[[u32; 3]],
|
|
||||||
border_radius: Real,
|
|
||||||
) -> Option<Self> {
|
|
||||||
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| {
|
|
||||||
ColliderShape(Arc::new(RoundShape {
|
|
||||||
base_shape: ch,
|
|
||||||
border_radius,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes an heightfield shape defined by its set of height and a scale
|
|
||||||
/// factor along each coordinate axis.
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
pub fn heightfield(heights: na::DVector<Real>, scale: Vector<Real>) -> Self {
|
|
||||||
ColliderShape(Arc::new(HeightField::new(heights, scale)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes an heightfield shape on the x-z plane defined by its set of height and a scale
|
|
||||||
/// factor along each coordinate axis.
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
pub fn heightfield(heights: na::DMatrix<Real>, scale: Vector<Real>) -> Self {
|
|
||||||
ColliderShape(Arc::new(HeightField::new(heights, scale)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
|
||||||
impl serde::Serialize for ColliderShape {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
use crate::serde::ser::SerializeStruct;
|
|
||||||
|
|
||||||
if let Some(ser) = self.0.as_serialize() {
|
|
||||||
let typ = self.0.shape_type();
|
|
||||||
let mut state = serializer.serialize_struct("ColliderShape", 2)?;
|
|
||||||
state.serialize_field("tag", &(typ as i32))?;
|
|
||||||
state.serialize_field("inner", ser)?;
|
|
||||||
state.end()
|
|
||||||
} else {
|
|
||||||
Err(serde::ser::Error::custom(
|
|
||||||
"Found a non-serializable custom shape.",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
|
||||||
impl<'de> serde::Deserialize<'de> for ColliderShape {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct Visitor {};
|
|
||||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
|
||||||
type Value = ColliderShape;
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(formatter, "one shape type tag and the inner shape data")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
|
||||||
where
|
|
||||||
A: serde::de::SeqAccess<'de>,
|
|
||||||
{
|
|
||||||
use num::cast::FromPrimitive;
|
|
||||||
|
|
||||||
let tag: i32 = seq
|
|
||||||
.next_element()?
|
|
||||||
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
|
||||||
|
|
||||||
fn deser<'de, A, S: Shape + serde::Deserialize<'de>>(
|
|
||||||
seq: &mut A,
|
|
||||||
) -> Result<Arc<dyn Shape>, A::Error>
|
|
||||||
where
|
|
||||||
A: serde::de::SeqAccess<'de>,
|
|
||||||
{
|
|
||||||
let shape: S = seq.next_element()?.ok_or_else(|| {
|
|
||||||
serde::de::Error::custom("Failed to deserialize builtin shape.")
|
|
||||||
})?;
|
|
||||||
Ok(Arc::new(shape) as Arc<dyn Shape>)
|
|
||||||
}
|
|
||||||
|
|
||||||
let shape = match ShapeType::from_i32(tag) {
|
|
||||||
Some(ShapeType::Ball) => deser::<A, Ball>(&mut seq)?,
|
|
||||||
Some(ShapeType::Cuboid) => deser::<A, Cuboid>(&mut seq)?,
|
|
||||||
Some(ShapeType::Capsule) => deser::<A, Capsule>(&mut seq)?,
|
|
||||||
Some(ShapeType::Triangle) => deser::<A, Triangle>(&mut seq)?,
|
|
||||||
Some(ShapeType::Segment) => deser::<A, Segment>(&mut seq)?,
|
|
||||||
Some(ShapeType::TriMesh) => deser::<A, TriMesh>(&mut seq)?,
|
|
||||||
Some(ShapeType::HeightField) => deser::<A, HeightField>(&mut seq)?,
|
|
||||||
Some(ShapeType::HalfSpace) => deser::<A, HalfSpace>(&mut seq)?,
|
|
||||||
Some(ShapeType::RoundCuboid) => deser::<A, RoundCuboid>(&mut seq)?,
|
|
||||||
Some(ShapeType::RoundTriangle) => deser::<A, RoundTriangle>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
Some(ShapeType::ConvexPolygon) => deser::<A, ConvexPolygon>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
Some(ShapeType::RoundConvexPolygon) => {
|
|
||||||
deser::<A, RoundConvexPolygon>(&mut seq)?
|
|
||||||
}
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::Cylinder) => deser::<A, Cylinder>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::ConvexPolyhedron) => deser::<A, ConvexPolyhedron>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::Cone) => deser::<A, Cone>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::RoundCylinder) => deser::<A, RoundCylinder>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::RoundCone) => deser::<A, RoundCone>(&mut seq)?,
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Some(ShapeType::RoundConvexPolyhedron) => {
|
|
||||||
deser::<A, RoundConvexPolyhedron>(&mut seq)?
|
|
||||||
}
|
|
||||||
Some(ShapeType::Compound) => {
|
|
||||||
return Err(serde::de::Error::custom(
|
|
||||||
"found invalid shape type to deserialize",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(serde::de::Error::custom(
|
|
||||||
"found invalid shape type to deserialize",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ColliderShape(shape))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +50,7 @@ impl<'de> serde::Deserialize<'de> for ColliderShape {
|
|||||||
pub struct Collider {
|
pub struct Collider {
|
||||||
shape: ColliderShape,
|
shape: ColliderShape,
|
||||||
density: Real,
|
density: Real,
|
||||||
is_sensor: bool,
|
pub(crate) flags: ColliderFlags,
|
||||||
pub(crate) parent: RigidBodyHandle,
|
pub(crate) parent: RigidBodyHandle,
|
||||||
pub(crate) delta: Isometry<Real>,
|
pub(crate) delta: Isometry<Real>,
|
||||||
pub(crate) position: Isometry<Real>,
|
pub(crate) position: Isometry<Real>,
|
||||||
@@ -344,7 +79,7 @@ impl Collider {
|
|||||||
|
|
||||||
/// Is this collider a sensor?
|
/// Is this collider a sensor?
|
||||||
pub fn is_sensor(&self) -> bool {
|
pub fn is_sensor(&self) -> bool {
|
||||||
self.is_sensor
|
self.flags.is_sensor()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@@ -415,8 +150,12 @@ pub struct ColliderBuilder {
|
|||||||
density: Option<Real>,
|
density: Option<Real>,
|
||||||
/// The friction coefficient of the collider to be built.
|
/// The friction coefficient of the collider to be built.
|
||||||
pub friction: Real,
|
pub friction: Real,
|
||||||
|
/// The rule used to combine two friction coefficients.
|
||||||
|
pub friction_combine_rule: CoefficientCombineRule,
|
||||||
/// The restitution coefficient of the collider to be built.
|
/// The restitution coefficient of the collider to be built.
|
||||||
pub restitution: Real,
|
pub restitution: Real,
|
||||||
|
/// The rule used to combine two restitution coefficients.
|
||||||
|
pub restitution_combine_rule: CoefficientCombineRule,
|
||||||
/// The position of this collider relative to the local frame of the rigid-body it is attached to.
|
/// The position of this collider relative to the local frame of the rigid-body it is attached to.
|
||||||
pub delta: Isometry<Real>,
|
pub delta: Isometry<Real>,
|
||||||
/// Is this collider a sensor?
|
/// Is this collider a sensor?
|
||||||
@@ -442,6 +181,8 @@ impl ColliderBuilder {
|
|||||||
user_data: 0,
|
user_data: 0,
|
||||||
collision_groups: InteractionGroups::all(),
|
collision_groups: InteractionGroups::all(),
|
||||||
solver_groups: InteractionGroups::all(),
|
solver_groups: InteractionGroups::all(),
|
||||||
|
friction_combine_rule: CoefficientCombineRule::Average,
|
||||||
|
restitution_combine_rule: CoefficientCombineRule::Average,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,12 +386,24 @@ impl ColliderBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the rule to be used to combine two friction coefficients in a contact.
|
||||||
|
pub fn friction_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
|
||||||
|
self.friction_combine_rule = rule;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the restitution coefficient of the collider this builder will build.
|
/// Sets the restitution coefficient of the collider this builder will build.
|
||||||
pub fn restitution(mut self, restitution: Real) -> Self {
|
pub fn restitution(mut self, restitution: Real) -> Self {
|
||||||
self.restitution = restitution;
|
self.restitution = restitution;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the rule to be used to combine two restitution coefficients in a contact.
|
||||||
|
pub fn restitution_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
|
||||||
|
self.restitution_combine_rule = rule;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the density of the collider this builder will build.
|
/// Sets the density of the collider this builder will build.
|
||||||
pub fn density(mut self, density: Real) -> Self {
|
pub fn density(mut self, density: Real) -> Self {
|
||||||
self.density = Some(density);
|
self.density = Some(density);
|
||||||
@@ -700,6 +453,11 @@ impl ColliderBuilder {
|
|||||||
/// Builds a new collider attached to the given rigid-body.
|
/// Builds a new collider attached to the given rigid-body.
|
||||||
pub fn build(&self) -> Collider {
|
pub fn build(&self) -> Collider {
|
||||||
let density = self.get_density();
|
let density = self.get_density();
|
||||||
|
let mut flags = ColliderFlags::empty();
|
||||||
|
flags.set(ColliderFlags::SENSOR, self.is_sensor);
|
||||||
|
flags = flags
|
||||||
|
.with_friction_combine_rule(self.friction_combine_rule)
|
||||||
|
.with_restitution_combine_rule(self.restitution_combine_rule);
|
||||||
|
|
||||||
Collider {
|
Collider {
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
@@ -707,7 +465,7 @@ impl ColliderBuilder {
|
|||||||
friction: self.friction,
|
friction: self.friction,
|
||||||
restitution: self.restitution,
|
restitution: self.restitution,
|
||||||
delta: self.delta,
|
delta: self.delta,
|
||||||
is_sensor: self.is_sensor,
|
flags,
|
||||||
parent: RigidBodyHandle::invalid(),
|
parent: RigidBodyHandle::invalid(),
|
||||||
position: Isometry::identity(),
|
position: Isometry::identity(),
|
||||||
predicted_position: Isometry::identity(),
|
predicted_position: Isometry::identity(),
|
||||||
|
|||||||
304
src/geometry/collider_shape.rs
Normal file
304
src/geometry/collider_shape.rs
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
use crate::math::{Isometry, Point, Real, Vector};
|
||||||
|
use cdl::shape::{
|
||||||
|
Ball, Capsule, Compound, Cuboid, HalfSpace, HeightField, RoundCuboid, RoundShape,
|
||||||
|
RoundTriangle, Segment, Shape, ShapeType, TriMesh, Triangle,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
use cdl::shape::{
|
||||||
|
Cone, ConvexPolyhedron, Cylinder, RoundCone, RoundConvexPolyhedron, RoundCylinder,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
use cdl::shape::{ConvexPolygon, RoundConvexPolygon};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// The shape of a collider.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ColliderShape(pub Arc<dyn Shape>);
|
||||||
|
|
||||||
|
impl Deref for ColliderShape {
|
||||||
|
type Target = dyn Shape;
|
||||||
|
fn deref(&self) -> &dyn Shape {
|
||||||
|
&*self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColliderShape {
|
||||||
|
/// Initialize a compound shape defined by its subshapes.
|
||||||
|
pub fn compound(shapes: Vec<(Isometry<Real>, ColliderShape)>) -> Self {
|
||||||
|
let raw_shapes = shapes.into_iter().map(|s| (s.0, s.1 .0)).collect();
|
||||||
|
let compound = Compound::new(raw_shapes);
|
||||||
|
ColliderShape(Arc::new(compound))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a ball shape defined by its radius.
|
||||||
|
pub fn ball(radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Ball::new(radius)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a cylindrical shape defined by its half-height
|
||||||
|
/// (along along the y axis) and its radius.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn cylinder(half_height: Real, radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Cylinder::new(half_height, radius)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a rounded cylindrical shape defined by its half-height
|
||||||
|
/// (along along the y axis), its radius, and its roundedness (the
|
||||||
|
/// radius of the sphere used for dilating the cylinder).
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: Cylinder::new(half_height, radius),
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a rounded cone shape defined by its half-height
|
||||||
|
/// (along along the y axis), its radius, and its roundedness (the
|
||||||
|
/// radius of the sphere used for dilating the cylinder).
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: Cone::new(half_height, radius),
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a cone shape defined by its half-height
|
||||||
|
/// (along along the y axis) and its basis radius.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn cone(half_height: Real, radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Cone::new(half_height, radius)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a cuboid shape defined by its half-extents.
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
pub fn cuboid(hx: Real, hy: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Cuboid::new(Vector::new(hx, hy))))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a round cuboid shape defined by its half-extents and border radius.
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
pub fn round_cuboid(hx: Real, hy: Real, border_radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: Cuboid::new(Vector::new(hx, hy)),
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a cuboid shape defined by its half-extents.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn cuboid(hx: Real, hy: Real, hz: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Cuboid::new(Vector::new(hx, hy, hz))))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a round cuboid shape defined by its half-extents and border radius.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn round_cuboid(hx: Real, hy: Real, hz: Real, border_radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: Cuboid::new(Vector::new(hx, hy, hz)),
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a capsule shape from its endpoints and radius.
|
||||||
|
pub fn capsule(a: Point<Real>, b: Point<Real>, radius: Real) -> Self {
|
||||||
|
ColliderShape(Arc::new(Capsule::new(a, b, radius)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a segment shape from its endpoints.
|
||||||
|
pub fn segment(a: Point<Real>, b: Point<Real>) -> Self {
|
||||||
|
ColliderShape(Arc::new(Segment::new(a, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes a triangle shape.
|
||||||
|
pub fn triangle(a: Point<Real>, b: Point<Real>, c: Point<Real>) -> Self {
|
||||||
|
ColliderShape(Arc::new(Triangle::new(a, b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes a triangle mesh shape defined by its vertex and index buffers.
|
||||||
|
pub fn trimesh(vertices: Vec<Point<Real>>, indices: Vec<[u32; 3]>) -> Self {
|
||||||
|
ColliderShape(Arc::new(TriMesh::new(vertices, indices)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convex_hull(points: &[Point<Real>]) -> Option<Self> {
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
return ConvexPolygon::from_convex_hull(points).map(|ch| ColliderShape(Arc::new(ch)));
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
return ConvexPolyhedron::from_convex_hull(points).map(|ch| ColliderShape(Arc::new(ch)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
pub fn convex_polyline(points: Vec<Point<Real>>) -> Option<Self> {
|
||||||
|
ConvexPolygon::from_convex_polyline(points).map(|ch| ColliderShape(Arc::new(ch)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn convex_mesh(points: Vec<Point<Real>>, indices: &[[u32; 3]]) -> Option<Self> {
|
||||||
|
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| ColliderShape(Arc::new(ch)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn round_convex_hull(points: &[Point<Real>], border_radius: Real) -> Option<Self> {
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
return ConvexPolygon::from_convex_hull(points).map(|ch| {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: ch,
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
return ConvexPolyhedron::from_convex_hull(points).map(|ch| {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: ch,
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
pub fn round_convex_polyline(points: Vec<Point<Real>>, border_radius: Real) -> Option<Self> {
|
||||||
|
ConvexPolygon::from_convex_polyline(points).map(|ch| {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: ch,
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn round_convex_mesh(
|
||||||
|
points: Vec<Point<Real>>,
|
||||||
|
indices: &[[u32; 3]],
|
||||||
|
border_radius: Real,
|
||||||
|
) -> Option<Self> {
|
||||||
|
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| {
|
||||||
|
ColliderShape(Arc::new(RoundShape {
|
||||||
|
base_shape: ch,
|
||||||
|
border_radius,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes an heightfield shape defined by its set of height and a scale
|
||||||
|
/// factor along each coordinate axis.
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
pub fn heightfield(heights: na::DVector<Real>, scale: Vector<Real>) -> Self {
|
||||||
|
ColliderShape(Arc::new(HeightField::new(heights, scale)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes an heightfield shape on the x-z plane defined by its set of height and a scale
|
||||||
|
/// factor along each coordinate axis.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
pub fn heightfield(heights: na::DMatrix<Real>, scale: Vector<Real>) -> Self {
|
||||||
|
ColliderShape(Arc::new(HeightField::new(heights, scale)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
impl serde::Serialize for ColliderShape {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use crate::serde::ser::SerializeStruct;
|
||||||
|
|
||||||
|
if let Some(ser) = self.0.as_serialize() {
|
||||||
|
let typ = self.0.shape_type();
|
||||||
|
let mut state = serializer.serialize_struct("ColliderShape", 2)?;
|
||||||
|
state.serialize_field("tag", &(typ as i32))?;
|
||||||
|
state.serialize_field("inner", ser)?;
|
||||||
|
state.end()
|
||||||
|
} else {
|
||||||
|
Err(serde::ser::Error::custom(
|
||||||
|
"Found a non-serializable custom shape.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
impl<'de> serde::Deserialize<'de> for ColliderShape {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor {};
|
||||||
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
|
type Value = ColliderShape;
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(formatter, "one shape type tag and the inner shape data")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: serde::de::SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
use num::cast::FromPrimitive;
|
||||||
|
|
||||||
|
let tag: i32 = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
|
||||||
|
fn deser<'de, A, S: Shape + serde::Deserialize<'de>>(
|
||||||
|
seq: &mut A,
|
||||||
|
) -> Result<Arc<dyn Shape>, A::Error>
|
||||||
|
where
|
||||||
|
A: serde::de::SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let shape: S = seq.next_element()?.ok_or_else(|| {
|
||||||
|
serde::de::Error::custom("Failed to deserialize builtin shape.")
|
||||||
|
})?;
|
||||||
|
Ok(Arc::new(shape) as Arc<dyn Shape>)
|
||||||
|
}
|
||||||
|
|
||||||
|
let shape = match ShapeType::from_i32(tag) {
|
||||||
|
Some(ShapeType::Ball) => deser::<A, Ball>(&mut seq)?,
|
||||||
|
Some(ShapeType::Cuboid) => deser::<A, Cuboid>(&mut seq)?,
|
||||||
|
Some(ShapeType::Capsule) => deser::<A, Capsule>(&mut seq)?,
|
||||||
|
Some(ShapeType::Triangle) => deser::<A, Triangle>(&mut seq)?,
|
||||||
|
Some(ShapeType::Segment) => deser::<A, Segment>(&mut seq)?,
|
||||||
|
Some(ShapeType::TriMesh) => deser::<A, TriMesh>(&mut seq)?,
|
||||||
|
Some(ShapeType::HeightField) => deser::<A, HeightField>(&mut seq)?,
|
||||||
|
Some(ShapeType::HalfSpace) => deser::<A, HalfSpace>(&mut seq)?,
|
||||||
|
Some(ShapeType::RoundCuboid) => deser::<A, RoundCuboid>(&mut seq)?,
|
||||||
|
Some(ShapeType::RoundTriangle) => deser::<A, RoundTriangle>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
Some(ShapeType::ConvexPolygon) => deser::<A, ConvexPolygon>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
Some(ShapeType::RoundConvexPolygon) => {
|
||||||
|
deser::<A, RoundConvexPolygon>(&mut seq)?
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::Cylinder) => deser::<A, Cylinder>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::ConvexPolyhedron) => deser::<A, ConvexPolyhedron>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::Cone) => deser::<A, Cone>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::RoundCylinder) => deser::<A, RoundCylinder>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::RoundCone) => deser::<A, RoundCone>(&mut seq)?,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::RoundConvexPolyhedron) => {
|
||||||
|
deser::<A, RoundConvexPolyhedron>(&mut seq)?
|
||||||
|
}
|
||||||
|
Some(ShapeType::Compound) => {
|
||||||
|
return Err(serde::de::Error::custom(
|
||||||
|
"found invalid shape type to deserialize",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(serde::de::Error::custom(
|
||||||
|
"found invalid shape type to deserialize",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ColliderShape(shape))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
//! Structures related to geometry: colliders, shapes, etc.
|
//! Structures related to geometry: colliders, shapes, etc.
|
||||||
|
|
||||||
pub use self::broad_phase_multi_sap::BroadPhase;
|
pub use self::broad_phase_multi_sap::BroadPhase;
|
||||||
pub use self::collider::{Collider, ColliderBuilder, ColliderShape};
|
pub use self::collider::{Collider, ColliderBuilder};
|
||||||
pub use self::collider_set::{ColliderHandle, ColliderSet};
|
pub use self::collider_set::{ColliderHandle, ColliderSet};
|
||||||
|
pub use self::collider_shape::ColliderShape;
|
||||||
pub use self::contact_pair::{ContactData, ContactManifoldData};
|
pub use self::contact_pair::{ContactData, ContactManifoldData};
|
||||||
pub use self::contact_pair::{ContactPair, SolverContact, SolverFlags};
|
pub use self::contact_pair::{ContactPair, SolverContact, SolverFlags};
|
||||||
pub use self::interaction_graph::{
|
pub use self::interaction_graph::{
|
||||||
ColliderGraphIndex, InteractionGraph, RigidBodyGraphIndex, TemporaryInteractionIndex,
|
ColliderGraphIndex, InteractionGraph, RigidBodyGraphIndex, TemporaryInteractionIndex,
|
||||||
};
|
};
|
||||||
|
pub use self::interaction_groups::InteractionGroups;
|
||||||
pub use self::narrow_phase::NarrowPhase;
|
pub use self::narrow_phase::NarrowPhase;
|
||||||
pub use self::pair_filter::{ContactPairFilter, PairFilterContext, ProximityPairFilter};
|
pub use self::pair_filter::{ContactPairFilter, PairFilterContext, ProximityPairFilter};
|
||||||
|
|
||||||
@@ -81,7 +83,6 @@ impl IntersectionEvent {
|
|||||||
|
|
||||||
pub(crate) use self::broad_phase_multi_sap::{BroadPhasePairEvent, ColliderPair};
|
pub(crate) use self::broad_phase_multi_sap::{BroadPhasePairEvent, ColliderPair};
|
||||||
pub(crate) use self::collider_set::RemovedCollider;
|
pub(crate) use self::collider_set::RemovedCollider;
|
||||||
pub use self::interaction_groups::InteractionGroups;
|
|
||||||
pub(crate) use self::narrow_phase::ContactManifoldIndex;
|
pub(crate) use self::narrow_phase::ContactManifoldIndex;
|
||||||
pub(crate) use cdl::partitioning::SimdQuadTree;
|
pub(crate) use cdl::partitioning::SimdQuadTree;
|
||||||
pub use cdl::shape::*;
|
pub use cdl::shape::*;
|
||||||
@@ -98,6 +99,7 @@ pub(crate) fn default_query_dispatcher() -> std::sync::Arc<dyn cdl::query::Query
|
|||||||
mod broad_phase_multi_sap;
|
mod broad_phase_multi_sap;
|
||||||
mod collider;
|
mod collider;
|
||||||
mod collider_set;
|
mod collider_set;
|
||||||
|
mod collider_shape;
|
||||||
mod contact_pair;
|
mod contact_pair;
|
||||||
mod interaction_graph;
|
mod interaction_graph;
|
||||||
mod interaction_groups;
|
mod interaction_groups;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use rayon::prelude::*;
|
|||||||
|
|
||||||
use crate::data::pubsub::Subscription;
|
use crate::data::pubsub::Subscription;
|
||||||
use crate::data::Coarena;
|
use crate::data::Coarena;
|
||||||
use crate::dynamics::{BodyPair, RigidBodySet};
|
use crate::dynamics::{BodyPair, CoefficientCombineRule, RigidBodySet};
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactData, ContactEvent,
|
BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactData, ContactEvent,
|
||||||
ContactManifoldData, ContactPairFilter, IntersectionEvent, PairFilterContext,
|
ContactManifoldData, ContactPairFilter, IntersectionEvent, PairFilterContext,
|
||||||
@@ -522,6 +522,19 @@ impl NarrowPhase {
|
|||||||
|
|
||||||
let mut has_any_active_contact = false;
|
let mut has_any_active_contact = false;
|
||||||
|
|
||||||
|
let friction = CoefficientCombineRule::combine(
|
||||||
|
co1.friction,
|
||||||
|
co2.friction,
|
||||||
|
co1.flags.friction_combine_rule_value(),
|
||||||
|
co2.flags.friction_combine_rule_value(),
|
||||||
|
);
|
||||||
|
let restitution = CoefficientCombineRule::combine(
|
||||||
|
co1.restitution,
|
||||||
|
co2.restitution,
|
||||||
|
co1.flags.restitution_combine_rule_value(),
|
||||||
|
co2.flags.restitution_combine_rule_value(),
|
||||||
|
);
|
||||||
|
|
||||||
for manifold in &mut pair.manifolds {
|
for manifold in &mut pair.manifolds {
|
||||||
let world_pos1 = manifold.subshape_pos1.prepend_to(co1.position());
|
let world_pos1 = manifold.subshape_pos1.prepend_to(co1.position());
|
||||||
manifold.data.solver_contacts.clear();
|
manifold.data.solver_contacts.clear();
|
||||||
@@ -541,8 +554,8 @@ impl NarrowPhase {
|
|||||||
point: world_pos1 * contact.local_p1
|
point: world_pos1 * contact.local_p1
|
||||||
+ manifold.data.normal * contact.dist / 2.0,
|
+ manifold.data.normal * contact.dist / 2.0,
|
||||||
dist: contact.dist,
|
dist: contact.dist,
|
||||||
friction: (co1.friction + co2.friction) / 2.0,
|
friction,
|
||||||
restitution: (co1.restitution + co2.restitution) / 2.0,
|
restitution,
|
||||||
surface_velocity: Vector::zeros(),
|
surface_velocity: Vector::zeros(),
|
||||||
data: contact.data,
|
data: contact.data,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user