diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-12-22 16:23:41 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-22 16:23:41 +0100 |
| commit | fd3b4801b63fd56369ff37bdc2e5189db159e8ff (patch) | |
| tree | a2017a39480dcd9045da00dbf0ff9c60d6b16259 | |
| parent | d7cd20d3e4b0fdd963705bbef42520dc05811a56 (diff) | |
| parent | 496f4e32588d4f5efd821e7834ddd0d7b0dd1acc (diff) | |
| download | rapier-fd3b4801b63fd56369ff37bdc2e5189db159e8ff.tar.gz rapier-fd3b4801b63fd56369ff37bdc2e5189db159e8ff.tar.bz2 rapier-fd3b4801b63fd56369ff37bdc2e5189db159e8ff.zip | |
Merge pull request #81 from rezural/harness
Introduce a run harness, to make running salva with rapier easier with headless.
| -rw-r--r-- | benchmarks3d/Cargo.toml | 4 | ||||
| -rw-r--r-- | benchmarks3d/harness_capsules3.rs | 72 | ||||
| -rw-r--r-- | src_testbed/harness/mod.rs | 186 | ||||
| -rw-r--r-- | src_testbed/harness/plugin.rs | 15 | ||||
| -rw-r--r-- | src_testbed/lib.rs | 5 |
5 files changed, 281 insertions, 1 deletions
diff --git a/benchmarks3d/Cargo.toml b/benchmarks3d/Cargo.toml index 03194df..1ae91e4 100644 --- a/benchmarks3d/Cargo.toml +++ b/benchmarks3d/Cargo.toml @@ -25,3 +25,7 @@ path = "../build/rapier3d" [[bin]] name = "all_benchmarks3" path = "all_benchmarks3.rs" + +[[bin]] +name = "harness_capsules3" +path = "harness_capsules3.rs" diff --git a/benchmarks3d/harness_capsules3.rs b/benchmarks3d/harness_capsules3.rs new file mode 100644 index 0000000..4632811 --- /dev/null +++ b/benchmarks3d/harness_capsules3.rs @@ -0,0 +1,72 @@ +extern crate nalgebra as na; + +use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet}; +use rapier3d::geometry::{ColliderBuilder, ColliderSet}; +use rapier_testbed3d::harness::Harness; + +pub fn init_world(harness: &mut Harness) { + /* + * World + */ + let mut bodies = RigidBodySet::new(); + let mut colliders = ColliderSet::new(); + let joints = JointSet::new(); + + /* + * Ground + */ + let ground_size = 200.1; + let ground_height = 0.1; + + let rigid_body = RigidBodyBuilder::new_static() + .translation(0.0, -ground_height, 0.0) + .build(); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).build(); + colliders.insert(collider, handle, &mut bodies); + + /* + * Create the cubes + */ + let num = 8; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let shifty = rad * 4.0; + let centerx = shift * (num / 2) as f32; + let centery = shift / 2.0; + let centerz = shift * (num / 2) as f32; + + let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; + + for j in 0usize..47 { + for i in 0..num { + for k in 0usize..num { + let x = i as f32 * shift - centerx + offset; + let y = j as f32 * shifty + centery + 3.0; + let z = k as f32 * shift - centerz + offset; + + // Build the rigid body. + let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y, z).build(); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::capsule_y(rad, rad).build(); + colliders.insert(collider, handle, &mut bodies); + } + } + + offset -= 0.05 * rad * (num as f32 - 1.0); + } + + /* + * Set up the harness. + */ + harness.set_world(bodies, colliders, joints); +} + +fn main() { + let harness = &mut Harness::new_empty(); + init_world(harness); + harness.set_max_steps(10000); + harness.run(); + println!("{}", harness.state.timestep_id); +} diff --git a/src_testbed/harness/mod.rs b/src_testbed/harness/mod.rs new file mode 100644 index 0000000..fa6c4c6 --- /dev/null +++ b/src_testbed/harness/mod.rs @@ -0,0 +1,186 @@ +use crate::physics::{PhysicsEvents, PhysicsState}; +use plugin::HarnessPlugin; +use rapier::dynamics::{IntegrationParameters, JointSet, RigidBodySet}; +use rapier::geometry::{BroadPhase, ColliderSet, NarrowPhase}; +use rapier::math::Vector; +use rapier::pipeline::{ChannelEventCollector, PhysicsPipeline, QueryPipeline}; + +pub mod plugin; + +pub struct HarnessState { + #[cfg(feature = "parallel")] + pub thread_pool: rapier::rayon::ThreadPool, + pub timestep_id: usize, +} + +pub struct Harness { + physics: PhysicsState, + max_steps: usize, + callbacks: Callbacks, + plugins: Vec<Box<dyn HarnessPlugin>>, + time: f32, + events: PhysicsEvents, + event_handler: ChannelEventCollector, + pub state: HarnessState, +} + +type Callbacks = Vec<Box<dyn FnMut(&mut PhysicsState, &PhysicsEvents, &HarnessState, f32)>>; + +#[allow(dead_code)] +impl Harness { + pub fn new_empty() -> Self { + #[cfg(feature = "parallel")] + let num_threads = num_cpus::get_physical(); + + #[cfg(feature = "parallel")] + let thread_pool = rapier::rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build() + .unwrap(); + + let contact_channel = crossbeam::channel::unbounded(); + let proximity_channel = crossbeam::channel::unbounded(); + let event_handler = ChannelEventCollector::new(proximity_channel.0, contact_channel.0); + let events = PhysicsEvents { + contact_events: contact_channel.1, + proximity_events: proximity_channel.1, + }; + let physics = PhysicsState::new(); + let state = HarnessState { + #[cfg(feature = "parallel")] + thread_pool, + timestep_id: 0, + }; + + Self { + physics, + max_steps: 1000, + callbacks: Vec::new(), + plugins: Vec::new(), + time: 0.0, + events, + event_handler, + state, + } + } + + pub fn new(bodies: RigidBodySet, colliders: ColliderSet, joints: JointSet) -> Self { + let mut res = Self::new_empty(); + res.set_world(bodies, colliders, joints); + res + } + + pub fn set_max_steps(&mut self, max_steps: usize) { + self.max_steps = max_steps + } + + pub fn integration_parameters_mut(&mut self) -> &mut IntegrationParameters { + &mut self.physics.integration_parameters + } + + pub fn physics_state_mut(&mut self) -> &mut PhysicsState { + &mut self.physics + } + + pub fn set_world(&mut self, bodies: RigidBodySet, colliders: ColliderSet, joints: JointSet) { + self.set_world_with_gravity(bodies, colliders, joints, Vector::y() * -9.81) + } + + pub fn set_world_with_gravity( + &mut self, + bodies: RigidBodySet, + colliders: ColliderSet, + joints: JointSet, + gravity: Vector<f32>, + ) { + // println!("Num bodies: {}", bodies.len()); + // println!("Num joints: {}", joints.len()); + self.physics.gravity = gravity; + self.physics.bodies = bodies; + self.physics.colliders = colliders; + self.physics.joints = joints; + self.physics.broad_phase = BroadPhase::new(); + self.physics.narrow_phase = NarrowPhase::new(); + self.time = 0.0; + self.state.timestep_id = 0; + self.physics.query_pipeline = QueryPipeline::new(); + self.physics.pipeline = PhysicsPipeline::new(); + self.physics.pipeline.counters.enable(); + } + + pub fn add_plugin(&mut self, plugin: impl HarnessPlugin + 'static) { + self.plugins.push(Box::new(plugin)); + } + + pub fn add_callback< + F: FnMut(&mut PhysicsState, &PhysicsEvents, &HarnessState, f32) + 'static, + >( + &mut self, + callback: F, + ) { + self.callbacks.push(Box::new(callback)); + } + + pub fn step(&mut self) { + #[cfg(feature = "parallel")] + { + let physics = &mut self.physics; + let event_handler = &self.event_handler; + self.state.thread_pool.install(|| { + physics.pipeline.step( + &physics.gravity, + &physics.integration_parameters, + &mut physics.broad_phase, + &mut physics.narrow_phase, + &mut physics.bodies, + &mut physics.colliders, + &mut physics.joints, + None, + None, + event_handler, + ); + }); + } + + #[cfg(not(feature = "parallel"))] + self.physics.pipeline.step( + &self.physics.gravity, + &self.physics.integration_parameters, + &mut self.physics.broad_phase, + &mut self.physics.narrow_phase, + &mut self.physics.bodies, + &mut self.physics.colliders, + &mut self.physics.joints, + None, + None, + &self.event_handler, + ); + + self.physics + .query_pipeline + .update(&self.physics.bodies, &self.physics.colliders); + + for plugin in &mut self.plugins { + plugin.step(&mut self.physics) + } + + for f in &mut self.callbacks { + f(&mut self.physics, &self.events, &self.state, self.time) + } + + for plugin in &mut self.plugins { + plugin.run_callbacks(&mut self.physics, &self.events, &self.state, self.time) + } + + self.events.poll_all(); + + self.time += self.physics.integration_parameters.dt(); + } + + pub fn run(&mut self) { + for _ in 0..self.max_steps { + self.step(); + self.state.timestep_id += 1; + } + } +} diff --git a/src_testbed/harness/plugin.rs b/src_testbed/harness/plugin.rs new file mode 100644 index 0000000..078219e --- /dev/null +++ b/src_testbed/harness/plugin.rs @@ -0,0 +1,15 @@ +use crate::harness::HarnessState; +use crate::physics::PhysicsEvents; +use crate::PhysicsState; + +pub trait HarnessPlugin { + fn run_callbacks( + &mut self, + physics: &mut PhysicsState, + events: &PhysicsEvents, + harness_state: &HarnessState, + t: f32, + ); + fn step(&mut self, physics: &mut PhysicsState); + fn profiling_string(&self) -> String; +} diff --git a/src_testbed/lib.rs b/src_testbed/lib.rs index e7475f0..5358e7c 100644 --- a/src_testbed/lib.rs +++ b/src_testbed/lib.rs @@ -22,16 +22,19 @@ extern crate bitflags; extern crate log; pub use crate::engine::GraphicsManager; +pub use crate::harness::plugin::HarnessPlugin; +pub use crate::physics::PhysicsState; pub use crate::plugin::TestbedPlugin; pub use crate::testbed::Testbed; #[cfg(all(feature = "dim2", feature = "other-backends"))] mod box2d_backend; mod engine; +pub mod harness; #[cfg(feature = "other-backends")] mod nphysics_backend; pub mod objects; -mod physics; +pub mod physics; #[cfg(all(feature = "dim3", feature = "other-backends"))] mod physx_backend; mod plugin; |
