aboutsummaryrefslogtreecommitdiff
path: root/examples3d
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2021-02-24 11:26:53 +0100
committerGitHub <noreply@github.com>2021-02-24 11:26:53 +0100
commit649eba10130673534a60b17a0343b15208e5d622 (patch)
tree0a5532b645945bbe542ad9a41d1344a318f307d8 /examples3d
parentd31a327b45118a77bd9676f350f110683a235acf (diff)
parent3cc2738e5fdcb0d25818b550cdff93eab75f1b20 (diff)
downloadrapier-649eba10130673534a60b17a0343b15208e5d622.tar.gz
rapier-649eba10130673534a60b17a0343b15208e5d622.tar.bz2
rapier-649eba10130673534a60b17a0343b15208e5d622.zip
Merge pull request #120 from dimforge/contact_modification
Add the ability to modify the contact points seen by the constraints solver
Diffstat (limited to 'examples3d')
-rw-r--r--examples3d/all_examples3.rs2
-rw-r--r--examples3d/damping3.rs2
-rw-r--r--examples3d/fountain3.rs6
-rw-r--r--examples3d/one_way_platforms3.rs143
4 files changed, 148 insertions, 5 deletions
diff --git a/examples3d/all_examples3.rs b/examples3d/all_examples3.rs
index 9cbf4c3..8a71665 100644
--- a/examples3d/all_examples3.rs
+++ b/examples3d/all_examples3.rs
@@ -29,6 +29,7 @@ mod heightfield3;
mod joints3;
mod keva3;
mod locked_rotations3;
+mod one_way_platforms3;
mod platform3;
mod primitives3;
mod restitution3;
@@ -83,6 +84,7 @@ pub fn main() {
("Heightfield", heightfield3::init_world),
("Joints", joints3::init_world),
("Locked rotations", locked_rotations3::init_world),
+ ("One-way platforms", one_way_platforms3::init_world),
("Platform", platform3::init_world),
("Restitution", restitution3::init_world),
("Sensor", sensor3::init_world),
diff --git a/examples3d/damping3.rs b/examples3d/damping3.rs
index 8c68d3b..3847ceb 100644
--- a/examples3d/damping3.rs
+++ b/examples3d/damping3.rs
@@ -40,6 +40,6 @@ pub fn init_world(testbed: &mut Testbed) {
/*
* Set up the testbed.
*/
- testbed.set_world_with_gravity(bodies, colliders, joints, Vector3::zeros());
+ testbed.set_world_with_params(bodies, colliders, joints, Vector3::zeros(), ());
testbed.look_at(Point3::new(2.0, 2.5, 20.0), Point3::new(2.0, 2.5, 0.0));
}
diff --git a/examples3d/fountain3.rs b/examples3d/fountain3.rs
index 5acc2e8..caaa21b 100644
--- a/examples3d/fountain3.rs
+++ b/examples3d/fountain3.rs
@@ -23,16 +23,14 @@ pub fn init_world(testbed: &mut Testbed) {
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).build();
colliders.insert(collider, handle, &mut bodies);
- let mut k = 0;
// Callback that will be executed on the main loop to handle proximities.
- testbed.add_callback(move |mut window, mut graphics, physics, _, _| {
- k += 1;
+ testbed.add_callback(move |mut window, mut graphics, physics, _, run_state| {
let rigid_body = RigidBodyBuilder::new_dynamic()
.translation(0.0, 10.0, 0.0)
.build();
let handle = physics.bodies.insert(rigid_body);
- let collider = match k % 3 {
+ let collider = match run_state.timestep_id % 3 {
0 => ColliderBuilder::round_cylinder(rad, rad, rad / 10.0).build(),
1 => ColliderBuilder::cone(rad, rad).build(),
_ => ColliderBuilder::cuboid(rad, rad, rad).build(),
diff --git a/examples3d/one_way_platforms3.rs b/examples3d/one_way_platforms3.rs
new file mode 100644
index 0000000..173d03d
--- /dev/null
+++ b/examples3d/one_way_platforms3.rs
@@ -0,0 +1,143 @@
+use na::{Point3, Vector3};
+use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
+use rapier3d::geometry::{ColliderBuilder, ColliderHandle, ColliderSet};
+use rapier3d::pipeline::{ContactModificationContext, PhysicsHooks, PhysicsHooksFlags};
+use rapier_testbed3d::Testbed;
+
+struct OneWayPlatformHook {
+ platform1: ColliderHandle,
+ platform2: ColliderHandle,
+}
+
+impl PhysicsHooks for OneWayPlatformHook {
+ fn active_hooks(&self) -> PhysicsHooksFlags {
+ PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS
+ }
+
+ fn modify_solver_contacts(&self, context: &mut ContactModificationContext) {
+ // The allowed normal for the first platform is its local +y axis, and the
+ // allowed normal for the second platform is its local -y axis.
+ //
+ // Now we have to be careful because the `manifold.local_n1` normal points
+ // toward the outside of the shape of `context.co1`. So we need to flip the
+ // allowed normal direction if the platform is in `context.collider_handle2`.
+ //
+ // Therefore:
+ // - If context.collider_handle1 == self.platform1 then the allowed normal is +y.
+ // - If context.collider_handle2 == self.platform1 then the allowed normal is -y.
+ // - If context.collider_handle1 == self.platform2 then its allowed normal +y needs to be flipped to -y.
+ // - If context.collider_handle2 == self.platform2 then the allowed normal -y needs to be flipped to +y.
+ let mut allowed_local_n1 = Vector3::zeros();
+
+ if context.collider_handle1 == self.platform1 {
+ allowed_local_n1 = Vector3::y();
+ } else if context.collider_handle2 == self.platform1 {
+ // Flip the allowed direction.
+ allowed_local_n1 = -Vector3::y();
+ }
+
+ if context.collider_handle1 == self.platform2 {
+ allowed_local_n1 = -Vector3::y();
+ } else if context.collider_handle2 == self.platform2 {
+ // Flip the allowed direction.
+ allowed_local_n1 = -Vector3::y();
+ }
+
+ // Call the helper function that simulates one-way platforms.
+ context.update_as_oneway_platform(&allowed_local_n1, 0.1);
+
+ // Set the surface velocity of the accepted contacts.
+ let tangent_velocity = if context.collider_handle1 == self.platform1
+ || context.collider_handle2 == self.platform2
+ {
+ -12.0
+ } else {
+ 12.0
+ };
+
+ for contact in context.solver_contacts.iter_mut() {
+ contact.tangent_velocity.z = tangent_velocity;
+ }
+ }
+}
+
+pub fn init_world(testbed: &mut Testbed) {
+ /*
+ * World
+ */
+ let mut bodies = RigidBodySet::new();
+ let mut colliders = ColliderSet::new();
+ let joints = JointSet::new();
+
+ /*
+ * Ground
+ */
+ let rigid_body = RigidBodyBuilder::new_static().build();
+ let handle = bodies.insert(rigid_body);
+
+ let collider = ColliderBuilder::cuboid(9.0, 0.5, 25.0)
+ .translation(0.0, 2.0, 30.0)
+ .modify_solver_contacts(true)
+ .build();
+ let platform1 = colliders.insert(collider, handle, &mut bodies);
+ let collider = ColliderBuilder::cuboid(9.0, 0.5, 25.0)
+ .translation(0.0, -2.0, -30.0)
+ .modify_solver_contacts(true)
+ .build();
+ let platform2 = colliders.insert(collider, handle, &mut bodies);
+
+ /*
+ * Setup the one-way platform hook.
+ */
+ let physics_hooks = OneWayPlatformHook {
+ platform1,
+ platform2,
+ };
+
+ /*
+ * Spawn cubes at regular intervals and apply a custom gravity
+ * depending on their position.
+ */
+ testbed.add_callback(move |mut window, mut graphics, physics, _, run_state| {
+ if run_state.timestep_id % 50 == 0 && physics.bodies.len() <= 7 {
+ // Spawn a new cube.
+ let collider = ColliderBuilder::cuboid(1.0, 2.0, 1.5).build();
+ let body = RigidBodyBuilder::new_dynamic()
+ .translation(0.0, 6.0, 20.0)
+ .build();
+ let handle = physics.bodies.insert(body);
+ physics
+ .colliders
+ .insert(collider, handle, &mut physics.bodies);
+
+ if let (Some(graphics), Some(window)) = (&mut graphics, &mut window) {
+ graphics.add(window, handle, &physics.bodies, &physics.colliders);
+ }
+ }
+
+ physics.bodies.foreach_active_dynamic_body_mut(|_, body| {
+ if body.position().translation.y > 1.0 {
+ body.set_gravity_scale(1.0, false);
+ } else if body.position().translation.y < -1.0 {
+ body.set_gravity_scale(-1.0, false);
+ }
+ });
+ });
+
+ /*
+ * Set up the testbed.
+ */
+ testbed.set_world_with_params(
+ bodies,
+ colliders,
+ joints,
+ Vector3::new(0.0, -9.81, 0.0),
+ physics_hooks,
+ );
+ testbed.look_at(Point3::new(-100.0, 0.0, 0.0), Point3::origin());
+}
+
+fn main() {
+ let testbed = Testbed::from_builders(0, vec![("Boxes", init_world)]);
+ testbed.run()
+}