From 4c679fefc1c113c8f6b80691cf47dffea33d942c Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Mon, 10 Jun 2024 20:47:24 -0700 Subject: [PATCH] 0.18.0-rc.0 setup --- CHANGELOG.md | 6 +++ Cargo.toml | 2 +- examples/mouse_picking.rs | 2 +- examples/reflecting_laser.rs | 2 +- examples/simplified_mesh.rs | 2 +- src/cursor.rs | 62 ++++++++++++++++++++++++++++ src/deferred.rs | 5 --- src/lib.rs | 78 +++++------------------------------- src/primitives.rs | 31 -------------- 9 files changed, 82 insertions(+), 108 deletions(-) create mode 100644 src/cursor.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0063202..5555e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.18.0 + +- Changed: updated to Bevy 0.14. +- Changed: `DefaultPlugin` renamed `CursorRayPlugin` to reflect what it actually does. +- Removed: all primitive raycasts have been removed. Users should use `bevy_math` instead. + # 0.17.0 Raycasting is now 20-50% faster. diff --git a/Cargo.toml b/Cargo.toml index d30de60..68ad845 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_mod_raycast" -version = "0.17.0" +version = "0.18.0-rc.0" authors = ["Aevyrie "] edition = "2021" license = "MIT" diff --git a/examples/mouse_picking.rs b/examples/mouse_picking.rs index 842340f..cc51681 100644 --- a/examples/mouse_picking.rs +++ b/examples/mouse_picking.rs @@ -8,7 +8,7 @@ use bevy_mod_raycast::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins.set(bevy_mod_raycast::low_latency_window_plugin())) - .add_plugins(DefaultRaycastingPlugin) + .add_plugins(CursorRayPlugin) .add_systems(Startup, setup) .add_systems(Update, raycast) .run(); diff --git a/examples/reflecting_laser.rs b/examples/reflecting_laser.rs index 0f9528f..5e2fcbb 100644 --- a/examples/reflecting_laser.rs +++ b/examples/reflecting_laser.rs @@ -10,7 +10,7 @@ fn main() { App::new() .add_plugins(( DefaultPlugins.set(bevy_mod_raycast::low_latency_window_plugin()), - DefaultRaycastingPlugin, + CursorRayPlugin, )) .add_systems(Startup, setup_scene) .add_systems(Update, bouncing_raycast) diff --git a/examples/simplified_mesh.rs b/examples/simplified_mesh.rs index d8b7cd1..e1fbe02 100644 --- a/examples/simplified_mesh.rs +++ b/examples/simplified_mesh.rs @@ -13,7 +13,7 @@ fn main() { App::new() .add_plugins(( DefaultPlugins.set(bevy_mod_raycast::low_latency_window_plugin()), - DefaultRaycastingPlugin, + CursorRayPlugin, FrameTimeDiagnosticsPlugin, )) .add_systems(Startup, (setup_scene, setup_ui)) diff --git a/src/cursor.rs b/src/cursor.rs new file mode 100644 index 0000000..0d5631a --- /dev/null +++ b/src/cursor.rs @@ -0,0 +1,62 @@ +use bevy_app::prelude::*; +use bevy_derive::Deref; +use bevy_ecs::prelude::*; +use bevy_math::Ray3d; +use bevy_render::camera::Camera; +use bevy_transform::components::GlobalTransform; +use bevy_window::Window; + +use crate::ray_from_screenspace; + +/// Automatically generates a ray in world space corresponding to the mouse cursor, and stores it in +/// [`CursorRay`]. +#[derive(Default)] +pub struct CursorRayPlugin; +impl Plugin for CursorRayPlugin { + fn build(&self, app: &mut App) { + app.add_systems(First, update_cursor_ray) + .add_systems( + PostUpdate, + update_cursor_ray.after(bevy_transform::TransformSystem::TransformPropagate), + ) + .init_resource::(); + } +} + +/// Holds the latest cursor position as a 3d ray. +/// +/// Requires the [`CursorRayPlugin`] is added to your app. This is updated in both [`First`] and +/// [`PostUpdate`]. The ray built in `First` will have the latest cursor position, but will not +/// account for any updates to camera position done in [`Update`]. The ray built in `PostUpdate` +/// will account for the camera position being updated and any camera transform propagation. +#[derive(Resource, Default, Deref)] +pub struct CursorRay(pub Option); + +/// Updates the [`CursorRay`] every frame. +pub fn update_cursor_ray( + primary_window: Query>, + windows: Query<&Window>, + cameras: Query<(&Camera, &GlobalTransform)>, + mut cursor_ray: ResMut, +) { + cursor_ray.0 = cameras + .iter() + .filter_map(|(camera, transform)| { + if let bevy_render::camera::RenderTarget::Window(window_ref) = camera.target { + Some(((camera, transform), window_ref)) + } else { + None + } + }) + .filter_map(|(cam, window_ref)| { + window_ref + .normalize(primary_window.get_single().ok()) + .map(|window_ref| (cam, window_ref.entity())) + }) + .filter_map(|(cam, window_entity)| windows.get(window_entity).ok().map(|w| (cam, w))) + .filter_map(|(cam, window)| window.cursor_position().map(|pos| (cam, window, pos))) + .filter_map(|((camera, transform), window, cursor)| { + ray_from_screenspace(cursor, camera, transform, window) + }) + .next(); +} diff --git a/src/deferred.rs b/src/deferred.rs index 6041be9..ae1bf84 100644 --- a/src/deferred.rs +++ b/src/deferred.rs @@ -350,11 +350,6 @@ impl RaycastSource { } } - /// Run an intersection check between this [`RaycastSource`] and a 3D primitive [`Primitive3d`]. - pub fn intersect_primitive(&self, shape: Primitive3d) -> Option { - Some(intersects_primitive(self.ray?, shape)?.into()) - } - /// Get a copy of the ray cast source's ray. pub fn get_ray(&self) -> Option { self.ray diff --git a/src/lib.rs b/src/lib.rs index ff4acff..2b4df68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,15 +17,17 @@ //! The plugin provides two ways of raycasting: //! - An [immediate-mode API](immediate), which allows you to raycast into the scene on-demand in //! any system. Intersections are returned immediately as a sorted `Vec`. -//! - A [deferred API](deferred), where raycasts are performed once every frame based on -//! entities tagged with specific components. Intersections can be queried from the ECS. +//! - A [deferred API](deferred), where raycasts are performed once every frame based on entities +//! tagged with specific components. Intersections can be queried from the ECS. +//! +//! The plugin also provides the [`CursorRayPlugin`] for automatically generating a world space 3D +//! ray corresponding to the mouse cursor. This is useful for mouse picking. //! //! ## Choosing an API //! -//! While the deferred API requires adding components on entities, in return it's generally -//! more "hands-off". Once you add the components to entities, the plugin will run raycasts for you -//! every frame, and you can query your [`RaycastSource`]s to see what they have intersected that -//! frame. +//! While the deferred API requires adding components on entities, in return it's generally more +//! "hands-off". Once you add the components to entities, the plugin will run raycasts for you every +//! frame, and you can query your [`RaycastSource`]s to see what they have intersected that frame. //! //! You can also think of this as being the "declarative" API. Instead of defining how the raycast //! happens, you instead describe what you want. For example, "this entity should cast rays in the @@ -52,85 +54,25 @@ #![allow(clippy::type_complexity)] +pub mod cursor; pub mod deferred; pub mod immediate; pub mod markers; pub mod primitives; pub mod raycast; -use bevy_app::prelude::*; -use bevy_derive::Deref; -use bevy_ecs::prelude::*; -use bevy_math::Ray3d; -use bevy_render::camera::Camera; -use bevy_transform::components::GlobalTransform; use bevy_utils::default; -use bevy_window::Window; #[allow(unused_imports)] // Needed for docs use prelude::*; pub mod prelude { - pub use crate::{ - deferred::*, immediate::*, markers::*, primitives::*, raycast::*, CursorRay, - DefaultRaycastingPlugin, - }; + pub use crate::{cursor::*, deferred::*, immediate::*, markers::*, primitives::*, raycast::*}; #[cfg(feature = "debug")] pub use crate::debug::*; } -#[derive(Default)] -pub struct DefaultRaycastingPlugin; -impl Plugin for DefaultRaycastingPlugin { - fn build(&self, app: &mut App) { - app.add_systems(First, update_cursor_ray) - .add_systems( - PostUpdate, - update_cursor_ray.after(bevy_transform::TransformSystem::TransformPropagate), - ) - .init_resource::(); - } -} - -/// Holds the latest cursor position as a 3d ray. -/// -/// Requires the [`DefaultRaycastingPlugin`] is added to your app. This is updated in both [`First`] -/// and [`PostUpdate`]. The ray built in `First` will have the latest cursor position, but will not -/// account for any updates to camera position done in [`Update`]. The ray built in `PostUpdate` -/// will account for the camera position being updated and any camera transform propagation. -#[derive(Resource, Default, Deref)] -pub struct CursorRay(pub Option); - -/// Updates the [`CursorRay`] every frame. -pub fn update_cursor_ray( - primary_window: Query>, - windows: Query<&Window>, - cameras: Query<(&Camera, &GlobalTransform)>, - mut cursor_ray: ResMut, -) { - cursor_ray.0 = cameras - .iter() - .filter_map(|(camera, transform)| { - if let bevy_render::camera::RenderTarget::Window(window_ref) = camera.target { - Some(((camera, transform), window_ref)) - } else { - None - } - }) - .filter_map(|(cam, window_ref)| { - window_ref - .normalize(primary_window.get_single().ok()) - .map(|window_ref| (cam, window_ref.entity())) - }) - .filter_map(|(cam, window_entity)| windows.get(window_entity).ok().map(|w| (cam, w))) - .filter_map(|(cam, window)| window.cursor_position().map(|pos| (cam, window, pos))) - .filter_map(|((camera, transform), window, cursor)| { - ray_from_screenspace(cursor, camera, transform, window) - }) - .next(); -} - /// Used for examples to reduce picking latency. Not relevant code for the examples. #[doc(hidden)] #[allow(dead_code)] diff --git a/src/primitives.rs b/src/primitives.rs index 8598b4b..68d9aa6 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -3,11 +3,6 @@ use bevy_reflect::Reflect; pub use rays::*; -#[non_exhaustive] -pub enum Primitive3d { - Plane { point: Vec3, normal: Vec3 }, -} - #[derive(Debug, Clone, Reflect)] pub struct IntersectionData { position: Vec3, @@ -90,7 +85,6 @@ impl IntersectionData { /// Encapsulates Ray3D, preventing use of struct literal syntax. This allows us to guarantee that /// the `Ray3d` direction is normalized, because it can only be instantiated with the constructor. pub mod rays { - use super::Primitive3d; use bevy_math::{prelude::*, Ray3d, Vec3A}; use bevy_render::{camera::Camera, primitives::Aabb}; use bevy_transform::components::GlobalTransform; @@ -207,29 +201,4 @@ pub mod rays { } Some([hit_near, hit_far]) } - - /// Checks if the ray intersects with a primitive shape - pub fn intersects_primitive(ray: Ray3d, shape: Primitive3d) -> Option { - match shape { - Primitive3d::Plane { - point: plane_origin, - normal: plane_normal, - } => { - // assuming vectors are all normalized - let denominator = ray.direction.dot(plane_normal); - if denominator.abs() > f32::EPSILON { - let point_to_point = plane_origin - ray.origin; - let intersect_dist = plane_normal.dot(point_to_point) / denominator; - let intersect_position = ray.direction * intersect_dist + ray.origin; - Some(PrimitiveIntersection::new( - intersect_position, - plane_normal, - intersect_dist, - )) - } else { - None - } - } - } - } }