commit d07cb1ab98d7fa59a16ab8842bf273f7ad2586ca
parent 750547eaa9bec4e367975fd0d8c84771ac01170a
Author: Kel <kel@unclear.info>
Date: Tue, 9 Jul 2019 12:35:37 -0400
Support all nphysics shapes (#8)
* Add support for all shapes
* That fork was a mistake
* Fix documentation
Diffstat:
13 files changed, 181 insertions(+), 124 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -24,9 +24,10 @@ specs = "0.14.3"
specs-hierarchy = "0.3.1"
shrev = "1.1.1"
nalgebra = "0.18.0"
-ncollide3d = "0.19.1"
+ncollide3d = "0.19"
nphysics3d = "0.11.1"
amethyst_core = { version = "0.6.0", optional = true }
+objekt = "0.1.2"
[dev-dependencies]
simple_logger = "1.2.0"
diff --git a/examples/basic.rs b/examples/basic.rs
@@ -4,12 +4,9 @@ extern crate simple_logger;
use specs::world::{Builder, World};
use specs_physics::{
colliders::Shape,
- nalgebra::Isometry3,
+ nalgebra::{Isometry3, Vector3},
nphysics::object::BodyStatus,
- physics_dispatcher,
- PhysicsBodyBuilder,
- PhysicsColliderBuilder,
- SimplePosition,
+ physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition,
};
fn main() {
@@ -31,7 +28,12 @@ fn main() {
1.0, 1.0, 1.0,
)))
.with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Dynamic).build())
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(1.0, 1.0, 1.0),
+ })
+ .build(),
+ )
.build();
// execute the dispatcher
diff --git a/examples/collision.rs b/examples/collision.rs
@@ -5,12 +5,9 @@ extern crate simple_logger;
use specs::world::{Builder, World};
use specs_physics::{
colliders::Shape,
- nalgebra::Isometry3,
+ nalgebra::{Isometry3, Vector3},
nphysics::{algebra::Velocity3, object::BodyStatus},
- physics_dispatcher,
- PhysicsBodyBuilder,
- PhysicsColliderBuilder,
- SimplePosition,
+ physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition,
};
fn main() {
@@ -36,7 +33,12 @@ fn main() {
.velocity(Velocity3::linear(1.0, 0.0, 0.0))
.build(),
)
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(2.0, 2.0, 1.0),
+ })
+ .build(),
+ )
.build();
// create an Entity with a static PhysicsBody component right next to the first
@@ -47,7 +49,12 @@ fn main() {
3.0, 1.0, 1.0,
)))
.with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Static).build())
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(2.0, 2.0, 1.0),
+ })
+ .build(),
+ )
.build();
// execute the dispatcher
diff --git a/examples/events.rs b/examples/events.rs
@@ -6,12 +6,9 @@ use specs::world::{Builder, World};
use specs_physics::{
colliders::Shape,
events::ContactEvents,
- nalgebra::Isometry3,
+ nalgebra::{Isometry3, Vector3},
nphysics::{algebra::Velocity3, object::BodyStatus},
- physics_dispatcher,
- PhysicsBodyBuilder,
- PhysicsColliderBuilder,
- SimplePosition,
+ physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition,
};
fn main() {
@@ -38,7 +35,12 @@ fn main() {
.velocity(Velocity3::linear(1.0, 0.0, 0.0))
.build(),
)
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(2.0, 2.0, 1.0),
+ })
+ .build(),
+ )
.build();
// create an Entity with a static PhysicsBody component right now to the first
@@ -49,7 +51,12 @@ fn main() {
3.0, 1.0, 1.0,
)))
.with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Static).build())
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(2.0, 2.0, 1.0),
+ })
+ .build(),
+ )
.build();
// execute the dispatcher
diff --git a/examples/hierarchy.rs b/examples/hierarchy.rs
@@ -4,13 +4,9 @@ extern crate simple_logger;
use specs::world::{Builder, World};
use specs_physics::{
colliders::Shape,
- nalgebra::Isometry3,
+ nalgebra::{Isometry3, Vector3},
nphysics::object::BodyStatus,
- physics_dispatcher,
- PhysicsBodyBuilder,
- PhysicsColliderBuilder,
- PhysicsParent,
- SimplePosition,
+ physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, PhysicsParent, SimplePosition,
};
fn main() {
@@ -33,7 +29,12 @@ fn main() {
1.0, 1.0, 1.0,
)))
.with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Dynamic).build())
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(1.0, 1.0, 1.0),
+ })
+ .build(),
+ )
.build();
// create the child Entity; if this Entity has its own PhysicsBody it'll more or
@@ -46,9 +47,11 @@ fn main() {
1.0, 1.0, 1.0,
)))
.with(
- PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0))
- .sensor(true)
- .build(),
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(1.0, 1.0, 1.0),
+ })
+ .sensor(true)
+ .build(),
)
.with(PhysicsParent { entity: parent })
.build();
diff --git a/examples/positions.rs b/examples/positions.rs
@@ -5,12 +5,9 @@ extern crate simple_logger;
use specs::world::{Builder, World};
use specs_physics::{
colliders::Shape,
- nalgebra::Isometry3,
+ nalgebra::{Isometry3, Vector3},
nphysics::{algebra::Velocity3, object::BodyStatus},
- physics_dispatcher,
- PhysicsBodyBuilder,
- PhysicsColliderBuilder,
- SimplePosition,
+ physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition,
};
fn main() {
@@ -37,7 +34,12 @@ fn main() {
.velocity(Velocity3::linear(1.0, 0.0, 0.0))
.build(),
)
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build())
+ .with(
+ PhysicsColliderBuilder::<f32>::from(Shape::Cuboid {
+ half_extents: Vector3::new(1.0, 1.0, 1.0),
+ })
+ .build(),
+ )
.build();
// execute the dispatcher
diff --git a/src/colliders.rs b/src/colliders.rs
@@ -1,11 +1,14 @@
-use std::{f32::consts::PI, fmt};
+use std::{f32::consts::PI, fmt, ops::Deref};
use specs::{Component, DenseVecStorage, FlaggedStorage};
use crate::{
- nalgebra::{Isometry3, RealField, Vector3},
+ nalgebra::{DMatrix, Isometry3, Point2, Point3, RealField, Unit, Vector3},
ncollide::{
- shape::{Ball, Cuboid, ShapeHandle},
+ shape::{
+ Ball, Capsule, Compound, ConvexHull, Cuboid, HeightField, Plane, Polyline, Segment,
+ ShapeHandle, TriMesh, Triangle,
+ },
world::CollisionGroups,
},
nphysics::{
@@ -14,27 +17,109 @@ use crate::{
},
};
+pub type MeshData<N> = (Vec<Point3<N>>, Vec<Point3<usize>>, Option<Vec<Point2<N>>>);
+
+pub trait IntoMesh: objekt::Clone + Send + Sync {
+ type N: RealField;
+
+ fn points(&self) -> MeshData<Self::N>;
+}
+
+impl<'clone, N: RealField> IntoMesh for Box<(dyn IntoMesh<N = N> + 'clone)> {
+ type N = N;
+
+ fn points(&self) -> MeshData<Self::N> {
+ self.deref().points()
+ }
+}
+
+impl<'clone, N: RealField> Clone for Box<dyn IntoMesh<N = N> + 'clone> {
+ fn clone(&self) -> Self {
+ objekt::clone_box(&*self)
+ }
+}
+
/// `Shape` serves as an abstraction over nphysics `ShapeHandle`s and makes it
/// easier to configure and define said `ShapeHandle`s for the user without
/// having to know the underlying nphysics API.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone)]
pub enum Shape<N: RealField> {
- Circle(N),
- Rectangle(N, N, N),
+ Ball {
+ radius: N,
+ },
+ Capsule {
+ half_height: N,
+ radius: N,
+ },
+ Compound {
+ parts: Vec<(Isometry3<N>, Shape<N>)>,
+ },
+ ConvexHull {
+ points: Vec<Point3<N>>,
+ },
+ Cuboid {
+ half_extents: Vector3<N>,
+ },
+ HeightField {
+ heights: DMatrix<N>,
+ scale: Vector3<N>,
+ },
+ Plane {
+ normal: Unit<Vector3<N>>,
+ },
+ Polyline {
+ points: Vec<Point3<N>>,
+ indices: Option<Vec<Point2<usize>>>,
+ },
+ Segment {
+ a: Point3<N>,
+ b: Point3<N>,
+ },
+ TriMesh {
+ handle: Box<dyn IntoMesh<N = N>>,
+ },
+ Triangle {
+ a: Point3<N>,
+ b: Point3<N>,
+ c: Point3<N>,
+ },
}
impl<N: RealField> Shape<N> {
/// Converts a `Shape` and its values into its corresponding `ShapeHandle`
/// type. The `ShapeHandle` is used to define a `Collider` in the
/// `PhysicsWorld`.
- fn handle(&self, margin: N) -> ShapeHandle<N> {
- match *self {
- Shape::Circle(radius) => ShapeHandle::new(Ball::new(radius)),
- Shape::Rectangle(width, height, depth) => ShapeHandle::new(Cuboid::new(Vector3::new(
- width / N::from_f32(2.0).unwrap() - margin,
- height / N::from_f32(2.0).unwrap() - margin,
- depth / N::from_f32(2.0).unwrap() - margin,
- ))),
+ fn handle(&self) -> ShapeHandle<N> {
+ match self {
+ Shape::Ball { radius } => ShapeHandle::new(Ball::<N>::new(*radius)),
+ Shape::Capsule {
+ half_height,
+ radius,
+ } => ShapeHandle::new(Capsule::new(*half_height, *radius)),
+ Shape::Compound { parts } => ShapeHandle::new(Compound::new(
+ parts
+ .into_iter()
+ .map(|part| (part.0, part.1.handle()))
+ .collect(),
+ )),
+ Shape::ConvexHull { points } => ShapeHandle::new(
+ ConvexHull::try_from_points(&points)
+ .expect("Failed to generate Convex Hull from points."),
+ ),
+ Shape::Cuboid { half_extents } => ShapeHandle::new(Cuboid::new(*half_extents)),
+ Shape::HeightField { heights, scale } => {
+ ShapeHandle::new(HeightField::new(heights.clone(), *scale))
+ }
+ Shape::Plane { normal } => ShapeHandle::new(Plane::new(*normal)),
+ Shape::Polyline { points, indices } => {
+ ShapeHandle::new(Polyline::new(points.clone(), indices.clone()))
+ }
+ Shape::Segment { a, b } => ShapeHandle::new(Segment::new(*a, *b)),
+ Shape::TriMesh { handle } => {
+ let data = handle.points();
+ ShapeHandle::new(TriMesh::new(data.0, data.1, data.2))
+ }
+ Shape::Triangle { a, b, c } => ShapeHandle::new(Triangle::new(*a, *b, *c)),
}
}
}
@@ -92,7 +177,7 @@ impl<N: RealField> PhysicsCollider<N> {
/// Returns the `ShapeHandle` for `shape`, taking the `margin` into
/// consideration.
pub(crate) fn shape_handle(&self) -> ShapeHandle<N> {
- self.shape.handle(self.margin)
+ self.shape.handle()
}
}
@@ -105,13 +190,13 @@ impl<N: RealField> PhysicsCollider<N> {
/// ```rust
/// use specs_physics::{
/// colliders::Shape,
-/// nalgebra::Isometry3,
+/// nalgebra::{Isometry3, Vector3},
/// ncollide::world::CollisionGroups,
/// nphysics::material::{BasicMaterial, MaterialHandle},
/// PhysicsColliderBuilder,
/// };
///
-/// let physics_collider = PhysicsColliderBuilder::from(Shape::Rectangle(10.0, 10.0, 1.0))
+/// let physics_collider = PhysicsColliderBuilder::from(Shape::Cuboid{ half_extents: Vector3::new(10.0, 10.0, 1.0) })
/// .offset_from_parent(Isometry3::identity())
/// .density(1.2)
/// .material(MaterialHandle::new(BasicMaterial::default()))
diff --git a/src/lib.rs b/src/lib.rs
@@ -113,13 +113,14 @@
//! ```rust
//! use specs_physics::{
//! colliders::Shape,
-//! nalgebra::Isometry3,
+//! nalgebra::{Isometry3, Vector3},
//! ncollide::world::CollisionGroups,
//! nphysics::material::{BasicMaterial, MaterialHandle},
//! PhysicsColliderBuilder,
//! };
//!
-//! let physics_collider = PhysicsColliderBuilder::from(Shape::Rectangle(10.0, 10.0, 1.0))
+//! let physics_collider = PhysicsColliderBuilder::from(
+//! Shape::Cuboid{ half_extents: Vector3::new(10.0, 10.0, 1.0) })
//! .offset_from_parent(Isometry3::identity())
//! .density(1.2)
//! .material(MaterialHandle::new(BasicMaterial::default()))
@@ -246,13 +247,7 @@ pub use shrev;
use std::collections::HashMap;
use specs::{
- world::Index,
- Component,
- DenseVecStorage,
- Dispatcher,
- DispatcherBuilder,
- Entity,
- FlaggedStorage,
+ world::Index, Component, DenseVecStorage, Dispatcher, DispatcherBuilder, Entity, FlaggedStorage,
};
use specs_hierarchy::Parent;
@@ -272,11 +267,8 @@ use self::{
world::World,
},
systems::{
- PhysicsStepperSystem,
- SyncBodiesFromPhysicsSystem,
- SyncBodiesToPhysicsSystem,
- SyncCollidersToPhysicsSystem,
- SyncParametersToPhysicsSystem,
+ PhysicsStepperSystem, SyncBodiesFromPhysicsSystem, SyncBodiesToPhysicsSystem,
+ SyncCollidersToPhysicsSystem, SyncParametersToPhysicsSystem,
},
};
diff --git a/src/systems/mod.rs b/src/systems/mod.rs
@@ -2,16 +2,11 @@ use std::ops::Deref;
use specs::{
storage::{ComponentEvent, MaskedStorage},
- BitSet,
- Component,
- ReaderId,
- Storage,
- Tracked,
+ BitSet, Component, ReaderId, Storage, Tracked,
};
pub use self::{
- physics_stepper::PhysicsStepperSystem,
- sync_bodies_from_physics::SyncBodiesFromPhysicsSystem,
+ physics_stepper::PhysicsStepperSystem, sync_bodies_from_physics::SyncBodiesFromPhysicsSystem,
sync_bodies_to_physics::SyncBodiesToPhysicsSystem,
sync_colliders_to_physics::SyncCollidersToPhysicsSystem,
sync_parameters_to_physics::SyncParametersToPhysicsSystem,
diff --git a/src/systems/physics_stepper.rs b/src/systems/physics_stepper.rs
@@ -1,15 +1,7 @@
use std::marker::PhantomData;
use specs::{
- world::Index,
- Entities,
- Entity,
- Read,
- Resources,
- System,
- SystemData,
- Write,
- WriteExpect,
+ world::Index, Entities, Entity, Read, Resources, System, SystemData, Write, WriteExpect,
};
use crate::{
diff --git a/src/systems/sync_bodies_to_physics.rs b/src/systems/sync_bodies_to_physics.rs
@@ -1,17 +1,8 @@
use std::marker::PhantomData;
use specs::{
- storage::ComponentEvent,
- world::Index,
- BitSet,
- Join,
- ReadStorage,
- ReaderId,
- Resources,
- System,
- SystemData,
- WriteExpect,
- WriteStorage,
+ storage::ComponentEvent, world::Index, BitSet, Join, ReadStorage, ReaderId, Resources, System,
+ SystemData, WriteExpect, WriteStorage,
};
use crate::{
@@ -209,12 +200,8 @@ where
#[cfg(test)]
mod tests {
use crate::{
- nalgebra::Isometry3,
- nphysics::object::BodyStatus,
- systems::SyncBodiesToPhysicsSystem,
- Physics,
- PhysicsBodyBuilder,
- SimplePosition,
+ nalgebra::Isometry3, nphysics::object::BodyStatus, systems::SyncBodiesToPhysicsSystem,
+ Physics, PhysicsBodyBuilder, SimplePosition,
};
use specs::{world::Builder, DispatcherBuilder, World};
diff --git a/src/systems/sync_colliders_to_physics.rs b/src/systems/sync_colliders_to_physics.rs
@@ -1,16 +1,8 @@
use std::marker::PhantomData;
use specs::{
- storage::ComponentEvent,
- world::Index,
- Join,
- ReadStorage,
- ReaderId,
- Resources,
- System,
- SystemData,
- WriteExpect,
- WriteStorage,
+ storage::ComponentEvent, world::Index, Join, ReadStorage, ReaderId, Resources, System,
+ SystemData, WriteExpect, WriteStorage,
};
use crate::{
@@ -18,8 +10,7 @@ use crate::{
colliders::PhysicsCollider,
nalgebra::RealField,
nphysics::object::{BodyPartHandle, ColliderDesc},
- Physics,
- PhysicsParent,
+ Physics, PhysicsParent,
};
use super::iterate_component_events;
@@ -257,12 +248,8 @@ mod tests {
use specs::{world::Builder, DispatcherBuilder, World};
use crate::{
- colliders::Shape,
- nalgebra::Isometry3,
- systems::SyncCollidersToPhysicsSystem,
- Physics,
- PhysicsColliderBuilder,
- SimplePosition,
+ colliders::Shape, nalgebra::Isometry3, systems::SyncCollidersToPhysicsSystem, Physics,
+ PhysicsColliderBuilder, SimplePosition,
};
#[test]
@@ -284,7 +271,7 @@ mod tests {
.with(SimplePosition::<f32>(Isometry3::<f32>::translation(
1.0, 1.0, 1.0,
)))
- .with(PhysicsColliderBuilder::<f32>::from(Shape::Circle(5.0)).build())
+ .with(PhysicsColliderBuilder::<f32>::from(Shape::Ball { radius: 5.0 }).build())
.build();
dispatcher.dispatch(&mut world.res);
diff --git a/src/systems/sync_parameters_to_physics.rs b/src/systems/sync_parameters_to_physics.rs
@@ -82,10 +82,7 @@ mod tests {
use specs::{DispatcherBuilder, World};
use crate::{
- nalgebra::Vector3,
- parameters::Gravity,
- systems::SyncParametersToPhysicsSystem,
- Physics,
+ nalgebra::Vector3, parameters::Gravity, systems::SyncParametersToPhysicsSystem, Physics,
};
#[test]