Skip to content

Commit

Permalink
Merge pull request #53 from Jondolf/spatial-queries
Browse files Browse the repository at this point in the history
Add spatial queries
  • Loading branch information
Jondolf authored Jul 6, 2023
2 parents 27c53de + 0fa38a3 commit 2966c2b
Show file tree
Hide file tree
Showing 19 changed files with 2,190 additions and 7 deletions.
6 changes: 5 additions & 1 deletion crates/bevy_xpbd_2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ default = [ "2d", "f32" ]
2d = []
f32 = [ "dep:parry2d" ]
f64 = [ "dep:parry2d-f64" ]
debug-plugin = [ "dep:bevy_prototype_debug_lines" ]
debug-plugin = [ "dep:bevy_prototype_debug_lines", "examples_common_2d/debug-plugin" ]
simd = [ "parry2d?/simd-stable", "parry2d-f64?/simd-stable" ]
enhanced-determinism = [ "parry2d?/enhanced-determinism", "parry2d-f64?/enhanced-determinism" ]

Expand Down Expand Up @@ -61,6 +61,10 @@ required-features = ["2d"]
name = "prismatic_joint_2d"
required-features = ["2d"]

[[example]]
name = "ray_caster"
required-features = ["2d"]

[[example]]
name = "revolute_joint_2d"
required-features = ["2d"]
84 changes: 84 additions & 0 deletions crates/bevy_xpbd_2d/examples/ray_caster.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! A simple ray casting example that uses the [`RayCaster`] component.
//!
//! An alternative, more controlled approach is to use the methods of
//! the [`SpatialQuery`] system parameter.
#![allow(clippy::unnecessary_cast)]

use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
use bevy_xpbd_2d::prelude::*;
use examples_common_2d::{bevy_prototype_debug_lines::*, *};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(XpbdExamplePlugin)
.insert_resource(ClearColor(Color::rgb(0.05, 0.05, 0.1)))
.add_system(render_rays)
.add_startup_system(setup)
.run();
}

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(Camera2dBundle::default());

// Spawn a perimeter of circles that the ray will be cast against
let radius = 16.0;
for x in -4..=4 {
for y in -4..=4 {
if (-3..4).contains(&x) && (-3..4).contains(&y) {
continue;
}

commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(shape::Circle::new(radius as f32).into()).into(),
material: materials.add(ColorMaterial::from(Color::rgb(0.2, 0.7, 0.9))),
..default()
},
RigidBody::Kinematic,
Position(Vector::new(
x as Scalar * radius * 3.0,
y as Scalar * radius * 3.0,
)),
Collider::ball(radius),
));
}
}

// Spawn a rotating kinematic body with a ray caster
commands.spawn((
RigidBody::Kinematic,
AngularVelocity(0.2),
RayCaster::new(Vector::ZERO, Vector::X),
));
}

fn render_rays(mut rays: Query<(&mut RayCaster, &mut RayHits)>, mut lines: ResMut<DebugLines>) {
for (ray, hits) in &mut rays {
// Convert to Vec3 for lines
let origin = ray.global_origin().extend(0.0).as_f32();
let direction = ray.global_direction().extend(0.0).as_f32();

for hit in hits.iter() {
lines.line_colored(
origin,
origin + direction * hit.time_of_impact as f32,
0.001,
Color::GREEN,
);
}
if hits.is_empty() {
lines.line_colored(
origin,
origin + direction * 1_000_000.0,
0.001,
Color::ORANGE_RED,
);
}
}
}
2 changes: 1 addition & 1 deletion crates/bevy_xpbd_3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ default = [ "3d", "f32" ]
3d = []
f32 = [ "dep:parry3d" ]
f64 = [ "dep:parry3d-f64" ]
debug-plugin = [ "dep:bevy_prototype_debug_lines" ]
debug-plugin = [ "dep:bevy_prototype_debug_lines", "examples_common_3d/debug-plugin" ]
simd = [ "parry3d?/simd-stable", "parry3d-f64?/simd-stable" ]
enhanced-determinism = [ "parry3d?/enhanced-determinism", "parry3d-f64?/enhanced-determinism" ]

Expand Down
4 changes: 4 additions & 0 deletions crates/examples_common_2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name = "examples_common_2d"
version = "0.1.0"
edition = "2021"

[features]
debug-plugin = []

[dependencies]
bevy = { version = "0.10.1", default-features = false, features = [
"bevy_core_pipeline",
Expand All @@ -16,4 +19,5 @@ bevy = { version = "0.10.1", default-features = false, features = [
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
] }
bevy_screen_diagnostics = "0.2"
bevy_prototype_debug_lines = "0.10.1"
bevy_xpbd_2d = { path = "../bevy_xpbd_2d", default-features = false }
8 changes: 7 additions & 1 deletion crates/examples_common_2d/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use bevy::prelude::*;
pub extern crate bevy_prototype_debug_lines;

use bevy::prelude::*;
use bevy_prototype_debug_lines::DebugLinesPlugin;
use bevy_screen_diagnostics::{ScreenDiagnosticsPlugin, ScreenFrameDiagnosticsPlugin};
use bevy_xpbd_2d::prelude::*;

Expand All @@ -16,6 +18,10 @@ impl Plugin for XpbdExamplePlugin {
.add_system(bevy_xpbd_2d::resume.in_schedule(OnExit(AppState::Paused)))
.add_system(pause_button)
.add_system(step_button.run_if(in_state(AppState::Paused)));
#[cfg(not(feature = "debug-plugin"))]
{
app.add_plugin(DebugLinesPlugin::default());
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions crates/examples_common_3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name = "examples_common_3d"
version = "0.1.0"
edition = "2021"

[features]
debug-plugin = []

[dependencies]
bevy = { version = "0.10.1", default-features = false, features = [
"bevy_core_pipeline",
Expand All @@ -16,4 +19,5 @@ bevy = { version = "0.10.1", default-features = false, features = [
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
] }
bevy_screen_diagnostics = "0.2"
bevy_prototype_debug_lines = "0.10.1"
bevy_xpbd_3d = { path = "../bevy_xpbd_3d", default-features = false }
8 changes: 7 additions & 1 deletion crates/examples_common_3d/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use bevy::prelude::*;
pub extern crate bevy_prototype_debug_lines;

use bevy::prelude::*;
use bevy_prototype_debug_lines::DebugLinesPlugin;
use bevy_screen_diagnostics::{ScreenDiagnosticsPlugin, ScreenFrameDiagnosticsPlugin};
use bevy_xpbd_3d::prelude::*;

Expand All @@ -16,6 +18,10 @@ impl Plugin for XpbdExamplePlugin {
.add_system(bevy_xpbd_3d::resume.in_schedule(OnExit(AppState::Paused)))
.add_system(pause_button)
.add_system(step_button.run_if(in_state(AppState::Paused)));
#[cfg(not(feature = "debug-plugin"))]
{
app.add_plugin(DebugLinesPlugin::default());
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/components/collider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ impl Collider {
&self.0
}

/// Computes the [Axis-Aligned Bounding Box](ColliderAabb) of the collider.
#[cfg(feature = "2d")]
pub fn compute_aabb(&self, position: Vector, rotation: Scalar) -> ColliderAabb {
ColliderAabb(self.get_shape().compute_aabb(&utils::make_isometry(
position,
&Rotation::from_radians(rotation),
)))
}

/// Computes the [Axis-Aligned Bounding Box](ColliderAabb) of the collider.
#[cfg(feature = "3d")]
pub fn compute_aabb(&self, position: Vector, rotation: Quaternion) -> ColliderAabb {
ColliderAabb(
self.get_shape()
.compute_aabb(&utils::make_isometry(position, &Rotation(rotation))),
)
}

/// Creates a collider with a compound shape defined by a given vector of colliders with a position and a rotation.
///
/// Especially for dynamic rigid bodies, compound shape colliders should be preferred over triangle meshes and polylines,
Expand Down
2 changes: 0 additions & 2 deletions src/components/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ pub struct Rotation {
/// // Spawn a dynamic rigid body rotated by 1.5 radians around the x axis
/// commands.spawn((RigidBody::Dynamic, Rotation(Quat::from_rotation_x(1.5))));
/// }
/// # #[cfg(not(feature = "f32"))]
/// # fn setup() {}
/// ```
#[cfg(feature = "3d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut)]
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
//! - [Gravity](Gravity)
//! - [Joints](joints)
//! - Built-in [constraints] and support for [custom constraints](constraints#custom-constraints)
//! - [Spatial queries](spatial_query)
//! - [Ray casting](spatial_query#ray-casting)
//! - [Shape casting](spatial_query#shape-casting)
//! - [Point projection](spatial_query#point-projection)
//! - [Intersection tests](spatial_query#intersection-tests)
//! - Automatically deactivating bodies with [sleeping](Sleeping)
//! - Configurable [timesteps](PhysicsTimestep) and [substepping](SubstepCount)
//! - `f32`/`f64` precision (`f32` by default)
Expand Down Expand Up @@ -155,6 +160,9 @@
//! - [Configure gravity](Gravity)
//! - [Configure restitution](Restitution)
//! - [Configure friction](Friction)
//! - [Perform spatial queries](spatial_query)
//! - [Ray casting](spatial_query#ray-casting)
//! - [Shape casting](spatial_query#shape-casting)
//! - [Configure the physics timestep](PhysicsTimestep)
//! - [Configure the substep count](SubstepCount)
//! - [Create custom constraints](constraints#custom-constraints)
Expand Down
9 changes: 9 additions & 0 deletions src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod prepare;
pub mod setup;
pub mod sleeping;
pub mod solver;
pub mod spatial_query;
pub mod sync;

pub use broad_phase::BroadPhasePlugin;
Expand All @@ -37,6 +38,7 @@ pub use prepare::PreparePlugin;
pub use setup::*;
pub use sleeping::SleepingPlugin;
pub use solver::{solve_constraint, SolverPlugin};
pub use spatial_query::*;
pub use sync::SyncPlugin;

#[allow(unused_imports)]
Expand All @@ -56,6 +58,7 @@ use bevy::prelude::*;
/// - [`SolverPlugin`]: Solves positional and angular [constraints], updates velocities and solves velocity constraints
/// (dynamic [friction](Friction) and [restitution](Restitution)).
/// - [`SleepingPlugin`]: Controls when bodies should be deactivated and marked as [`Sleeping`] to improve performance.
/// - [`SpatialQueryPlugin`]: Handles spatial queries like [ray casting](RayCaster) and shape casting.
/// - [`SyncPlugin`]: Synchronizes the engine's [`Position`]s and [`Rotation`]s with Bevy's `Transform`s.
/// - `PhysicsDebugPlugin`: Renders physics objects and events like [AABBs](ColliderAabb) and [contacts](Collision)
/// for debugging purposes (only with `debug-plugin` feature enabled).
Expand Down Expand Up @@ -150,6 +153,7 @@ impl PluginGroup for PhysicsPlugins {
.add(IntegratorPlugin)
.add(SolverPlugin)
.add(SleepingPlugin)
.add(SpatialQueryPlugin)
.add(SyncPlugin)
}
}
Expand All @@ -164,6 +168,7 @@ impl PluginGroup for PhysicsPlugins {
/// 3. Update velocities
/// 4. Solve velocity constraints (dynamic friction and restitution)
/// 4. Sleeping
/// 5. Spatial queries (ray casting and shape casting)
/// 5. Sync data
#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PhysicsSet {
Expand All @@ -185,6 +190,10 @@ pub enum PhysicsSet {
///
/// See [`SleepingPlugin`].
Sleeping,
/// Responsible for spatial queries like [ray casting](`RayCaster`) and shape casting.
///
/// See [`SpatialQueryPlugin`].
SpatialQuery,
/// Responsible for synchronizing [`Position`]s and [`Rotation`]s with Bevy's `Transform`s.
///
/// See [`SyncPlugin`].
Expand Down
1 change: 1 addition & 0 deletions src/plugins/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ impl Plugin for PhysicsSetupPlugin {
PhysicsSet::BroadPhase,
PhysicsSet::Substeps,
PhysicsSet::Sleeping,
PhysicsSet::SpatialQuery,
PhysicsSet::Sync,
)
.chain(),
Expand Down
Loading

0 comments on commit 2966c2b

Please sign in to comment.