Collider shape: use a trait-object instead of an enum.
This commit is contained in:
@@ -22,7 +22,7 @@ simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
|||||||
# enabled with the "simd-stable" or "simd-nightly" feature.
|
# enabled with the "simd-stable" or "simd-nightly" feature.
|
||||||
simd-is-enabled = [ ]
|
simd-is-enabled = [ ]
|
||||||
wasm-bindgen = [ "instant/wasm-bindgen" ]
|
wasm-bindgen = [ "instant/wasm-bindgen" ]
|
||||||
serde-serialize = [ "nalgebra/serde-serialize", "ncollide2d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde", "arrayvec/serde" ]
|
serde-serialize = [ "erased-serde", "nalgebra/serde-serialize", "ncollide2d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde", "arrayvec/serde" ]
|
||||||
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
|
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@@ -46,7 +46,10 @@ arrayvec = "0.5"
|
|||||||
bit-vec = "0.6"
|
bit-vec = "0.6"
|
||||||
rustc-hash = "1"
|
rustc-hash = "1"
|
||||||
serde = { version = "1", features = [ "derive" ], optional = true }
|
serde = { version = "1", features = [ "derive" ], optional = true }
|
||||||
|
erased-serde = { version = "0.3", optional = true }
|
||||||
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
|
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
|
||||||
|
downcast-rs = "1.2"
|
||||||
|
num-derive = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bincode = "1"
|
bincode = "1"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
|||||||
# enabled with the "simd-stable" or "simd-nightly" feature.
|
# enabled with the "simd-stable" or "simd-nightly" feature.
|
||||||
simd-is-enabled = [ ]
|
simd-is-enabled = [ ]
|
||||||
wasm-bindgen = [ "instant/wasm-bindgen" ]
|
wasm-bindgen = [ "instant/wasm-bindgen" ]
|
||||||
serde-serialize = [ "nalgebra/serde-serialize", "ncollide3d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde" ]
|
serde-serialize = [ "erased-serde", "nalgebra/serde-serialize", "ncollide3d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde" ]
|
||||||
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
|
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@@ -46,7 +46,11 @@ arrayvec = "0.5"
|
|||||||
bit-vec = "0.6"
|
bit-vec = "0.6"
|
||||||
rustc-hash = "1"
|
rustc-hash = "1"
|
||||||
serde = { version = "1", features = [ "derive" ], optional = true }
|
serde = { version = "1", features = [ "derive" ], optional = true }
|
||||||
|
erased-serde = { version = "0.3", optional = true }
|
||||||
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
|
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
|
||||||
|
downcast-rs = "1.2"
|
||||||
|
num-derive = "0.3"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bincode = "1"
|
bincode = "1"
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ impl MassProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
/// Reconstructs the inverse angular inertia tensor of the rigid body from its principal inertia values and axii.
|
/// Reconstructs the inverse angular inertia tensor of the rigid body from its principal inertia values and axes.
|
||||||
pub fn reconstruct_inverse_inertia_matrix(&self) -> Matrix3<f32> {
|
pub fn reconstruct_inverse_inertia_matrix(&self) -> Matrix3<f32> {
|
||||||
let inv_principal_inertia = self.inv_principal_inertia_sqrt.map(|e| e * e);
|
let inv_principal_inertia = self.inv_principal_inertia_sqrt.map(|e| e * e);
|
||||||
self.principal_inertia_local_frame.to_rotation_matrix()
|
self.principal_inertia_local_frame.to_rotation_matrix()
|
||||||
@@ -103,7 +103,7 @@ impl MassProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[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 axes.
|
||||||
pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> {
|
pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> {
|
||||||
let principal_inertia = self.inv_principal_inertia_sqrt.map(|e| utils::inv(e * e));
|
let principal_inertia = self.inv_principal_inertia_sqrt.map(|e| utils::inv(e * e));
|
||||||
self.principal_inertia_local_frame.to_rotation_matrix()
|
self.principal_inertia_local_frame.to_rotation_matrix()
|
||||||
|
|||||||
@@ -4,21 +4,19 @@ use crate::geometry::Capsule;
|
|||||||
use crate::math::{Point, PrincipalAngularInertia, Rotation, Vector};
|
use crate::math::{Point, PrincipalAngularInertia, Rotation, Vector};
|
||||||
|
|
||||||
impl MassProperties {
|
impl MassProperties {
|
||||||
pub(crate) fn from_capsule(density: f32, a: Point<f32>, b: Point<f32>, radius: f32) -> Self {
|
pub(crate) fn from_capsule(density: f32, half_height: f32, radius: f32) -> Self {
|
||||||
let half_height = (b - a).norm() / 2.0;
|
|
||||||
let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
|
let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
|
||||||
let (ball_vol, ball_unit_i) = Self::ball_volume_unit_angular_inertia(radius);
|
let (ball_vol, ball_unit_i) = Self::ball_volume_unit_angular_inertia(radius);
|
||||||
let cap_vol = cyl_vol + ball_vol;
|
let cap_vol = cyl_vol + ball_vol;
|
||||||
let cap_mass = cap_vol * density;
|
let cap_mass = cap_vol * density;
|
||||||
let mut cap_unit_i = cyl_unit_i + ball_unit_i;
|
let mut cap_unit_i = cyl_unit_i + ball_unit_i;
|
||||||
let local_com = na::center(&a, &b);
|
|
||||||
|
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
{
|
{
|
||||||
let h = half_height * 2.0;
|
let h = half_height * 2.0;
|
||||||
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
|
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
|
||||||
cap_unit_i += extra;
|
cap_unit_i += extra;
|
||||||
Self::new(local_com, cap_mass, cap_unit_i * cap_mass)
|
Self::new(Point::origin(), cap_mass, cap_unit_i * cap_mass)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
@@ -27,12 +25,11 @@ impl MassProperties {
|
|||||||
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
|
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
|
||||||
cap_unit_i.x += extra;
|
cap_unit_i.x += extra;
|
||||||
cap_unit_i.z += extra;
|
cap_unit_i.z += extra;
|
||||||
let local_frame = Capsule::new(a, b, radius).rotation_wrt_y();
|
|
||||||
Self::with_principal_inertia_frame(
|
Self::with_principal_inertia_frame(
|
||||||
local_com,
|
Point::origin(),
|
||||||
cap_mass,
|
cap_mass,
|
||||||
cap_unit_i * cap_mass,
|
cap_unit_i * cap_mass,
|
||||||
local_frame,
|
Rotation::identity(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ impl SAPAxis {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
struct SAPRegion {
|
struct SAPRegion {
|
||||||
axii: [SAPAxis; DIM],
|
axes: [SAPAxis; DIM],
|
||||||
existing_proxies: BitVec,
|
existing_proxies: BitVec,
|
||||||
#[cfg_attr(feature = "serde-serialize", serde(skip))]
|
#[cfg_attr(feature = "serde-serialize", serde(skip))]
|
||||||
to_insert: Vec<usize>, // Workspace
|
to_insert: Vec<usize>, // Workspace
|
||||||
@@ -344,14 +344,14 @@ struct SAPRegion {
|
|||||||
|
|
||||||
impl SAPRegion {
|
impl SAPRegion {
|
||||||
pub fn new(bounds: AABB<f32>) -> Self {
|
pub fn new(bounds: AABB<f32>) -> Self {
|
||||||
let axii = [
|
let axes = [
|
||||||
SAPAxis::new(bounds.mins.x, bounds.maxs.x),
|
SAPAxis::new(bounds.mins.x, bounds.maxs.x),
|
||||||
SAPAxis::new(bounds.mins.y, bounds.maxs.y),
|
SAPAxis::new(bounds.mins.y, bounds.maxs.y),
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
SAPAxis::new(bounds.mins.z, bounds.maxs.z),
|
SAPAxis::new(bounds.mins.z, bounds.maxs.z),
|
||||||
];
|
];
|
||||||
SAPRegion {
|
SAPRegion {
|
||||||
axii,
|
axes,
|
||||||
existing_proxies: BitVec::new(),
|
existing_proxies: BitVec::new(),
|
||||||
to_insert: Vec::new(),
|
to_insert: Vec::new(),
|
||||||
need_update: false,
|
need_update: false,
|
||||||
@@ -386,15 +386,15 @@ impl SAPRegion {
|
|||||||
// Update endpoints.
|
// Update endpoints.
|
||||||
let mut deleted_any = false;
|
let mut deleted_any = false;
|
||||||
for dim in 0..DIM {
|
for dim in 0..DIM {
|
||||||
self.axii[dim].update_endpoints(dim, proxies, reporting);
|
self.axes[dim].update_endpoints(dim, proxies, reporting);
|
||||||
deleted_any = self.axii[dim]
|
deleted_any = self.axes[dim]
|
||||||
.delete_out_of_bounds_proxies(&mut self.existing_proxies)
|
.delete_out_of_bounds_proxies(&mut self.existing_proxies)
|
||||||
|| deleted_any;
|
|| deleted_any;
|
||||||
}
|
}
|
||||||
|
|
||||||
if deleted_any {
|
if deleted_any {
|
||||||
for dim in 0..DIM {
|
for dim in 0..DIM {
|
||||||
self.axii[dim].delete_out_of_bounds_endpoints(&self.existing_proxies);
|
self.axes[dim].delete_out_of_bounds_endpoints(&self.existing_proxies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,9 +404,9 @@ impl SAPRegion {
|
|||||||
if !self.to_insert.is_empty() {
|
if !self.to_insert.is_empty() {
|
||||||
// Insert new proxies.
|
// Insert new proxies.
|
||||||
for dim in 1..DIM {
|
for dim in 1..DIM {
|
||||||
self.axii[dim].batch_insert(dim, &self.to_insert, proxies, None);
|
self.axes[dim].batch_insert(dim, &self.to_insert, proxies, None);
|
||||||
}
|
}
|
||||||
self.axii[0].batch_insert(0, &self.to_insert, proxies, Some(reporting));
|
self.axes[0].batch_insert(0, &self.to_insert, proxies, Some(reporting));
|
||||||
self.to_insert.clear();
|
self.to_insert.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,172 +3,186 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
|
|||||||
use crate::geometry::PolygonalFeatureMap;
|
use crate::geometry::PolygonalFeatureMap;
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph,
|
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph,
|
||||||
Polygon, Proximity, Ray, RayIntersection, Triangle, Trimesh,
|
Polygon, Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh,
|
||||||
};
|
};
|
||||||
use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
|
use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
|
||||||
|
use downcast_rs::{impl_downcast, DowncastSync};
|
||||||
|
use erased_serde::Serialize;
|
||||||
use na::Point3;
|
use na::Point3;
|
||||||
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
|
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
|
||||||
use ncollide::query::RayCast;
|
use ncollide::query::RayCast;
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
|
use std::any::Any;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// The shape of a collider.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
pub struct ColliderShape(pub Arc<dyn Shape>);
|
||||||
/// An enum grouping all the possible shape of a collider.
|
|
||||||
pub enum Shape {
|
impl Deref for ColliderShape {
|
||||||
/// A ball shape.
|
type Target = Shape;
|
||||||
Ball(Ball),
|
fn deref(&self) -> &Shape {
|
||||||
/// A convex polygon shape.
|
&*self.0
|
||||||
Polygon(Polygon),
|
}
|
||||||
/// A cuboid shape.
|
|
||||||
Cuboid(Cuboid),
|
|
||||||
/// A capsule shape.
|
|
||||||
Capsule(Capsule),
|
|
||||||
/// A triangle shape.
|
|
||||||
Triangle(Triangle),
|
|
||||||
/// A triangle mesh shape.
|
|
||||||
Trimesh(Trimesh),
|
|
||||||
/// A heightfield shape.
|
|
||||||
HeightField(HeightField),
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
/// A cylindrical shape.
|
|
||||||
Cylinder(Cylinder),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl ColliderShape {
|
||||||
/// Gets a reference to the underlying ball shape, if `self` is one.
|
/// Initialize a ball shape defined by its radius.
|
||||||
pub fn as_ball(&self) -> Option<&Ball> {
|
pub fn ball(radius: f32) -> Self {
|
||||||
match self {
|
ColliderShape(Arc::new(Ball::new(radius)))
|
||||||
Shape::Ball(b) => Some(b),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to the underlying polygon shape, if `self` is one.
|
/// Initialize a cylindrical shape defined by its half-height
|
||||||
pub fn as_polygon(&self) -> Option<&Polygon> {
|
/// (along along the y axis) and its radius.
|
||||||
match self {
|
|
||||||
Shape::Polygon(p) => Some(p),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying cuboid shape, if `self` is one.
|
|
||||||
pub fn as_cuboid(&self) -> Option<&Cuboid> {
|
|
||||||
match self {
|
|
||||||
Shape::Cuboid(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying capsule shape, if `self` is one.
|
|
||||||
pub fn as_capsule(&self) -> Option<&Capsule> {
|
|
||||||
match self {
|
|
||||||
Shape::Capsule(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying triangle mesh shape, if `self` is one.
|
|
||||||
pub fn as_trimesh(&self) -> Option<&Trimesh> {
|
|
||||||
match self {
|
|
||||||
Shape::Trimesh(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying heightfield shape, if `self` is one.
|
|
||||||
pub fn as_heightfield(&self) -> Option<&HeightField> {
|
|
||||||
match self {
|
|
||||||
Shape::HeightField(h) => Some(h),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying triangle shape, if `self` is one.
|
|
||||||
pub fn as_triangle(&self) -> Option<&Triangle> {
|
|
||||||
match self {
|
|
||||||
Shape::Triangle(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying cylindrical shape, if `self` is one.
|
|
||||||
pub fn as_cylinder(&self) -> Option<&Cylinder> {
|
|
||||||
match self {
|
|
||||||
Shape::Cylinder(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// gets a reference to this shape seen as a PolygonalFeatureMap.
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
pub fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
|
pub fn cylinder(half_height: f32, radius: f32) -> Self {
|
||||||
match self {
|
ColliderShape(Arc::new(Cylinder::new(half_height, radius)))
|
||||||
Shape::Triangle(t) => Some(t),
|
|
||||||
Shape::Cuboid(c) => Some(c),
|
|
||||||
Shape::Cylinder(c) => Some(c),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the axis-aligned bounding box of this shape.
|
/// Initialize a cuboid shape defined by its half-extents.
|
||||||
pub fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
pub fn cuboid(half_extents: Vector<f32>) -> Self {
|
||||||
match self {
|
ColliderShape(Arc::new(Cuboid::new(half_extents)))
|
||||||
Shape::Ball(ball) => ball.bounding_volume(position),
|
|
||||||
Shape::Polygon(poly) => poly.aabb(position),
|
|
||||||
Shape::Capsule(caps) => caps.aabb(position),
|
|
||||||
Shape::Cuboid(cuboid) => cuboid.bounding_volume(position),
|
|
||||||
Shape::Triangle(triangle) => triangle.bounding_volume(position),
|
|
||||||
Shape::Trimesh(trimesh) => trimesh.aabb(position),
|
|
||||||
Shape::HeightField(heightfield) => heightfield.bounding_volume(position),
|
|
||||||
Shape::Cylinder(cylinder) => cylinder.bounding_volume(position),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the first intersection point between a ray in this collider.
|
/// Initialize a capsule shape aligned with the `y` axis.
|
||||||
///
|
pub fn capsule(half_height: f32, radius: f32) -> Self {
|
||||||
/// Some shapes are not supported yet and will always return `None`.
|
ColliderShape(Arc::new(Capsule::new(half_height, radius)))
|
||||||
///
|
}
|
||||||
/// # Parameters
|
|
||||||
/// - `position`: the position of this shape.
|
/// Initializes a triangle shape.
|
||||||
/// - `ray`: the ray to cast.
|
pub fn triangle(a: Point<f32>, b: Point<f32>, c: Point<f32>) -> Self {
|
||||||
/// - `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively
|
ColliderShape(Arc::new(Triangle::new(a, b, c)))
|
||||||
/// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `f32::MAX` for an unbounded ray.
|
}
|
||||||
pub fn cast_ray(
|
|
||||||
&self,
|
/// Initializes a triangle mesh shape defined by its vertex and index buffers.
|
||||||
position: &Isometry<f32>,
|
pub fn trimesh(vertices: Vec<Point<f32>>, indices: Vec<Point3<u32>>) -> Self {
|
||||||
ray: &Ray,
|
ColliderShape(Arc::new(Trimesh::new(vertices, indices)))
|
||||||
max_toi: f32,
|
}
|
||||||
) -> Option<RayIntersection> {
|
|
||||||
match self {
|
/// Initializes an heightfield shape defined by its set of height and a scale
|
||||||
Shape::Ball(ball) => ball.toi_and_normal_with_ray(position, ray, max_toi, true),
|
/// factor along each coordinate axis.
|
||||||
Shape::Polygon(_poly) => None,
|
#[cfg(feature = "dim2")]
|
||||||
Shape::Capsule(caps) => {
|
pub fn heightfield(heights: na::DVector<f32>, scale: Vector<f32>) -> Self {
|
||||||
let pos = position * caps.transform_wrt_y();
|
ColliderShape(Arc::new(HeightField::new(heights, scale)))
|
||||||
let caps = ncollide::shape::Capsule::new(caps.half_height(), caps.radius);
|
}
|
||||||
caps.toi_and_normal_with_ray(&pos, ray, max_toi, true)
|
|
||||||
|
/// 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<f32>, scale: Vector<f32>) -> 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")
|
||||||
}
|
}
|
||||||
Shape::Cuboid(cuboid) => cuboid.toi_and_normal_with_ray(position, ray, max_toi, true),
|
|
||||||
#[cfg(feature = "dim2")]
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
Shape::Triangle(_) | Shape::Trimesh(_) => {
|
where
|
||||||
// This is not implemented yet in 2D.
|
A: serde::de::SeqAccess<'de>,
|
||||||
None
|
{
|
||||||
}
|
use num::cast::FromPrimitive;
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Shape::Triangle(triangle) => {
|
let tag: i32 = seq
|
||||||
triangle.toi_and_normal_with_ray(position, ray, max_toi, true)
|
.next_element()?
|
||||||
}
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Shape::Trimesh(trimesh) => {
|
let shape = match ShapeType::from_i32(tag) {
|
||||||
trimesh.toi_and_normal_with_ray(position, ray, max_toi, true)
|
Some(ShapeType::Ball) => {
|
||||||
}
|
let shape: Ball = seq
|
||||||
Shape::HeightField(heightfield) => {
|
.next_element()?
|
||||||
heightfield.toi_and_normal_with_ray(position, ray, max_toi, true)
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
}
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
#[cfg(feature = "dim3")]
|
}
|
||||||
Shape::Cylinder(cylinder) => {
|
Some(ShapeType::Polygon) => {
|
||||||
cylinder.toi_and_normal_with_ray(position, ray, max_toi, true)
|
unimplemented!()
|
||||||
|
// let shape: Polygon = seq
|
||||||
|
// .next_element()?
|
||||||
|
// .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
// Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
Some(ShapeType::Cuboid) => {
|
||||||
|
let shape: Cuboid = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
Some(ShapeType::Capsule) => {
|
||||||
|
let shape: Capsule = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
Some(ShapeType::Triangle) => {
|
||||||
|
let shape: Triangle = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
Some(ShapeType::Trimesh) => {
|
||||||
|
let shape: Trimesh = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
Some(ShapeType::HeightField) => {
|
||||||
|
let shape: HeightField = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
Some(ShapeType::Cylinder) => {
|
||||||
|
let shape: Cylinder = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
|
||||||
|
Arc::new(shape) as Arc<dyn Shape>
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(serde::de::Error::custom(
|
||||||
|
"found invalid shape type to deserialize",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ColliderShape(shape))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +191,7 @@ impl Shape {
|
|||||||
///
|
///
|
||||||
/// To build a new collider, use the `ColliderBuilder` structure.
|
/// To build a new collider, use the `ColliderBuilder` structure.
|
||||||
pub struct Collider {
|
pub struct Collider {
|
||||||
shape: Shape,
|
shape: ColliderShape,
|
||||||
density: f32,
|
density: f32,
|
||||||
is_sensor: bool,
|
is_sensor: bool,
|
||||||
pub(crate) parent: RigidBodyHandle,
|
pub(crate) parent: RigidBodyHandle,
|
||||||
@@ -245,7 +259,7 @@ impl Collider {
|
|||||||
|
|
||||||
/// The geometric shape of this collider.
|
/// The geometric shape of this collider.
|
||||||
pub fn shape(&self) -> &Shape {
|
pub fn shape(&self) -> &Shape {
|
||||||
&self.shape
|
&*self.shape.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the axis-aligned bounding box of this collider.
|
/// Compute the axis-aligned bounding box of this collider.
|
||||||
@@ -261,23 +275,7 @@ impl Collider {
|
|||||||
|
|
||||||
/// Compute the local-space mass properties of this collider.
|
/// Compute the local-space mass properties of this collider.
|
||||||
pub fn mass_properties(&self) -> MassProperties {
|
pub fn mass_properties(&self) -> MassProperties {
|
||||||
match &self.shape {
|
self.shape.mass_properties(self.density)
|
||||||
Shape::Ball(ball) => MassProperties::from_ball(self.density, ball.radius),
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
Shape::Polygon(p) => MassProperties::from_polygon(self.density, p.vertices()),
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
Shape::Polygon(_p) => unimplemented!(),
|
|
||||||
Shape::Cuboid(c) => MassProperties::from_cuboid(self.density, c.half_extents),
|
|
||||||
Shape::Capsule(caps) => {
|
|
||||||
MassProperties::from_capsule(self.density, caps.a, caps.b, caps.radius)
|
|
||||||
}
|
|
||||||
Shape::Triangle(_) | Shape::Trimesh(_) | Shape::HeightField(_) => {
|
|
||||||
MassProperties::zero()
|
|
||||||
}
|
|
||||||
Shape::Cylinder(c) => {
|
|
||||||
MassProperties::from_cylinder(self.density, c.half_height, c.radius)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +284,7 @@ impl Collider {
|
|||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
pub struct ColliderBuilder {
|
pub struct ColliderBuilder {
|
||||||
/// The shape of the collider to be built.
|
/// The shape of the collider to be built.
|
||||||
pub shape: Shape,
|
pub shape: ColliderShape,
|
||||||
/// The density of the collider to be built.
|
/// The density of the collider to be built.
|
||||||
density: Option<f32>,
|
density: Option<f32>,
|
||||||
/// The friction coefficient of the collider to be built.
|
/// The friction coefficient of the collider to be built.
|
||||||
@@ -301,7 +299,7 @@ pub struct ColliderBuilder {
|
|||||||
|
|
||||||
impl ColliderBuilder {
|
impl ColliderBuilder {
|
||||||
/// Initialize a new collider builder with the given shape.
|
/// Initialize a new collider builder with the given shape.
|
||||||
pub fn new(shape: Shape) -> Self {
|
pub fn new(shape: ColliderShape) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shape,
|
shape,
|
||||||
density: None,
|
density: None,
|
||||||
@@ -320,102 +318,81 @@ impl ColliderBuilder {
|
|||||||
|
|
||||||
/// Initialize a new collider builder with a ball shape defined by its radius.
|
/// Initialize a new collider builder with a ball shape defined by its radius.
|
||||||
pub fn ball(radius: f32) -> Self {
|
pub fn ball(radius: f32) -> Self {
|
||||||
Self::new(Shape::Ball(Ball::new(radius)))
|
Self::new(ColliderShape::ball(radius))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a cylindrical shape defined by its half-height
|
/// Initialize a new collider builder with a cylindrical shape defined by its half-height
|
||||||
/// (along along the y axis) and its radius.
|
/// (along along the y axis) and its radius.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
pub fn cylinder(half_height: f32, radius: f32) -> Self {
|
pub fn cylinder(half_height: f32, radius: f32) -> Self {
|
||||||
Self::new(Shape::Cylinder(Cylinder::new(half_height, radius)))
|
Self::new(ColliderShape::cylinder(half_height, radius))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a cuboid shape defined by its half-extents.
|
/// Initialize a new collider builder with a cuboid shape defined by its half-extents.
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
pub fn cuboid(hx: f32, hy: f32) -> Self {
|
pub fn cuboid(hx: f32, hy: f32) -> Self {
|
||||||
let cuboid = Cuboid {
|
Self::new(ColliderShape::cuboid(Vector::new(hx, hy)))
|
||||||
half_extents: Vector::new(hx, hy),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::new(Shape::Cuboid(cuboid))
|
|
||||||
|
|
||||||
/*
|
|
||||||
use crate::math::Point;
|
|
||||||
let vertices = vec![
|
|
||||||
Point::new(hx, -hy),
|
|
||||||
Point::new(hx, hy),
|
|
||||||
Point::new(-hx, hy),
|
|
||||||
Point::new(-hx, -hy),
|
|
||||||
];
|
|
||||||
let normals = vec![Vector::x(), Vector::y(), -Vector::x(), -Vector::y()];
|
|
||||||
let polygon = Polygon::new(vertices, normals);
|
|
||||||
|
|
||||||
Self::new(Shape::Polygon(polygon))
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a capsule shape aligned with the `x` axis.
|
/// Initialize a new collider builder with a capsule shape aligned with the `x` axis.
|
||||||
pub fn capsule_x(half_height: f32, radius: f32) -> Self {
|
pub fn capsule_x(half_height: f32, radius: f32) -> Self {
|
||||||
let capsule = Capsule::new_x(half_height, radius);
|
#[cfg(feature = "dim2")]
|
||||||
Self::new(Shape::Capsule(capsule))
|
let rot = -std::f32::consts::FRAC_PI_2;
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
let rot = Vector::z() * -std::f32::consts::FRAC_PI_2;
|
||||||
|
Self::new(ColliderShape::capsule(half_height, radius))
|
||||||
|
.position(Isometry::new(na::zero(), rot))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a capsule shape aligned with the `y` axis.
|
/// Initialize a new collider builder with a capsule shape aligned with the `y` axis.
|
||||||
pub fn capsule_y(half_height: f32, radius: f32) -> Self {
|
pub fn capsule_y(half_height: f32, radius: f32) -> Self {
|
||||||
let capsule = Capsule::new_y(half_height, radius);
|
Self::new(ColliderShape::capsule(half_height, radius))
|
||||||
Self::new(Shape::Capsule(capsule))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a capsule shape aligned with the `z` axis.
|
/// Initialize a new collider builder with a capsule shape aligned with the `z` axis.
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
pub fn capsule_z(half_height: f32, radius: f32) -> Self {
|
pub fn capsule_z(half_height: f32, radius: f32) -> Self {
|
||||||
let capsule = Capsule::new_z(half_height, radius);
|
let rot = Vector::x() * std::f32::consts::FRAC_PI_2;
|
||||||
Self::new(Shape::Capsule(capsule))
|
Self::new(ColliderShape::capsule(half_height, radius))
|
||||||
|
.position(Isometry::new(na::zero(), rot))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new collider builder with a cuboid shape defined by its half-extents.
|
/// Initialize a new collider builder with a cuboid shape defined by its half-extents.
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self {
|
pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self {
|
||||||
let cuboid = Cuboid {
|
Self::new(ColliderShape::cuboid(Vector::new(hx, hy, hz)))
|
||||||
half_extents: Vector::new(hx, hy, hz),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::new(Shape::Cuboid(cuboid))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a collider builder with a segment shape.
|
/// Initializes a collider builder with a segment shape.
|
||||||
///
|
///
|
||||||
/// A segment shape is modeled by a capsule with a 0 radius.
|
/// A segment shape is modeled by a capsule with a 0 radius.
|
||||||
pub fn segment(a: Point<f32>, b: Point<f32>) -> Self {
|
pub fn segment(a: Point<f32>, b: Point<f32>) -> Self {
|
||||||
let capsule = Capsule::new(a, b, 0.0);
|
let (pos, half_height) = crate::utils::segment_to_capsule(&a, &b);
|
||||||
Self::new(Shape::Capsule(capsule))
|
Self::new(ColliderShape::capsule(half_height, 0.0)).position(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a collider builder with a triangle shape.
|
/// Initializes a collider builder with a triangle shape.
|
||||||
pub fn triangle(a: Point<f32>, b: Point<f32>, c: Point<f32>) -> Self {
|
pub fn triangle(a: Point<f32>, b: Point<f32>, c: Point<f32>) -> Self {
|
||||||
let triangle = Triangle::new(a, b, c);
|
Self::new(ColliderShape::triangle(a, b, c))
|
||||||
Self::new(Shape::Triangle(triangle))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers.
|
/// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers.
|
||||||
pub fn trimesh(vertices: Vec<Point<f32>>, indices: Vec<Point3<u32>>) -> Self {
|
pub fn trimesh(vertices: Vec<Point<f32>>, indices: Vec<Point3<u32>>) -> Self {
|
||||||
let trimesh = Trimesh::new(vertices, indices);
|
Self::new(ColliderShape::trimesh(vertices, indices))
|
||||||
Self::new(Shape::Trimesh(trimesh))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a collider builder with a heightfield shape defined by its set of height and a scale
|
/// Initializes a collider builder with a heightfield shape defined by its set of height and a scale
|
||||||
/// factor along each coordinate axis.
|
/// factor along each coordinate axis.
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
pub fn heightfield(heights: na::DVector<f32>, scale: Vector<f32>) -> Self {
|
pub fn heightfield(heights: na::DVector<f32>, scale: Vector<f32>) -> Self {
|
||||||
let heightfield = HeightField::new(heights, scale);
|
Self::new(ColliderShape::heightfield(heights, scale))
|
||||||
Self::new(Shape::HeightField(heightfield))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a collider builder with a heightfield shape defined by its set of height and a scale
|
/// Initializes a collider builder with a heightfield shape defined by its set of height and a scale
|
||||||
/// factor along each coordinate axis.
|
/// factor along each coordinate axis.
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
pub fn heightfield(heights: na::DMatrix<f32>, scale: Vector<f32>) -> Self {
|
pub fn heightfield(heights: na::DMatrix<f32>, scale: Vector<f32>) -> Self {
|
||||||
let heightfield = HeightField::new(heights, scale);
|
Self::new(ColliderShape::heightfield(heights, scale))
|
||||||
Self::new(Shape::HeightField(heightfield))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The default friction coefficient used by the collider builder.
|
/// The default friction coefficient used by the collider builder.
|
||||||
|
|||||||
@@ -5,30 +5,17 @@ use na::Unit;
|
|||||||
use ncollide::query::PointQuery;
|
use ncollide::query::PointQuery;
|
||||||
|
|
||||||
pub fn generate_contacts_ball_convex(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_ball_convex(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let Shape::Ball(ball1) = ctxt.shape1 {
|
if let Some(ball1) = ctxt.shape1.as_ball() {
|
||||||
ctxt.manifold.swap_identifiers();
|
ctxt.manifold.swap_identifiers();
|
||||||
|
do_generate_contacts(ctxt.shape2, ball1, ctxt, true);
|
||||||
match ctxt.shape2 {
|
} else if let Some(ball2) = ctxt.shape2.as_ball() {
|
||||||
Shape::Triangle(tri2) => do_generate_contacts(tri2, ball1, ctxt, true),
|
do_generate_contacts(ctxt.shape1, ball2, ctxt, false);
|
||||||
Shape::Cuboid(cube2) => do_generate_contacts(cube2, ball1, ctxt, true),
|
|
||||||
Shape::Capsule(capsule2) => do_generate_contacts(capsule2, ball1, ctxt, true),
|
|
||||||
Shape::Cylinder(cylinder2) => do_generate_contacts(cylinder2, ball1, ctxt, true),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
} else if let Shape::Ball(ball2) = ctxt.shape2 {
|
|
||||||
match ctxt.shape1 {
|
|
||||||
Shape::Triangle(tri1) => do_generate_contacts(tri1, ball2, ctxt, false),
|
|
||||||
Shape::Cuboid(cube1) => do_generate_contacts(cube1, ball2, ctxt, false),
|
|
||||||
Shape::Capsule(capsule1) => do_generate_contacts(capsule1, ball2, ctxt, false),
|
|
||||||
Shape::Cylinder(cylinder1) => do_generate_contacts(cylinder1, ball2, ctxt, false),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt.manifold.sort_contacts(ctxt.prediction_distance);
|
ctxt.manifold.sort_contacts(ctxt.prediction_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_generate_contacts<P: PointQuery<f32>>(
|
fn do_generate_contacts<P: ?Sized + PointQuery<f32>>(
|
||||||
point_query1: &P,
|
point_query1: &P,
|
||||||
ball2: &Ball,
|
ball2: &Ball,
|
||||||
ctxt: &mut PrimitiveContactGenerationContext,
|
ctxt: &mut PrimitiveContactGenerationContext,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use na::Unit;
|
|||||||
use ncollide::shape::{Segment, SegmentPointLocation};
|
use ncollide::shape::{Segment, SegmentPointLocation};
|
||||||
|
|
||||||
pub fn generate_contacts_capsule_capsule(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_capsule_capsule(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let (Shape::Capsule(capsule1), Shape::Capsule(capsule2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(capsule1), Some(capsule2)) = (ctxt.shape1.as_capsule(), ctxt.shape2.as_capsule()) {
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
capsule1,
|
capsule1,
|
||||||
@@ -94,7 +94,7 @@ pub fn generate_contacts<'a>(
|
|||||||
if dir1.dot(&dir2).abs() >= crate::utils::COS_FRAC_PI_8
|
if dir1.dot(&dir2).abs() >= crate::utils::COS_FRAC_PI_8
|
||||||
&& dir1.dot(&local_n1).abs() < crate::utils::SIN_FRAC_PI_8
|
&& dir1.dot(&local_n1).abs() < crate::utils::SIN_FRAC_PI_8
|
||||||
{
|
{
|
||||||
// Capsules axii are almost parallel and are almost perpendicular to the normal.
|
// Capsules axes are almost parallel and are almost perpendicular to the normal.
|
||||||
// Find a second contact point.
|
// Find a second contact point.
|
||||||
if let Some((clip_a, clip_b)) = crate::geometry::clip_segments_with_normal(
|
if let Some((clip_a, clip_b)) = crate::geometry::clip_segments_with_normal(
|
||||||
(capsule1.a, capsule1.b),
|
(capsule1.a, capsule1.b),
|
||||||
@@ -156,17 +156,18 @@ pub fn generate_contacts<'a>(
|
|||||||
let pos12 = pos1.inverse() * pos2;
|
let pos12 = pos1.inverse() * pos2;
|
||||||
let pos21 = pos12.inverse();
|
let pos21 = pos12.inverse();
|
||||||
|
|
||||||
let capsule2_1 = capsule1.transform_by(&pos12);
|
let seg1 = capsule1.segment();
|
||||||
|
let seg2_1 = capsule2.segment().transformed(&pos12);
|
||||||
let (loc1, loc2) = ncollide::query::closest_points_segment_segment_with_locations_nD(
|
let (loc1, loc2) = ncollide::query::closest_points_segment_segment_with_locations_nD(
|
||||||
(&capsule1.a, &capsule1.b),
|
(&seg1.a, &seg1.b),
|
||||||
(&capsule2_1.a, &capsule2_1.b),
|
(&seg2_1.a, &seg2_1.b),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
let bcoords1 = loc1.barycentric_coordinates();
|
let bcoords1 = loc1.barycentric_coordinates();
|
||||||
let bcoords2 = loc2.barycentric_coordinates();
|
let bcoords2 = loc2.barycentric_coordinates();
|
||||||
let local_p1 = capsule1.a * bcoords1[0] + capsule1.b.coords * bcoords1[1];
|
let local_p1 = seg1.a * bcoords1[0] + seg1.b.coords * bcoords1[1];
|
||||||
let local_p2 = capsule2_1.a * bcoords2[0] + capsule2_1.b.coords * bcoords2[1];
|
let local_p2 = seg2_1.a * bcoords2[0] + seg2_1.b.coords * bcoords2[1];
|
||||||
|
|
||||||
let local_n1 =
|
let local_n1 =
|
||||||
Unit::try_new(local_p2 - local_p1, f32::default_epsilon()).unwrap_or(Vector::y_axis());
|
Unit::try_new(local_p2 - local_p1, f32::default_epsilon()).unwrap_or(Vector::y_axis());
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::geometry::contact_generator::{
|
|||||||
PfmPfmContactManifoldGeneratorWorkspace, PrimitiveContactGenerator,
|
PfmPfmContactManifoldGeneratorWorkspace, PrimitiveContactGenerator,
|
||||||
TrimeshShapeContactGeneratorWorkspace,
|
TrimeshShapeContactGeneratorWorkspace,
|
||||||
};
|
};
|
||||||
use crate::geometry::Shape;
|
use crate::geometry::{Shape, ShapeType};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
/// Trait implemented by structures responsible for selecting a collision-detection algorithm
|
/// Trait implemented by structures responsible for selecting a collision-detection algorithm
|
||||||
@@ -12,8 +12,8 @@ pub trait ContactDispatcher {
|
|||||||
/// Select the collision-detection algorithm for the given pair of primitive shapes.
|
/// Select the collision-detection algorithm for the given pair of primitive shapes.
|
||||||
fn dispatch_primitives(
|
fn dispatch_primitives(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (
|
) -> (
|
||||||
PrimitiveContactGenerator,
|
PrimitiveContactGenerator,
|
||||||
Option<Box<dyn Any + Send + Sync>>,
|
Option<Box<dyn Any + Send + Sync>>,
|
||||||
@@ -21,8 +21,8 @@ pub trait ContactDispatcher {
|
|||||||
/// Select the collision-detection algorithm for the given pair of non-primitive shapes.
|
/// Select the collision-detection algorithm for the given pair of non-primitive shapes.
|
||||||
fn dispatch(
|
fn dispatch(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (ContactPhase, Option<Box<dyn Any + Send + Sync>>);
|
) -> (ContactPhase, Option<Box<dyn Any + Send + Sync>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,14 +32,14 @@ pub struct DefaultContactDispatcher;
|
|||||||
impl ContactDispatcher for DefaultContactDispatcher {
|
impl ContactDispatcher for DefaultContactDispatcher {
|
||||||
fn dispatch_primitives(
|
fn dispatch_primitives(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (
|
) -> (
|
||||||
PrimitiveContactGenerator,
|
PrimitiveContactGenerator,
|
||||||
Option<Box<dyn Any + Send + Sync>>,
|
Option<Box<dyn Any + Send + Sync>>,
|
||||||
) {
|
) {
|
||||||
match (shape1, shape2) {
|
match (shape1, shape2) {
|
||||||
(Shape::Ball(_), Shape::Ball(_)) => (
|
(ShapeType::Ball, ShapeType::Ball) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_ball_ball,
|
generate_contacts: super::generate_contacts_ball_ball,
|
||||||
#[cfg(feature = "simd-is-enabled")]
|
#[cfg(feature = "simd-is-enabled")]
|
||||||
@@ -48,56 +48,58 @@ impl ContactDispatcher for DefaultContactDispatcher {
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Cuboid(_), Shape::Cuboid(_)) => (
|
(ShapeType::Cuboid, ShapeType::Cuboid) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_cuboid_cuboid,
|
generate_contacts: super::generate_contacts_cuboid_cuboid,
|
||||||
..PrimitiveContactGenerator::default()
|
..PrimitiveContactGenerator::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Polygon(_), Shape::Polygon(_)) => (
|
// (ShapeType::Polygon, ShapeType::Polygon) => (
|
||||||
PrimitiveContactGenerator {
|
// PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_polygon_polygon,
|
// generate_contacts: super::generate_contacts_polygon_polygon,
|
||||||
..PrimitiveContactGenerator::default()
|
// ..PrimitiveContactGenerator::default()
|
||||||
},
|
// },
|
||||||
None,
|
// None,
|
||||||
),
|
// ),
|
||||||
(Shape::Capsule(_), Shape::Capsule(_)) => (
|
(ShapeType::Capsule, ShapeType::Capsule) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_capsule_capsule,
|
generate_contacts: super::generate_contacts_capsule_capsule,
|
||||||
..PrimitiveContactGenerator::default()
|
..PrimitiveContactGenerator::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Cuboid(_), Shape::Ball(_))
|
(ShapeType::Cuboid, ShapeType::Ball)
|
||||||
| (Shape::Ball(_), Shape::Cuboid(_))
|
| (ShapeType::Ball, ShapeType::Cuboid)
|
||||||
| (Shape::Triangle(_), Shape::Ball(_))
|
| (ShapeType::Triangle, ShapeType::Ball)
|
||||||
| (Shape::Ball(_), Shape::Triangle(_))
|
| (ShapeType::Ball, ShapeType::Triangle)
|
||||||
| (Shape::Capsule(_), Shape::Ball(_))
|
| (ShapeType::Capsule, ShapeType::Ball)
|
||||||
| (Shape::Ball(_), Shape::Capsule(_))
|
| (ShapeType::Ball, ShapeType::Capsule)
|
||||||
| (Shape::Cylinder(_), Shape::Ball(_))
|
| (ShapeType::Cylinder, ShapeType::Ball)
|
||||||
| (Shape::Ball(_), Shape::Cylinder(_)) => (
|
| (ShapeType::Ball, ShapeType::Cylinder) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_ball_convex,
|
generate_contacts: super::generate_contacts_ball_convex,
|
||||||
..PrimitiveContactGenerator::default()
|
..PrimitiveContactGenerator::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Capsule(_), Shape::Cuboid(_)) | (Shape::Cuboid(_), Shape::Capsule(_)) => (
|
(ShapeType::Capsule, ShapeType::Cuboid) | (ShapeType::Cuboid, ShapeType::Capsule) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_cuboid_capsule,
|
generate_contacts: super::generate_contacts_cuboid_capsule,
|
||||||
..PrimitiveContactGenerator::default()
|
..PrimitiveContactGenerator::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Triangle(_), Shape::Cuboid(_)) | (Shape::Cuboid(_), Shape::Triangle(_)) => (
|
(ShapeType::Triangle, ShapeType::Cuboid) | (ShapeType::Cuboid, ShapeType::Triangle) => {
|
||||||
PrimitiveContactGenerator {
|
(
|
||||||
generate_contacts: super::generate_contacts_cuboid_triangle,
|
PrimitiveContactGenerator {
|
||||||
..PrimitiveContactGenerator::default()
|
generate_contacts: super::generate_contacts_cuboid_triangle,
|
||||||
},
|
..PrimitiveContactGenerator::default()
|
||||||
None,
|
},
|
||||||
),
|
None,
|
||||||
(Shape::Cylinder(_), _) | (_, Shape::Cylinder(_)) => (
|
)
|
||||||
|
}
|
||||||
|
(ShapeType::Cylinder, _) | (_, ShapeType::Cylinder) => (
|
||||||
PrimitiveContactGenerator {
|
PrimitiveContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_pfm_pfm,
|
generate_contacts: super::generate_contacts_pfm_pfm,
|
||||||
..PrimitiveContactGenerator::default()
|
..PrimitiveContactGenerator::default()
|
||||||
@@ -110,18 +112,18 @@ impl ContactDispatcher for DefaultContactDispatcher {
|
|||||||
|
|
||||||
fn dispatch(
|
fn dispatch(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (ContactPhase, Option<Box<dyn Any + Send + Sync>>) {
|
) -> (ContactPhase, Option<Box<dyn Any + Send + Sync>>) {
|
||||||
match (shape1, shape2) {
|
match (shape1, shape2) {
|
||||||
(Shape::Trimesh(_), _) | (_, Shape::Trimesh(_)) => (
|
(ShapeType::Trimesh, _) | (_, ShapeType::Trimesh) => (
|
||||||
ContactPhase::NearPhase(ContactGenerator {
|
ContactPhase::NearPhase(ContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_trimesh_shape,
|
generate_contacts: super::generate_contacts_trimesh_shape,
|
||||||
..ContactGenerator::default()
|
..ContactGenerator::default()
|
||||||
}),
|
}),
|
||||||
Some(Box::new(TrimeshShapeContactGeneratorWorkspace::new())),
|
Some(Box::new(TrimeshShapeContactGeneratorWorkspace::new())),
|
||||||
),
|
),
|
||||||
(Shape::HeightField(_), _) | (_, Shape::HeightField(_)) => (
|
(ShapeType::HeightField, _) | (_, ShapeType::HeightField) => (
|
||||||
ContactPhase::NearPhase(ContactGenerator {
|
ContactPhase::NearPhase(ContactGenerator {
|
||||||
generate_contacts: super::generate_contacts_heightfield_shape,
|
generate_contacts: super::generate_contacts_heightfield_shape,
|
||||||
..ContactGenerator::default()
|
..ContactGenerator::default()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::math::Vector;
|
|||||||
use ncollide::shape::Segment;
|
use ncollide::shape::Segment;
|
||||||
|
|
||||||
pub fn generate_contacts_cuboid_capsule(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_cuboid_capsule(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let (Shape::Cuboid(cube1), Shape::Capsule(capsule2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(cube1), Some(capsule2)) = (ctxt.shape1.as_cuboid(), ctxt.shape2.as_capsule()) {
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube1,
|
cube1,
|
||||||
@@ -20,7 +20,9 @@ pub fn generate_contacts_cuboid_capsule(ctxt: &mut PrimitiveContactGenerationCon
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
ctxt.manifold.update_warmstart_multiplier();
|
ctxt.manifold.update_warmstart_multiplier();
|
||||||
} else if let (Shape::Capsule(capsule1), Shape::Cuboid(cube2)) = (ctxt.shape1, ctxt.shape2) {
|
} else if let (Some(capsule1), Some(cube2)) =
|
||||||
|
(ctxt.shape1.as_capsule(), ctxt.shape2.as_cuboid())
|
||||||
|
{
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube2,
|
cube2,
|
||||||
@@ -53,7 +55,7 @@ pub fn generate_contacts<'a>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let segment2 = Segment::new(capsule2.a, capsule2.b);
|
let segment2 = capsule2.segment();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::math::Vector;
|
|||||||
use ncollide::shape::Cuboid;
|
use ncollide::shape::Cuboid;
|
||||||
|
|
||||||
pub fn generate_contacts_cuboid_cuboid(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_cuboid_cuboid(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let (Shape::Cuboid(cube1), Shape::Cuboid(cube2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(cube1), Some(cube2)) = (ctxt.shape1.as_cuboid(), ctxt.shape2.as_cuboid()) {
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube1,
|
cube1,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn generate_contacts_cuboid_triangle(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_cuboid_triangle(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let (Shape::Cuboid(cube1), Shape::Triangle(triangle2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(cube1), Some(triangle2)) = (ctxt.shape1.as_cuboid(), ctxt.shape2.as_triangle()) {
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube1,
|
cube1,
|
||||||
@@ -21,7 +21,9 @@ pub fn generate_contacts_cuboid_triangle(ctxt: &mut PrimitiveContactGenerationCo
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
ctxt.manifold.update_warmstart_multiplier();
|
ctxt.manifold.update_warmstart_multiplier();
|
||||||
} else if let (Shape::Triangle(triangle1), Shape::Cuboid(cube2)) = (ctxt.shape1, ctxt.shape2) {
|
} else if let (Some(triangle1), Some(cube2)) =
|
||||||
|
(ctxt.shape1.as_triangle(), ctxt.shape2.as_cuboid())
|
||||||
|
{
|
||||||
generate_contacts(
|
generate_contacts(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube2,
|
cube2,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::geometry::contact_generator::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
use crate::geometry::Capsule;
|
use crate::geometry::Capsule;
|
||||||
use crate::geometry::{Collider, ContactManifold, HeightField, Shape};
|
use crate::geometry::{Collider, ContactManifold, HeightField, Shape, ShapeType};
|
||||||
use crate::ncollide::bounding_volume::BoundingVolume;
|
use crate::ncollide::bounding_volume::BoundingVolume;
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use crate::{geometry::Triangle, math::Point};
|
use crate::{geometry::Triangle, math::Point};
|
||||||
@@ -38,9 +38,9 @@ pub fn generate_contacts_heightfield_shape(ctxt: &mut ContactGenerationContext)
|
|||||||
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
||||||
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
||||||
|
|
||||||
if let Shape::HeightField(heightfield1) = collider1.shape() {
|
if let Some(heightfield1) = collider1.shape().as_heightfield() {
|
||||||
do_generate_contacts(heightfield1, collider1, collider2, ctxt, false)
|
do_generate_contacts(heightfield1, collider1, collider2, ctxt, false)
|
||||||
} else if let Shape::HeightField(heightfield2) = collider2.shape() {
|
} else if let Some(heightfield2) = collider2.shape().as_heightfield() {
|
||||||
do_generate_contacts(heightfield2, collider2, collider1, ctxt, true)
|
do_generate_contacts(heightfield2, collider2, collider1, ctxt, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,7 @@ fn do_generate_contacts(
|
|||||||
.expect("The HeightFieldShapeContactGeneratorWorkspace is missing.")
|
.expect("The HeightFieldShapeContactGeneratorWorkspace is missing.")
|
||||||
.downcast_mut()
|
.downcast_mut()
|
||||||
.expect("Invalid workspace type, expected a HeightFieldShapeContactGeneratorWorkspace.");
|
.expect("Invalid workspace type, expected a HeightFieldShapeContactGeneratorWorkspace.");
|
||||||
|
let shape_type2 = collider2.shape().shape_type();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detect if the detector context has been reset.
|
* Detect if the detector context has been reset.
|
||||||
@@ -76,19 +77,9 @@ fn do_generate_contacts(
|
|||||||
// subshape_id, manifold.subshape_index_pair
|
// subshape_id, manifold.subshape_index_pair
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// Use dummy shapes for the dispatch.
|
|
||||||
#[cfg(feature = "dim2")]
|
|
||||||
let sub_shape1 =
|
|
||||||
Shape::Capsule(Capsule::new(na::Point::origin(), na::Point::origin(), 0.0));
|
|
||||||
#[cfg(feature = "dim3")]
|
|
||||||
let sub_shape1 = Shape::Triangle(Triangle::new(
|
|
||||||
Point::origin(),
|
|
||||||
Point::origin(),
|
|
||||||
Point::origin(),
|
|
||||||
));
|
|
||||||
let (generator, workspace2) = ctxt
|
let (generator, workspace2) = ctxt
|
||||||
.dispatcher
|
.dispatcher
|
||||||
.dispatch_primitives(&sub_shape1, collider2.shape());
|
.dispatch_primitives(ShapeType::Capsule, shape_type2);
|
||||||
|
|
||||||
let sub_detector = SubDetector {
|
let sub_detector = SubDetector {
|
||||||
generator,
|
generator,
|
||||||
@@ -120,12 +111,18 @@ fn do_generate_contacts(
|
|||||||
let manifolds = &mut ctxt.pair.manifolds;
|
let manifolds = &mut ctxt.pair.manifolds;
|
||||||
let prediction_distance = ctxt.prediction_distance;
|
let prediction_distance = ctxt.prediction_distance;
|
||||||
let dispatcher = ctxt.dispatcher;
|
let dispatcher = ctxt.dispatcher;
|
||||||
|
let shape_type2 = collider2.shape().shape_type();
|
||||||
|
|
||||||
heightfield1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, part1, _| {
|
heightfield1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, part1, _| {
|
||||||
|
let position1 = *collider1.position();
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
let sub_shape1 = Shape::Capsule(Capsule::new(part1.a, part1.b, 0.0));
|
let (position1, sub_shape1) = {
|
||||||
|
let (dpos, height) = crate::utils::segment_to_capsule(&part1.a, &part1.b);
|
||||||
|
(position1 * dpos, Capsule::new(height, 0.0));
|
||||||
|
};
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
let sub_shape1 = Shape::Triangle(*part1);
|
let sub_shape1 = *part1;
|
||||||
|
|
||||||
let sub_detector = match workspace.sub_detectors.entry(i) {
|
let sub_detector = match workspace.sub_detectors.entry(i) {
|
||||||
Entry::Occupied(entry) => {
|
Entry::Occupied(entry) => {
|
||||||
let sub_detector = entry.into_mut();
|
let sub_detector = entry.into_mut();
|
||||||
@@ -137,7 +134,7 @@ fn do_generate_contacts(
|
|||||||
}
|
}
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let (generator, workspace2) =
|
let (generator, workspace2) =
|
||||||
dispatcher.dispatch_primitives(&sub_shape1, collider2.shape());
|
dispatcher.dispatch_primitives(ShapeType::Triangle, shape_type2);
|
||||||
let sub_detector = SubDetector {
|
let sub_detector = SubDetector {
|
||||||
generator,
|
generator,
|
||||||
manifold_id: manifolds.len(),
|
manifold_id: manifolds.len(),
|
||||||
@@ -162,7 +159,7 @@ fn do_generate_contacts(
|
|||||||
shape1: collider2.shape(),
|
shape1: collider2.shape(),
|
||||||
shape2: &sub_shape1,
|
shape2: &sub_shape1,
|
||||||
position1: collider2.position(),
|
position1: collider2.position(),
|
||||||
position2: collider1.position(),
|
position2: &position1,
|
||||||
manifold,
|
manifold,
|
||||||
workspace: sub_detector.workspace.as_deref_mut(),
|
workspace: sub_detector.workspace.as_deref_mut(),
|
||||||
}
|
}
|
||||||
@@ -173,7 +170,7 @@ fn do_generate_contacts(
|
|||||||
collider2,
|
collider2,
|
||||||
shape1: &sub_shape1,
|
shape1: &sub_shape1,
|
||||||
shape2: collider2.shape(),
|
shape2: collider2.shape(),
|
||||||
position1: collider1.position(),
|
position1: &position1,
|
||||||
position2: collider2.position(),
|
position2: collider2.position(),
|
||||||
manifold,
|
manifold,
|
||||||
workspace: sub_detector.workspace.as_deref_mut(),
|
workspace: sub_detector.workspace.as_deref_mut(),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub use self::heightfield_shape_contact_generator::{
|
|||||||
pub use self::pfm_pfm_contact_generator::{
|
pub use self::pfm_pfm_contact_generator::{
|
||||||
generate_contacts_pfm_pfm, PfmPfmContactManifoldGeneratorWorkspace,
|
generate_contacts_pfm_pfm, PfmPfmContactManifoldGeneratorWorkspace,
|
||||||
};
|
};
|
||||||
pub use self::polygon_polygon_contact_generator::generate_contacts_polygon_polygon;
|
// pub use self::polygon_polygon_contact_generator::generate_contacts_polygon_polygon;
|
||||||
pub use self::trimesh_shape_contact_generator::{
|
pub use self::trimesh_shape_contact_generator::{
|
||||||
generate_contacts_trimesh_shape, TrimeshShapeContactGeneratorWorkspace,
|
generate_contacts_trimesh_shape, TrimeshShapeContactGeneratorWorkspace,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,20 +5,21 @@ use crate::math::{Isometry, Point};
|
|||||||
use crate::{math::Vector, utils};
|
use crate::{math::Vector, utils};
|
||||||
|
|
||||||
pub fn generate_contacts_polygon_polygon(ctxt: &mut PrimitiveContactGenerationContext) {
|
pub fn generate_contacts_polygon_polygon(ctxt: &mut PrimitiveContactGenerationContext) {
|
||||||
if let (Shape::Polygon(polygon1), Shape::Polygon(polygon2)) = (ctxt.shape1, ctxt.shape2) {
|
unimplemented!()
|
||||||
generate_contacts(
|
// if let (Shape::Polygon(polygon1), Shape::Polygon(polygon2)) = (ctxt.shape1, ctxt.shape2) {
|
||||||
polygon1,
|
// generate_contacts(
|
||||||
&ctxt.position1,
|
// polygon1,
|
||||||
polygon2,
|
// &ctxt.position1,
|
||||||
&ctxt.position2,
|
// polygon2,
|
||||||
ctxt.manifold,
|
// &ctxt.position2,
|
||||||
);
|
// ctxt.manifold,
|
||||||
ctxt.manifold.update_warmstart_multiplier();
|
// );
|
||||||
} else {
|
// ctxt.manifold.update_warmstart_multiplier();
|
||||||
unreachable!()
|
// } else {
|
||||||
}
|
// unreachable!()
|
||||||
|
// }
|
||||||
ctxt.manifold.sort_contacts(ctxt.prediction_distance);
|
//
|
||||||
|
// ctxt.manifold.sort_contacts(ctxt.prediction_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_contacts<'a>(
|
fn generate_contacts<'a>(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::geometry::contact_generator::{
|
use crate::geometry::contact_generator::{
|
||||||
ContactGenerationContext, PrimitiveContactGenerationContext,
|
ContactGenerationContext, PrimitiveContactGenerationContext,
|
||||||
};
|
};
|
||||||
use crate::geometry::{Collider, ContactManifold, Shape, Trimesh};
|
use crate::geometry::{Collider, ContactManifold, Shape, ShapeType, Trimesh};
|
||||||
use crate::ncollide::bounding_volume::{BoundingVolume, AABB};
|
use crate::ncollide::bounding_volume::{BoundingVolume, AABB};
|
||||||
|
|
||||||
pub struct TrimeshShapeContactGeneratorWorkspace {
|
pub struct TrimeshShapeContactGeneratorWorkspace {
|
||||||
@@ -26,9 +26,9 @@ pub fn generate_contacts_trimesh_shape(ctxt: &mut ContactGenerationContext) {
|
|||||||
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
||||||
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
||||||
|
|
||||||
if let Shape::Trimesh(trimesh1) = collider1.shape() {
|
if let Some(trimesh1) = collider1.shape().as_trimesh() {
|
||||||
do_generate_contacts(trimesh1, collider1, collider2, ctxt, false)
|
do_generate_contacts(trimesh1, collider1, collider2, ctxt, false)
|
||||||
} else if let Shape::Trimesh(trimesh2) = collider2.shape() {
|
} else if let Some(trimesh2) = collider2.shape().as_trimesh() {
|
||||||
do_generate_contacts(trimesh2, collider2, collider1, ctxt, true)
|
do_generate_contacts(trimesh2, collider2, collider1, ctxt, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +121,7 @@ fn do_generate_contacts(
|
|||||||
let new_interferences = &workspace.interferences;
|
let new_interferences = &workspace.interferences;
|
||||||
let mut old_inter_it = workspace.old_interferences.drain(..).peekable();
|
let mut old_inter_it = workspace.old_interferences.drain(..).peekable();
|
||||||
let mut old_manifolds_it = workspace.old_manifolds.drain(..);
|
let mut old_manifolds_it = workspace.old_manifolds.drain(..);
|
||||||
|
let shape_type2 = collider2.shape().shape_type();
|
||||||
|
|
||||||
for (i, triangle_id) in new_interferences.iter().enumerate() {
|
for (i, triangle_id) in new_interferences.iter().enumerate() {
|
||||||
if *triangle_id >= trimesh1.num_triangles() {
|
if *triangle_id >= trimesh1.num_triangles() {
|
||||||
@@ -159,10 +160,10 @@ fn do_generate_contacts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let manifold = &mut ctxt.pair.manifolds[i];
|
let manifold = &mut ctxt.pair.manifolds[i];
|
||||||
let triangle1 = Shape::Triangle(trimesh1.triangle(*triangle_id));
|
let triangle1 = trimesh1.triangle(*triangle_id);
|
||||||
let (generator, mut workspace2) = ctxt
|
let (generator, mut workspace2) = ctxt
|
||||||
.dispatcher
|
.dispatcher
|
||||||
.dispatch_primitives(&triangle1, collider2.shape());
|
.dispatch_primitives(ShapeType::Triangle, shape_type2);
|
||||||
|
|
||||||
let mut ctxt2 = if ctxt_pair_pair.collider1 != manifold.pair.collider1 {
|
let mut ctxt2 = if ctxt_pair_pair.collider1 != manifold.pair.collider1 {
|
||||||
PrimitiveContactGenerationContext {
|
PrimitiveContactGenerationContext {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
//! 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::capsule::Capsule;
|
pub use self::collider::{Collider, ColliderBuilder, ColliderShape};
|
||||||
pub use self::collider::{Collider, ColliderBuilder, Shape};
|
|
||||||
pub use self::collider_set::{ColliderHandle, ColliderSet};
|
pub use self::collider_set::{ColliderHandle, ColliderSet};
|
||||||
pub use self::contact::{
|
pub use self::contact::{
|
||||||
Contact, ContactKinematics, ContactManifold, ContactPair, KinematicsCategory,
|
Contact, ContactKinematics, ContactManifold, ContactPair, KinematicsCategory,
|
||||||
@@ -19,9 +18,12 @@ pub use self::narrow_phase::NarrowPhase;
|
|||||||
pub use self::polygon::Polygon;
|
pub use self::polygon::Polygon;
|
||||||
pub use self::proximity::ProximityPair;
|
pub use self::proximity::ProximityPair;
|
||||||
pub use self::proximity_detector::{DefaultProximityDispatcher, ProximityDispatcher};
|
pub use self::proximity_detector::{DefaultProximityDispatcher, ProximityDispatcher};
|
||||||
|
pub use self::rounded::Rounded;
|
||||||
pub use self::trimesh::Trimesh;
|
pub use self::trimesh::Trimesh;
|
||||||
pub use ncollide::query::Proximity;
|
pub use ncollide::query::Proximity;
|
||||||
|
|
||||||
|
/// A capsule shape.
|
||||||
|
pub type Capsule = ncollide::shape::Capsule<f32>;
|
||||||
/// A cuboid shape.
|
/// A cuboid shape.
|
||||||
pub type Cuboid = ncollide::shape::Cuboid<f32>;
|
pub type Cuboid = ncollide::shape::Cuboid<f32>;
|
||||||
/// A triangle shape.
|
/// A triangle shape.
|
||||||
@@ -43,6 +45,8 @@ pub type ProximityEvent = ncollide::pipeline::ProximityEvent<ColliderHandle>;
|
|||||||
pub type Ray = ncollide::query::Ray<f32>;
|
pub type Ray = ncollide::query::Ray<f32>;
|
||||||
/// The intersection between a ray and a collider.
|
/// The intersection between a ray and a collider.
|
||||||
pub type RayIntersection = ncollide::query::RayIntersection<f32>;
|
pub type RayIntersection = ncollide::query::RayIntersection<f32>;
|
||||||
|
/// The the projection of a point on a collider.
|
||||||
|
pub type PointProjection = ncollide::query::PointProjection<f32>;
|
||||||
|
|
||||||
#[cfg(feature = "simd-is-enabled")]
|
#[cfg(feature = "simd-is-enabled")]
|
||||||
pub(crate) use self::ball::WBall;
|
pub(crate) use self::ball::WBall;
|
||||||
@@ -61,10 +65,10 @@ pub(crate) use self::polyhedron_feature3d::PolyhedronFace;
|
|||||||
pub(crate) use self::waabb::{WRay, WAABB};
|
pub(crate) use self::waabb::{WRay, WAABB};
|
||||||
pub(crate) use self::wquadtree::WQuadtree;
|
pub(crate) use self::wquadtree::WQuadtree;
|
||||||
//pub(crate) use self::z_order::z_cmp_floats;
|
//pub(crate) use self::z_order::z_cmp_floats;
|
||||||
|
pub use self::shape::{Shape, ShapeType};
|
||||||
|
|
||||||
mod ball;
|
mod ball;
|
||||||
mod broad_phase_multi_sap;
|
mod broad_phase_multi_sap;
|
||||||
mod capsule;
|
|
||||||
mod collider;
|
mod collider;
|
||||||
mod collider_set;
|
mod collider_set;
|
||||||
mod contact;
|
mod contact;
|
||||||
@@ -89,3 +93,5 @@ mod wquadtree;
|
|||||||
//mod z_order;
|
//mod z_order;
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
mod polygonal_feature_map;
|
mod polygonal_feature_map;
|
||||||
|
mod rounded;
|
||||||
|
mod shape;
|
||||||
|
|||||||
@@ -197,7 +197,8 @@ impl NarrowPhase {
|
|||||||
|
|
||||||
if self.proximity_graph.graph.find_edge(gid1, gid2).is_none() {
|
if self.proximity_graph.graph.find_edge(gid1, gid2).is_none() {
|
||||||
let dispatcher = DefaultProximityDispatcher;
|
let dispatcher = DefaultProximityDispatcher;
|
||||||
let generator = dispatcher.dispatch(co1.shape(), co2.shape());
|
let generator = dispatcher
|
||||||
|
.dispatch(co1.shape().shape_type(), co2.shape().shape_type());
|
||||||
let interaction =
|
let interaction =
|
||||||
ProximityPair::new(*pair, generator.0, generator.1);
|
ProximityPair::new(*pair, generator.0, generator.1);
|
||||||
let _ = self.proximity_graph.add_edge(
|
let _ = self.proximity_graph.add_edge(
|
||||||
@@ -226,7 +227,8 @@ impl NarrowPhase {
|
|||||||
|
|
||||||
if self.contact_graph.graph.find_edge(gid1, gid2).is_none() {
|
if self.contact_graph.graph.find_edge(gid1, gid2).is_none() {
|
||||||
let dispatcher = DefaultContactDispatcher;
|
let dispatcher = DefaultContactDispatcher;
|
||||||
let generator = dispatcher.dispatch(co1.shape(), co2.shape());
|
let generator = dispatcher
|
||||||
|
.dispatch(co1.shape().shape_type(), co2.shape().shape_type());
|
||||||
let interaction = ContactPair::new(*pair, generator.0, generator.1);
|
let interaction = ContactPair::new(*pair, generator.0, generator.1);
|
||||||
let _ = self.contact_graph.add_edge(
|
let _ = self.contact_graph.add_edge(
|
||||||
co1.contact_graph_index,
|
co1.contact_graph_index,
|
||||||
@@ -308,7 +310,8 @@ impl NarrowPhase {
|
|||||||
if pair.detector.is_none() {
|
if pair.detector.is_none() {
|
||||||
// We need a redispatch for this detector.
|
// We need a redispatch for this detector.
|
||||||
// This can happen, e.g., after restoring a snapshot of the narrow-phase.
|
// This can happen, e.g., after restoring a snapshot of the narrow-phase.
|
||||||
let (detector, workspace) = dispatcher.dispatch(co1.shape(), co2.shape());
|
let (detector, workspace) =
|
||||||
|
dispatcher.dispatch(co1.shape().shape_type(), co2.shape().shape_type());
|
||||||
pair.detector = Some(detector);
|
pair.detector = Some(detector);
|
||||||
pair.detector_workspace = workspace;
|
pair.detector_workspace = workspace;
|
||||||
}
|
}
|
||||||
@@ -418,7 +421,8 @@ impl NarrowPhase {
|
|||||||
if pair.generator.is_none() {
|
if pair.generator.is_none() {
|
||||||
// We need a redispatch for this generator.
|
// We need a redispatch for this generator.
|
||||||
// This can happen, e.g., after restoring a snapshot of the narrow-phase.
|
// This can happen, e.g., after restoring a snapshot of the narrow-phase.
|
||||||
let (generator, workspace) = dispatcher.dispatch(co1.shape(), co2.shape());
|
let (generator, workspace) =
|
||||||
|
dispatcher.dispatch(co1.shape().shape_type(), co2.shape().shape_type());
|
||||||
pair.generator = Some(generator);
|
pair.generator = Some(generator);
|
||||||
pair.generator_workspace = workspace;
|
pair.generator_workspace = workspace;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,16 @@ use crate::math::Isometry;
|
|||||||
use ncollide::query::PointQuery;
|
use ncollide::query::PointQuery;
|
||||||
|
|
||||||
pub fn detect_proximity_ball_convex(ctxt: &mut PrimitiveProximityDetectionContext) -> Proximity {
|
pub fn detect_proximity_ball_convex(ctxt: &mut PrimitiveProximityDetectionContext) -> Proximity {
|
||||||
if let Shape::Ball(ball1) = ctxt.shape1 {
|
if let Some(ball1) = ctxt.shape1.as_ball() {
|
||||||
match ctxt.shape2 {
|
do_detect_proximity(ctxt.shape2, ball1, &ctxt)
|
||||||
Shape::Triangle(tri2) => do_detect_proximity(tri2, ball1, &ctxt),
|
} else if let Some(ball2) = ctxt.shape2.as_ball() {
|
||||||
Shape::Cuboid(cube2) => do_detect_proximity(cube2, ball1, &ctxt),
|
do_detect_proximity(ctxt.shape1, ball2, &ctxt)
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
} else if let Shape::Ball(ball2) = ctxt.shape2 {
|
|
||||||
match ctxt.shape1 {
|
|
||||||
Shape::Triangle(tri1) => do_detect_proximity(tri1, ball2, &ctxt),
|
|
||||||
Shape::Cuboid(cube1) => do_detect_proximity(cube1, ball2, &ctxt),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Invalid shape types provide.")
|
panic!("Invalid shape types provide.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_detect_proximity<P: PointQuery<f32>>(
|
fn do_detect_proximity<P: ?Sized + PointQuery<f32>>(
|
||||||
point_query1: &P,
|
point_query1: &P,
|
||||||
ball2: &Ball,
|
ball2: &Ball,
|
||||||
ctxt: &PrimitiveProximityDetectionContext,
|
ctxt: &PrimitiveProximityDetectionContext,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::math::Isometry;
|
|||||||
use ncollide::shape::Cuboid;
|
use ncollide::shape::Cuboid;
|
||||||
|
|
||||||
pub fn detect_proximity_cuboid_cuboid(ctxt: &mut PrimitiveProximityDetectionContext) -> Proximity {
|
pub fn detect_proximity_cuboid_cuboid(ctxt: &mut PrimitiveProximityDetectionContext) -> Proximity {
|
||||||
if let (Shape::Cuboid(cube1), Shape::Cuboid(cube2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(cube1), Some(cube2)) = (ctxt.shape1.as_cuboid(), ctxt.shape2.as_cuboid()) {
|
||||||
detect_proximity(
|
detect_proximity(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube1,
|
cube1,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::math::Isometry;
|
|||||||
pub fn detect_proximity_cuboid_triangle(
|
pub fn detect_proximity_cuboid_triangle(
|
||||||
ctxt: &mut PrimitiveProximityDetectionContext,
|
ctxt: &mut PrimitiveProximityDetectionContext,
|
||||||
) -> Proximity {
|
) -> Proximity {
|
||||||
if let (Shape::Cuboid(cube1), Shape::Triangle(triangle2)) = (ctxt.shape1, ctxt.shape2) {
|
if let (Some(cube1), Some(triangle2)) = (ctxt.shape1.as_cuboid(), ctxt.shape2.as_triangle()) {
|
||||||
detect_proximity(
|
detect_proximity(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube1,
|
cube1,
|
||||||
@@ -13,7 +13,9 @@ pub fn detect_proximity_cuboid_triangle(
|
|||||||
triangle2,
|
triangle2,
|
||||||
ctxt.position2,
|
ctxt.position2,
|
||||||
)
|
)
|
||||||
} else if let (Shape::Triangle(triangle1), Shape::Cuboid(cube2)) = (ctxt.shape1, ctxt.shape2) {
|
} else if let (Some(triangle1), Some(cube2)) =
|
||||||
|
(ctxt.shape1.as_triangle(), ctxt.shape2.as_cuboid())
|
||||||
|
{
|
||||||
detect_proximity(
|
detect_proximity(
|
||||||
ctxt.prediction_distance,
|
ctxt.prediction_distance,
|
||||||
cube2,
|
cube2,
|
||||||
|
|||||||
@@ -5,17 +5,18 @@ use crate::math::Isometry;
|
|||||||
pub fn detect_proximity_polygon_polygon(
|
pub fn detect_proximity_polygon_polygon(
|
||||||
ctxt: &mut PrimitiveProximityDetectionContext,
|
ctxt: &mut PrimitiveProximityDetectionContext,
|
||||||
) -> Proximity {
|
) -> Proximity {
|
||||||
if let (Shape::Polygon(polygon1), Shape::Polygon(polygon2)) = (ctxt.shape1, ctxt.shape2) {
|
unimplemented!()
|
||||||
detect_proximity(
|
// if let (Some(polygon1), Some(polygon2)) = (ctxt.shape1.as_polygon(), ctxt.shape2.as_polygon()) {
|
||||||
ctxt.prediction_distance,
|
// detect_proximity(
|
||||||
polygon1,
|
// ctxt.prediction_distance,
|
||||||
&ctxt.position1,
|
// polygon1,
|
||||||
polygon2,
|
// &ctxt.position1,
|
||||||
&ctxt.position2,
|
// polygon2,
|
||||||
)
|
// &ctxt.position2,
|
||||||
} else {
|
// )
|
||||||
unreachable!()
|
// } else {
|
||||||
}
|
// unreachable!()
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_proximity<'a>(
|
fn detect_proximity<'a>(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::geometry::proximity_detector::{
|
|||||||
PrimitiveProximityDetector, ProximityDetector, ProximityPhase,
|
PrimitiveProximityDetector, ProximityDetector, ProximityPhase,
|
||||||
TrimeshShapeProximityDetectorWorkspace,
|
TrimeshShapeProximityDetectorWorkspace,
|
||||||
};
|
};
|
||||||
use crate::geometry::Shape;
|
use crate::geometry::{Shape, ShapeType};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
/// Trait implemented by structures responsible for selecting a collision-detection algorithm
|
/// Trait implemented by structures responsible for selecting a collision-detection algorithm
|
||||||
@@ -11,8 +11,8 @@ pub trait ProximityDispatcher {
|
|||||||
/// Select the proximity detection algorithm for the given pair of primitive shapes.
|
/// Select the proximity detection algorithm for the given pair of primitive shapes.
|
||||||
fn dispatch_primitives(
|
fn dispatch_primitives(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (
|
) -> (
|
||||||
PrimitiveProximityDetector,
|
PrimitiveProximityDetector,
|
||||||
Option<Box<dyn Any + Send + Sync>>,
|
Option<Box<dyn Any + Send + Sync>>,
|
||||||
@@ -20,8 +20,8 @@ pub trait ProximityDispatcher {
|
|||||||
/// Select the proximity detection algorithm for the given pair of non-primitive shapes.
|
/// Select the proximity detection algorithm for the given pair of non-primitive shapes.
|
||||||
fn dispatch(
|
fn dispatch(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (ProximityPhase, Option<Box<dyn Any + Send + Sync>>);
|
) -> (ProximityPhase, Option<Box<dyn Any + Send + Sync>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,14 +31,14 @@ pub struct DefaultProximityDispatcher;
|
|||||||
impl ProximityDispatcher for DefaultProximityDispatcher {
|
impl ProximityDispatcher for DefaultProximityDispatcher {
|
||||||
fn dispatch_primitives(
|
fn dispatch_primitives(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (
|
) -> (
|
||||||
PrimitiveProximityDetector,
|
PrimitiveProximityDetector,
|
||||||
Option<Box<dyn Any + Send + Sync>>,
|
Option<Box<dyn Any + Send + Sync>>,
|
||||||
) {
|
) {
|
||||||
match (shape1, shape2) {
|
match (shape1, shape2) {
|
||||||
(Shape::Ball(_), Shape::Ball(_)) => (
|
(ShapeType::Ball, ShapeType::Ball) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
#[cfg(feature = "simd-is-enabled")]
|
#[cfg(feature = "simd-is-enabled")]
|
||||||
detect_proximity_simd: super::detect_proximity_ball_ball_simd,
|
detect_proximity_simd: super::detect_proximity_ball_ball_simd,
|
||||||
@@ -47,56 +47,56 @@ impl ProximityDispatcher for DefaultProximityDispatcher {
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Cuboid(_), Shape::Cuboid(_)) => (
|
(ShapeType::Cuboid, ShapeType::Cuboid) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_cuboid_cuboid,
|
detect_proximity: super::detect_proximity_cuboid_cuboid,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Polygon(_), Shape::Polygon(_)) => (
|
(ShapeType::Polygon, ShapeType::Polygon) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_polygon_polygon,
|
detect_proximity: super::detect_proximity_polygon_polygon,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Triangle(_), Shape::Ball(_)) => (
|
(ShapeType::Triangle, ShapeType::Ball) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_ball_convex,
|
detect_proximity: super::detect_proximity_ball_convex,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Ball(_), Shape::Triangle(_)) => (
|
(ShapeType::Ball, ShapeType::Triangle) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_ball_convex,
|
detect_proximity: super::detect_proximity_ball_convex,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Cuboid(_), Shape::Ball(_)) => (
|
(ShapeType::Cuboid, ShapeType::Ball) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_ball_convex,
|
detect_proximity: super::detect_proximity_ball_convex,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Ball(_), Shape::Cuboid(_)) => (
|
(ShapeType::Ball, ShapeType::Cuboid) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_ball_convex,
|
detect_proximity: super::detect_proximity_ball_convex,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Triangle(_), Shape::Cuboid(_)) => (
|
(ShapeType::Triangle, ShapeType::Cuboid) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_cuboid_triangle,
|
detect_proximity: super::detect_proximity_cuboid_triangle,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(Shape::Cuboid(_), Shape::Triangle(_)) => (
|
(ShapeType::Cuboid, ShapeType::Triangle) => (
|
||||||
PrimitiveProximityDetector {
|
PrimitiveProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_cuboid_triangle,
|
detect_proximity: super::detect_proximity_cuboid_triangle,
|
||||||
..PrimitiveProximityDetector::default()
|
..PrimitiveProximityDetector::default()
|
||||||
@@ -109,18 +109,18 @@ impl ProximityDispatcher for DefaultProximityDispatcher {
|
|||||||
|
|
||||||
fn dispatch(
|
fn dispatch(
|
||||||
&self,
|
&self,
|
||||||
shape1: &Shape,
|
shape1: ShapeType,
|
||||||
shape2: &Shape,
|
shape2: ShapeType,
|
||||||
) -> (ProximityPhase, Option<Box<dyn Any + Send + Sync>>) {
|
) -> (ProximityPhase, Option<Box<dyn Any + Send + Sync>>) {
|
||||||
match (shape1, shape2) {
|
match (shape1, shape2) {
|
||||||
(Shape::Trimesh(_), _) => (
|
(ShapeType::Trimesh, _) => (
|
||||||
ProximityPhase::NearPhase(ProximityDetector {
|
ProximityPhase::NearPhase(ProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_trimesh_shape,
|
detect_proximity: super::detect_proximity_trimesh_shape,
|
||||||
..ProximityDetector::default()
|
..ProximityDetector::default()
|
||||||
}),
|
}),
|
||||||
Some(Box::new(TrimeshShapeProximityDetectorWorkspace::new())),
|
Some(Box::new(TrimeshShapeProximityDetectorWorkspace::new())),
|
||||||
),
|
),
|
||||||
(_, Shape::Trimesh(_)) => (
|
(_, ShapeType::Trimesh) => (
|
||||||
ProximityPhase::NearPhase(ProximityDetector {
|
ProximityPhase::NearPhase(ProximityDetector {
|
||||||
detect_proximity: super::detect_proximity_trimesh_shape,
|
detect_proximity: super::detect_proximity_trimesh_shape,
|
||||||
..ProximityDetector::default()
|
..ProximityDetector::default()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::geometry::proximity_detector::{
|
use crate::geometry::proximity_detector::{
|
||||||
PrimitiveProximityDetectionContext, ProximityDetectionContext,
|
PrimitiveProximityDetectionContext, ProximityDetectionContext,
|
||||||
};
|
};
|
||||||
use crate::geometry::{Collider, Proximity, Shape, Trimesh};
|
use crate::geometry::{Collider, Proximity, Shape, ShapeType, Trimesh};
|
||||||
use crate::ncollide::bounding_volume::{BoundingVolume, AABB};
|
use crate::ncollide::bounding_volume::{BoundingVolume, AABB};
|
||||||
|
|
||||||
pub struct TrimeshShapeProximityDetectorWorkspace {
|
pub struct TrimeshShapeProximityDetectorWorkspace {
|
||||||
@@ -24,9 +24,9 @@ pub fn detect_proximity_trimesh_shape(ctxt: &mut ProximityDetectionContext) -> P
|
|||||||
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
let collider1 = &ctxt.colliders[ctxt.pair.pair.collider1];
|
||||||
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
let collider2 = &ctxt.colliders[ctxt.pair.pair.collider2];
|
||||||
|
|
||||||
if let Shape::Trimesh(trimesh1) = collider1.shape() {
|
if let Some(trimesh1) = collider1.shape().as_trimesh() {
|
||||||
do_detect_proximity(trimesh1, collider1, collider2, ctxt)
|
do_detect_proximity(trimesh1, collider1, collider2, ctxt)
|
||||||
} else if let Shape::Trimesh(trimesh2) = collider2.shape() {
|
} else if let Some(trimesh2) = collider2.shape().as_trimesh() {
|
||||||
do_detect_proximity(trimesh2, collider2, collider1, ctxt)
|
do_detect_proximity(trimesh2, collider2, collider1, ctxt)
|
||||||
} else {
|
} else {
|
||||||
panic!("Invalid shape types provided.")
|
panic!("Invalid shape types provided.")
|
||||||
@@ -83,6 +83,7 @@ fn do_detect_proximity(
|
|||||||
let new_interferences = &workspace.interferences;
|
let new_interferences = &workspace.interferences;
|
||||||
let mut old_inter_it = workspace.old_interferences.drain(..).peekable();
|
let mut old_inter_it = workspace.old_interferences.drain(..).peekable();
|
||||||
let mut best_proximity = Proximity::Disjoint;
|
let mut best_proximity = Proximity::Disjoint;
|
||||||
|
let shape_type2 = collider2.shape().shape_type();
|
||||||
|
|
||||||
for triangle_id in new_interferences.iter() {
|
for triangle_id in new_interferences.iter() {
|
||||||
if *triangle_id >= trimesh1.num_triangles() {
|
if *triangle_id >= trimesh1.num_triangles() {
|
||||||
@@ -107,10 +108,10 @@ fn do_detect_proximity(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let triangle1 = Shape::Triangle(trimesh1.triangle(*triangle_id));
|
let triangle1 = trimesh1.triangle(*triangle_id);
|
||||||
let (proximity_detector, mut workspace2) = ctxt
|
let (proximity_detector, mut workspace2) = ctxt
|
||||||
.dispatcher
|
.dispatcher
|
||||||
.dispatch_primitives(&triangle1, collider2.shape());
|
.dispatch_primitives(ShapeType::Triangle, shape_type2);
|
||||||
|
|
||||||
let mut ctxt2 = PrimitiveProximityDetectionContext {
|
let mut ctxt2 = PrimitiveProximityDetectionContext {
|
||||||
prediction_distance: ctxt.prediction_distance,
|
prediction_distance: ctxt.prediction_distance,
|
||||||
|
|||||||
7
src/geometry/rounded.rs
Normal file
7
src/geometry/rounded.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/// A rounded shape.
|
||||||
|
pub struct Rounded<S> {
|
||||||
|
/// The shape being rounded.
|
||||||
|
pub shape: S,
|
||||||
|
/// The rounding radius.
|
||||||
|
pub radius: f32,
|
||||||
|
}
|
||||||
@@ -58,8 +58,8 @@ pub fn cuboid_cuboid_find_local_separating_edge_twoway(
|
|||||||
let y2 = pos12 * Vector::y();
|
let y2 = pos12 * Vector::y();
|
||||||
let z2 = pos12 * Vector::z();
|
let z2 = pos12 * Vector::z();
|
||||||
|
|
||||||
// We have 3 * 3 = 9 axii to test.
|
// We have 3 * 3 = 9 axes to test.
|
||||||
let axii = [
|
let axes = [
|
||||||
// Vector::{x, y ,z}().cross(y2)
|
// Vector::{x, y ,z}().cross(y2)
|
||||||
Vector::new(0.0, -x2.z, x2.y),
|
Vector::new(0.0, -x2.z, x2.y),
|
||||||
Vector::new(x2.z, 0.0, -x2.x),
|
Vector::new(x2.z, 0.0, -x2.x),
|
||||||
@@ -74,7 +74,7 @@ pub fn cuboid_cuboid_find_local_separating_edge_twoway(
|
|||||||
Vector::new(-z2.y, z2.x, 0.0),
|
Vector::new(-z2.y, z2.x, 0.0),
|
||||||
];
|
];
|
||||||
|
|
||||||
for axis1 in &axii {
|
for axis1 in &axes {
|
||||||
let norm1 = axis1.norm();
|
let norm1 = axis1.norm();
|
||||||
if norm1 > f32::default_epsilon() {
|
if norm1 > f32::default_epsilon() {
|
||||||
let (separation, axis1) = cuboid_cuboid_compute_separation_wrt_local_line(
|
let (separation, axis1) = cuboid_cuboid_compute_separation_wrt_local_line(
|
||||||
@@ -149,7 +149,7 @@ pub fn cube_support_map_compute_separation_wrt_local_line<S: SupportMap<f32>>(
|
|||||||
pub fn cube_support_map_find_local_separating_edge_twoway(
|
pub fn cube_support_map_find_local_separating_edge_twoway(
|
||||||
cube1: &Cuboid,
|
cube1: &Cuboid,
|
||||||
shape2: &impl SupportMap<f32>,
|
shape2: &impl SupportMap<f32>,
|
||||||
axii: &[Vector<f32>],
|
axes: &[Vector<f32>],
|
||||||
pos12: &Isometry<f32>,
|
pos12: &Isometry<f32>,
|
||||||
pos21: &Isometry<f32>,
|
pos21: &Isometry<f32>,
|
||||||
) -> (f32, Vector<f32>) {
|
) -> (f32, Vector<f32>) {
|
||||||
@@ -157,7 +157,7 @@ pub fn cube_support_map_find_local_separating_edge_twoway(
|
|||||||
let mut best_separation = -std::f32::MAX;
|
let mut best_separation = -std::f32::MAX;
|
||||||
let mut best_dir = Vector::zeros();
|
let mut best_dir = Vector::zeros();
|
||||||
|
|
||||||
for axis1 in axii {
|
for axis1 in axes {
|
||||||
if let Some(axis1) = Unit::try_new(*axis1, f32::default_epsilon()) {
|
if let Some(axis1) = Unit::try_new(*axis1, f32::default_epsilon()) {
|
||||||
let (separation, axis1) = cube_support_map_compute_separation_wrt_local_line(
|
let (separation, axis1) = cube_support_map_compute_separation_wrt_local_line(
|
||||||
cube1, shape2, pos12, pos21, &axis1,
|
cube1, shape2, pos12, pos21, &axis1,
|
||||||
@@ -184,8 +184,8 @@ pub fn cube_triangle_find_local_separating_edge_twoway(
|
|||||||
let y2 = pos12 * (triangle2.c - triangle2.b);
|
let y2 = pos12 * (triangle2.c - triangle2.b);
|
||||||
let z2 = pos12 * (triangle2.a - triangle2.c);
|
let z2 = pos12 * (triangle2.a - triangle2.c);
|
||||||
|
|
||||||
// We have 3 * 3 = 3 axii to test.
|
// We have 3 * 3 = 3 axes to test.
|
||||||
let axii = [
|
let axes = [
|
||||||
// Vector::{x, y ,z}().cross(y2)
|
// Vector::{x, y ,z}().cross(y2)
|
||||||
Vector::new(0.0, -x2.z, x2.y),
|
Vector::new(0.0, -x2.z, x2.y),
|
||||||
Vector::new(x2.z, 0.0, -x2.x),
|
Vector::new(x2.z, 0.0, -x2.x),
|
||||||
@@ -200,7 +200,7 @@ pub fn cube_triangle_find_local_separating_edge_twoway(
|
|||||||
Vector::new(-z2.y, z2.x, 0.0),
|
Vector::new(-z2.y, z2.x, 0.0),
|
||||||
];
|
];
|
||||||
|
|
||||||
cube_support_map_find_local_separating_edge_twoway(cube1, triangle2, &axii, pos12, pos21)
|
cube_support_map_find_local_separating_edge_twoway(cube1, triangle2, &axes, pos12, pos21)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
@@ -212,14 +212,14 @@ pub fn cube_segment_find_local_separating_edge_twoway(
|
|||||||
) -> (f32, Vector<f32>) {
|
) -> (f32, Vector<f32>) {
|
||||||
let x2 = pos12 * (segment2.b - segment2.a);
|
let x2 = pos12 * (segment2.b - segment2.a);
|
||||||
|
|
||||||
let axii = [
|
let axes = [
|
||||||
// Vector::{x, y ,z}().cross(y2)
|
// Vector::{x, y ,z}().cross(y2)
|
||||||
Vector::new(0.0, -x2.z, x2.y),
|
Vector::new(0.0, -x2.z, x2.y),
|
||||||
Vector::new(x2.z, 0.0, -x2.x),
|
Vector::new(x2.z, 0.0, -x2.x),
|
||||||
Vector::new(-x2.y, x2.x, 0.0),
|
Vector::new(-x2.y, x2.x, 0.0),
|
||||||
];
|
];
|
||||||
|
|
||||||
cube_support_map_find_local_separating_edge_twoway(cube1, segment2, &axii, pos12, pos21)
|
cube_support_map_find_local_separating_edge_twoway(cube1, segment2, &axes, pos12, pos21)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cube_support_map_find_local_separating_normal_oneway<S: SupportMap<f32>>(
|
pub fn cube_support_map_find_local_separating_normal_oneway<S: SupportMap<f32>>(
|
||||||
|
|||||||
275
src/geometry/shape.rs
Normal file
275
src/geometry/shape.rs
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
use crate::geometry::PolygonalFeatureMap;
|
||||||
|
use crate::geometry::{
|
||||||
|
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph,
|
||||||
|
Polygon, Proximity, Ray, RayIntersection, Triangle, Trimesh,
|
||||||
|
};
|
||||||
|
use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
|
||||||
|
use downcast_rs::{impl_downcast, DowncastSync};
|
||||||
|
use erased_serde::Serialize;
|
||||||
|
use na::Point3;
|
||||||
|
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
|
||||||
|
use ncollide::query::{PointQuery, RayCast};
|
||||||
|
use num::Zero;
|
||||||
|
use num_derive::FromPrimitive;
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, FromPrimitive)]
|
||||||
|
/// Enum representing the type of a shape.
|
||||||
|
pub enum ShapeType {
|
||||||
|
/// A ball shape.
|
||||||
|
Ball = 1,
|
||||||
|
/// A convex polygon shape.
|
||||||
|
Polygon,
|
||||||
|
/// A cuboid shape.
|
||||||
|
Cuboid,
|
||||||
|
/// A capsule shape.
|
||||||
|
Capsule,
|
||||||
|
/// A triangle shape.
|
||||||
|
Triangle,
|
||||||
|
/// A triangle mesh shape.
|
||||||
|
Trimesh,
|
||||||
|
/// A heightfield shape.
|
||||||
|
HeightField,
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
/// A cylindrical shape.
|
||||||
|
Cylinder,
|
||||||
|
// /// A custom shape type.
|
||||||
|
// Custom(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by shapes usable by Rapier.
|
||||||
|
pub trait Shape: RayCast<f32> + PointQuery<f32> + DowncastSync {
|
||||||
|
/// Convert this shape as a serializable entity.
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the AABB of this shape.
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32>;
|
||||||
|
|
||||||
|
/// Compute the mass-properties of this shape given its uniform density.
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties;
|
||||||
|
|
||||||
|
/// Gets the type tag of this shape.
|
||||||
|
fn shape_type(&self) -> ShapeType;
|
||||||
|
|
||||||
|
/// Converts this shape to a polygonal feature-map, if it is one.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn as_rounded(&self) -> Option<&Rounded<Box<AnyShape>>> {
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_downcast!(sync Shape);
|
||||||
|
|
||||||
|
impl dyn Shape {
|
||||||
|
/// Converts this abstract shape to a ball, if it is one.
|
||||||
|
pub fn as_ball(&self) -> Option<&Ball> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a cuboid, if it is one.
|
||||||
|
pub fn as_cuboid(&self) -> Option<&Cuboid> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a capsule, if it is one.
|
||||||
|
pub fn as_capsule(&self) -> Option<&Capsule> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a triangle, if it is one.
|
||||||
|
pub fn as_triangle(&self) -> Option<&Triangle> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a triangle mesh, if it is one.
|
||||||
|
pub fn as_trimesh(&self) -> Option<&Trimesh> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a heightfield, if it is one.
|
||||||
|
pub fn as_heightfield(&self) -> Option<&HeightField> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this abstract shape to a cylinder, if it is one.
|
||||||
|
pub fn as_cylinder(&self) -> Option<&Cylinder> {
|
||||||
|
self.downcast_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for Ball {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties {
|
||||||
|
MassProperties::from_ball(density, self.radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Ball
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl Shape for Polygon {
|
||||||
|
// #[cfg(feature = "serde-serialize")]
|
||||||
|
// fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
// Some(self as &dyn Serialize)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
// self.aabb(position)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn mass_properties(&self, _density: f32) -> MassProperties {
|
||||||
|
// unimplemented!()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn shape_type(&self) -> ShapeType {
|
||||||
|
// ShapeType::Polygon
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl Shape for Cuboid {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties {
|
||||||
|
MassProperties::from_cuboid(density, self.half_extents)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Cuboid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
|
||||||
|
Some(self as &dyn PolygonalFeatureMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for Capsule {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties {
|
||||||
|
MassProperties::from_capsule(density, self.half_height, self.radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Capsule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for Triangle {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties {
|
||||||
|
MassProperties::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Triangle
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
|
||||||
|
Some(self as &dyn PolygonalFeatureMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for Trimesh {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.aabb(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, _density: f32) -> MassProperties {
|
||||||
|
MassProperties::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Trimesh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for HeightField {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, _density: f32) -> MassProperties {
|
||||||
|
MassProperties::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::HeightField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
impl Shape for Cylinder {
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
fn as_serialize(&self) -> Option<&dyn Serialize> {
|
||||||
|
Some(self as &dyn Serialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
|
||||||
|
self.bounding_volume(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mass_properties(&self, density: f32) -> MassProperties {
|
||||||
|
MassProperties::from_cylinder(density, self.half_height, self.radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_type(&self) -> ShapeType {
|
||||||
|
ShapeType::Cylinder
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
|
||||||
|
Some(self as &dyn PolygonalFeatureMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
use crate::geometry::{Triangle, WQuadtree};
|
use crate::geometry::{PointProjection, Ray, RayIntersection, Triangle, WQuadtree};
|
||||||
use crate::math::{Isometry, Point};
|
use crate::math::{Isometry, Point};
|
||||||
use na::Point3;
|
use na::Point3;
|
||||||
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
|
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
|
||||||
|
use ncollide::query::{PointQuery, RayCast};
|
||||||
#[cfg(feature = "dim3")]
|
use ncollide::shape::FeatureId;
|
||||||
use {
|
|
||||||
crate::geometry::{Ray, RayIntersection},
|
|
||||||
ncollide::query::RayCast,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
@@ -110,6 +106,41 @@ impl Trimesh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PointQuery<f32> for Trimesh {
|
||||||
|
fn project_point(&self, m: &Isometry<f32>, pt: &Point<f32>, solid: bool) -> PointProjection {
|
||||||
|
// TODO
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn project_point_with_feature(
|
||||||
|
&self,
|
||||||
|
m: &Isometry<f32>,
|
||||||
|
pt: &Point<f32>,
|
||||||
|
) -> (PointProjection, FeatureId) {
|
||||||
|
// TODO
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
impl RayCast<f32> for Trimesh {
|
||||||
|
fn toi_and_normal_with_ray(
|
||||||
|
&self,
|
||||||
|
m: &Isometry<f32>,
|
||||||
|
ray: &Ray,
|
||||||
|
max_toi: f32,
|
||||||
|
solid: bool,
|
||||||
|
) -> Option<RayIntersection> {
|
||||||
|
// TODO
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersects_ray(&self, m: &Isometry<f32>, ray: &Ray, max_toi: f32) -> bool {
|
||||||
|
// TODO
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
impl RayCast<f32> for Trimesh {
|
impl RayCast<f32> for Trimesh {
|
||||||
fn toi_and_normal_with_ray(
|
fn toi_and_normal_with_ray(
|
||||||
|
|||||||
@@ -69,7 +69,11 @@ impl QueryPipeline {
|
|||||||
|
|
||||||
for handle in inter {
|
for handle in inter {
|
||||||
let collider = &colliders[handle];
|
let collider = &colliders[handle];
|
||||||
if let Some(inter) = collider.shape().cast_ray(collider.position(), ray, max_toi) {
|
if let Some(inter) =
|
||||||
|
collider
|
||||||
|
.shape()
|
||||||
|
.toi_and_normal_with_ray(collider.position(), ray, max_toi, true)
|
||||||
|
{
|
||||||
if inter.toi < best {
|
if inter.toi < best {
|
||||||
best = inter.toi;
|
best = inter.toi;
|
||||||
result = Some((handle, collider, inter));
|
result = Some((handle, collider, inter));
|
||||||
@@ -103,7 +107,11 @@ impl QueryPipeline {
|
|||||||
|
|
||||||
for handle in inter {
|
for handle in inter {
|
||||||
let collider = &colliders[handle];
|
let collider = &colliders[handle];
|
||||||
if let Some(inter) = collider.shape().cast_ray(collider.position(), ray, max_toi) {
|
if let Some(inter) =
|
||||||
|
collider
|
||||||
|
.shape()
|
||||||
|
.toi_and_normal_with_ray(collider.position(), ray, max_toi, true)
|
||||||
|
{
|
||||||
if !callback(handle, collider, inter) {
|
if !callback(handle, collider, inter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/utils.rs
26
src/utils.rs
@@ -1,6 +1,7 @@
|
|||||||
//! Miscellaneous utilities.
|
//! Miscellaneous utilities.
|
||||||
|
|
||||||
use crate::dynamics::RigidBodyHandle;
|
use crate::dynamics::RigidBodyHandle;
|
||||||
|
use crate::math::{Isometry, Point, Rotation, Vector};
|
||||||
#[cfg(all(feature = "enhanced-determinism", feature = "serde-serialize"))]
|
#[cfg(all(feature = "enhanced-determinism", feature = "serde-serialize"))]
|
||||||
use indexmap::IndexMap as HashMap;
|
use indexmap::IndexMap as HashMap;
|
||||||
use na::{Matrix2, Matrix3, Matrix3x2, Point2, Point3, Scalar, SimdRealField, Vector2, Vector3};
|
use na::{Matrix2, Matrix3, Matrix3x2, Point2, Point3, Scalar, SimdRealField, Vector2, Vector3};
|
||||||
@@ -1332,3 +1333,28 @@ pub(crate) fn other_handle(
|
|||||||
pair.0
|
pair.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the rotation that aligns the y axis to the segment direction.
|
||||||
|
pub(crate) fn rotation_wrt_y(a: &Point<f32>, b: &Point<f32>) -> Rotation<f32> {
|
||||||
|
let mut dir = b - a;
|
||||||
|
|
||||||
|
if dir.y < 0.0 {
|
||||||
|
dir = -dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
return Rotation::rotation_between(&Vector::y(), &dir);
|
||||||
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
return Rotation::rotation_between(&Vector::y(), &dir).unwrap_or(Rotation::identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the transform that aligns the y axis to the segment and move the origin to the segment middle,
|
||||||
|
// and the capsule's half-height.
|
||||||
|
pub(crate) fn segment_to_capsule(a: &Point<f32>, b: &Point<f32>) -> (Isometry<f32>, f32) {
|
||||||
|
let rot = rotation_wrt_y(a, b);
|
||||||
|
let half_height = (b - a).norm() / 2.0;
|
||||||
|
let center = na::center(a, b);
|
||||||
|
let pos = Isometry::from_parts(center.coords.into(), rot);
|
||||||
|
(pos, half_height)
|
||||||
|
}
|
||||||
|
|||||||
@@ -350,33 +350,44 @@ impl GraphicsManager {
|
|||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
out: &mut Vec<Node>,
|
out: &mut Vec<Node>,
|
||||||
) {
|
) {
|
||||||
match collider.shape() {
|
let shape = collider.shape();
|
||||||
Shape::Ball(ball) => {
|
|
||||||
out.push(Node::Ball(Ball::new(handle, ball.radius, color, window)))
|
if let Some(ball) = shape.as_ball() {
|
||||||
}
|
out.push(Node::Ball(Ball::new(handle, ball.radius, color, window)))
|
||||||
Shape::Polygon(poly) => out.push(Node::Convex(Convex::new(
|
}
|
||||||
handle,
|
|
||||||
poly.vertices().to_vec(),
|
// Shape::Polygon(poly) => out.push(Node::Convex(Convex::new(
|
||||||
color,
|
// handle,
|
||||||
window,
|
// poly.vertices().to_vec(),
|
||||||
))),
|
// color,
|
||||||
Shape::Cuboid(cuboid) => out.push(Node::Box(BoxNode::new(
|
// window,
|
||||||
|
// ))),
|
||||||
|
|
||||||
|
if let Some(cuboid) = shape.as_cuboid() {
|
||||||
|
out.push(Node::Box(BoxNode::new(
|
||||||
handle,
|
handle,
|
||||||
cuboid.half_extents,
|
cuboid.half_extents,
|
||||||
color,
|
color,
|
||||||
window,
|
window,
|
||||||
))),
|
)))
|
||||||
Shape::Capsule(capsule) => {
|
}
|
||||||
out.push(Node::Capsule(Capsule::new(handle, capsule, color, window)))
|
|
||||||
}
|
if let Some(capsule) = shape.as_capsule() {
|
||||||
Shape::Triangle(triangle) => out.push(Node::Mesh(Mesh::new(
|
out.push(Node::Capsule(Capsule::new(handle, capsule, color, window)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(triangle) = shape.as_triangle() {
|
||||||
|
out.push(Node::Mesh(Mesh::new(
|
||||||
handle,
|
handle,
|
||||||
vec![triangle.a, triangle.b, triangle.c],
|
vec![triangle.a, triangle.b, triangle.c],
|
||||||
vec![Point3::new(0, 1, 2)],
|
vec![Point3::new(0, 1, 2)],
|
||||||
color,
|
color,
|
||||||
window,
|
window,
|
||||||
))),
|
)))
|
||||||
Shape::Trimesh(trimesh) => out.push(Node::Mesh(Mesh::new(
|
}
|
||||||
|
|
||||||
|
if let Some(trimesh) = shape.as_trimesh() {
|
||||||
|
out.push(Node::Mesh(Mesh::new(
|
||||||
handle,
|
handle,
|
||||||
trimesh.vertices().to_vec(),
|
trimesh.vertices().to_vec(),
|
||||||
trimesh
|
trimesh
|
||||||
@@ -386,21 +397,27 @@ impl GraphicsManager {
|
|||||||
.collect(),
|
.collect(),
|
||||||
color,
|
color,
|
||||||
window,
|
window,
|
||||||
))),
|
)))
|
||||||
Shape::HeightField(heightfield) => out.push(Node::HeightField(HeightField::new(
|
}
|
||||||
|
|
||||||
|
if let Some(heightfield) = shape.as_heightfield() {
|
||||||
|
out.push(Node::HeightField(HeightField::new(
|
||||||
handle,
|
handle,
|
||||||
heightfield,
|
heightfield,
|
||||||
color,
|
color,
|
||||||
window,
|
window,
|
||||||
))),
|
)))
|
||||||
#[cfg(feature = "dim3")]
|
}
|
||||||
Shape::Cylinder(cylinder) => out.push(Node::Cylinder(Cylinder::new(
|
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
if let Some(cylinder) = shape.as_cylinder() {
|
||||||
|
out.push(Node::Cylinder(Cylinder::new(
|
||||||
handle,
|
handle,
|
||||||
cylinder.half_height,
|
cylinder.half_height,
|
||||||
cylinder.radius,
|
cylinder.radius,
|
||||||
color,
|
color,
|
||||||
window,
|
window,
|
||||||
))),
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user