1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! A small `bevy` plugin for raycasting against [`Mesh`](bevy_render::mesh::Mesh)es.
//!
//! ```
//! # use bevy::prelude::*;
//! use bevy_mod_raycast::prelude::*;
//!
//! fn raycast_system(mut raycast: Raycast) {
//!     let ray = Ray3d::new(Vec3::ZERO, Vec3::X);
//!     let hits = raycast.cast_ray(ray, &RaycastSettings::default());
//! }
//! ```
//!
//! *An example of the immediate mode raycasting API.*
//!
//! # Getting Started
//!
//! 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.
//!
//! ## 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.
//!
//! 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
//! direction it faces", and you can then query that entity to find out what it hit.
//!
//! By comparison, the immediate mode API is more imperative. You must define the raycast directly,
//! but in return you are immediately given the results of the raycast without needing to wait for
//! the scheduled raycasting system to run and query the results.
//!
//! # Use Cases
//!
//! This plugin is well suited for use cases where you don't want to use a full physics engine, you
//! are putting together a simple prototype, or you just want the simplest-possible API. Using the
//! [`Raycast`] system param requires no added components or plugins. You can just start raycasting
//! in your systems.
//!
//! ## Limitations
//!
//! This plugin runs entirely on the CPU, with minimal acceleration structures, and without support
//! for skinned meshes. However, there is a good chance that this simply won't be an issue for your
//! application. The provided `stress_test` example is a worst-case scenario that can help you judge
//! if the plugin will meet your performance needs. Using a laptop with an i7-11800H, I am able to
//! reach 110-530 fps in the stress test, raycasting against 1,000 monkey meshes.

#![allow(clippy::type_complexity)]

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,
    };

    #[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)]
pub fn low_latency_window_plugin() -> bevy_window::WindowPlugin {
    bevy_window::WindowPlugin {
        primary_window: Some(bevy_window::Window {
            present_mode: bevy_window::PresentMode::AutoNoVsync,
            ..default()
        }),
        ..default()
    }
}