Skip to content

Commit

Permalink
0.18.0-rc.0 setup
Browse files Browse the repository at this point in the history
  • Loading branch information
aevyrie committed Jun 11, 2024
1 parent 0637c54 commit 4c679fe
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 108 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_mod_raycast"
version = "0.17.0"
version = "0.18.0-rc.0"
authors = ["Aevyrie <aevyrie@gmail.com>"]
edition = "2021"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion examples/mouse_picking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion examples/reflecting_laser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion examples/simplified_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
62 changes: 62 additions & 0 deletions src/cursor.rs
Original file line number Diff line number Diff line change
@@ -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::<CursorRay>();
}
}

/// 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<Ray3d>);

/// Updates the [`CursorRay`] every frame.
pub fn update_cursor_ray(
primary_window: Query<Entity, With<bevy_window::PrimaryWindow>>,
windows: Query<&Window>,
cameras: Query<(&Camera, &GlobalTransform)>,
mut cursor_ray: ResMut<CursorRay>,
) {
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();
}
5 changes: 0 additions & 5 deletions src/deferred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,6 @@ impl<T: TypePath> RaycastSource<T> {
}
}

/// Run an intersection check between this [`RaycastSource`] and a 3D primitive [`Primitive3d`].
pub fn intersect_primitive(&self, shape: Primitive3d) -> Option<IntersectionData> {
Some(intersects_primitive(self.ray?, shape)?.into())
}

/// Get a copy of the ray cast source's ray.
pub fn get_ray(&self) -> Option<Ray3d> {
self.ray
Expand Down
78 changes: 10 additions & 68 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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::<CursorRay>();
}
}

/// 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<Ray3d>);

/// Updates the [`CursorRay`] every frame.
pub fn update_cursor_ray(
primary_window: Query<Entity, With<bevy_window::PrimaryWindow>>,
windows: Query<&Window>,
cameras: Query<(&Camera, &GlobalTransform)>,
mut cursor_ray: ResMut<CursorRay>,
) {
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)]
Expand Down
31 changes: 0 additions & 31 deletions src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<PrimitiveIntersection> {
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
}
}
}
}
}

0 comments on commit 4c679fe

Please sign in to comment.