From 0552cf91e8903d10948742b0bfdfbb24966528da Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 17 Jul 2023 03:47:30 +0300 Subject: [PATCH] Update to Bevy v0.11 (#84) * Update bevy to 0.11 Fix deriving Reflect - change type bound to `TypePath` Migrate to new `add_systems` * Fix screenspace projection Use `camera.viewport_to_world()` * Update examples for Bevy 0.11 Migrate to new `add` apis Revert tonemapping to ReinhardLuminance to avoid the `tonemapping_luts` feature --------- Co-authored-by: Aevyrie --- Cargo.toml | 4 +-- examples/bounding_volume.rs | 41 +++++++++++++------------ examples/minimal.rs | 14 +++++---- examples/mouse_picking.rs | 14 ++++----- examples/mouse_picking_2d.rs | 24 +++++++++------ examples/ray_intersection_over_mesh.rs | 30 +++++++++--------- examples/simplified_mesh.rs | 41 +++++++++++++------------ src/lib.rs | 42 ++++++++++++-------------- src/primitives.rs | 28 +++++++---------- 9 files changed, 121 insertions(+), 117 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 993053f..e3176d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,13 @@ categories = ["game-engines", "rendering"] resolver = "2" [dependencies] -bevy = { version = "0.10", default-features = false, features = [ +bevy = { version = "0.11", default-features = false, features = [ "bevy_render", "bevy_asset", ] } [dev-dependencies] -bevy = { version = "0.10", default-features = false, features = [ +bevy = { version = "0.11", default-features = false, features = [ "bevy_pbr", "bevy_winit", "bevy_ui", diff --git a/examples/bounding_volume.rs b/examples/bounding_volume.rs index dd66ac7..cb63511 100644 --- a/examples/bounding_volume.rs +++ b/examples/bounding_volume.rs @@ -1,5 +1,6 @@ use bevy::{ - diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin}, + core_pipeline::tonemapping::Tonemapping, + diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}, math::Vec3A, prelude::*, render::primitives::Aabb, @@ -17,28 +18,27 @@ use bevy_mod_raycast::{ fn main() { App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - present_mode: PresentMode::AutoNoVsync, + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + present_mode: PresentMode::AutoNoVsync, + ..default() + }), ..default() }), - ..default() - })) - .add_plugin(FrameTimeDiagnosticsPlugin::default()) - .add_plugin(DefaultRaycastingPlugin::::default()) + FrameTimeDiagnosticsPlugin::default(), + DefaultRaycastingPlugin::::default(), + )) // You will need to pay attention to what order you add systems! Putting them in the wrong // order can result in multiple frames of latency. Ray casting should probably happen after // the positions of your meshes have been updated in the UPDATE stage. - .add_system( - update_raycast_with_cursor - .before(RaycastSystem::BuildRays::) - .in_base_set(CoreSet::First), + .add_systems( + First, + update_raycast_with_cursor.before(RaycastSystem::BuildRays::), ) - .add_startup_system(setup_scene) - .add_startup_system(setup_ui) - .add_system(update_fps) - .add_system(make_scene_pickable) - .add_system(manage_aabb.in_base_set(CoreSet::First)) + .add_systems(Startup, (setup_scene, setup_ui)) + .add_systems(Update, (update_fps, make_scene_pickable)) + .add_systems(First, manage_aabb) .run(); } @@ -74,7 +74,10 @@ fn setup_scene(mut commands: Commands, asset_server: Res) { }); commands - .spawn(Camera3dBundle::default()) + .spawn(Camera3dBundle { + tonemapping: Tonemapping::ReinhardLuminance, + ..default() + }) .insert(RaycastSource::::new()); // Designate the camera as our source // Spawn multiple mesh to raycast on @@ -219,7 +222,7 @@ fn manage_aabb( } } -fn update_fps(diagnostics: Res, mut query: Query<&mut Text, With>) { +fn update_fps(diagnostics: Res, mut query: Query<&mut Text, With>) { for mut text in &mut query { if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) { if let Some(average) = fps.smoothed() { diff --git a/examples/minimal.rs b/examples/minimal.rs index baa5bfb..64f86fa 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*}; use bevy_mod_raycast::{ DefaultPluginState, DefaultRaycastingPlugin, Intersection, RaycastMesh, RaycastSource, }; @@ -11,11 +11,12 @@ use bevy_mod_raycast::{ fn main() { App::new() - .add_plugins(DefaultPlugins) - .add_plugin(DefaultRaycastingPlugin::::default()) - .add_startup_system(setup) - .add_system(rotator) - .add_system(intersection) + .add_plugins(( + DefaultPlugins, + DefaultRaycastingPlugin::::default(), + )) + .add_systems(Startup, setup) + .add_systems(Update, (rotator, intersection)) .run(); } @@ -40,6 +41,7 @@ fn setup( scale: 0.01, ..default() }), + tonemapping: Tonemapping::ReinhardLuminance, ..default() }, // Designate the camera as our ray casting source. Using `new_transform_empty()` means that diff --git a/examples/mouse_picking.rs b/examples/mouse_picking.rs index 45272b4..0eebe43 100644 --- a/examples/mouse_picking.rs +++ b/examples/mouse_picking.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, window::PresentMode}; +use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*, window::PresentMode}; use bevy_mod_raycast::{ DefaultPluginState, DefaultRaycastingPlugin, RaycastMesh, RaycastMethod, RaycastSource, @@ -22,18 +22,17 @@ fn main() { // plugin. This includes building rays, casting them, and placing a debug cursor at the // intersection. For more advanced uses, you can compose the systems in this plugin however // you need. For example, you might exclude the debug cursor system. - .add_plugin(DefaultRaycastingPlugin::::default()) + .add_plugins(DefaultRaycastingPlugin::::default()) // You will need to pay attention to what order you add systems! Putting them in the wrong // order can result in multiple frames of latency. Ray casting should probably happen near // start of the frame. For example, we want to be sure this system runs before we construct // any rays, hence the ".before(...)". You can use these provided RaycastSystem labels to // order your systems with the ones provided by the raycasting plugin. - .add_system( - update_raycast_with_cursor - .in_base_set(CoreSet::First) - .before(RaycastSystem::BuildRays::), + .add_systems( + First, + update_raycast_with_cursor.before(RaycastSystem::BuildRays::), ) - .add_startup_system(setup) + .add_systems(Startup, setup) .run(); } @@ -72,6 +71,7 @@ fn setup( commands .spawn(Camera3dBundle { transform: Transform::from_xyz(-2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y), + tonemapping: Tonemapping::ReinhardLuminance, ..Default::default() }) .insert(RaycastSource::::new()); // Designate the camera as our source diff --git a/examples/mouse_picking_2d.rs b/examples/mouse_picking_2d.rs index 3708236..68e54ff 100644 --- a/examples/mouse_picking_2d.rs +++ b/examples/mouse_picking_2d.rs @@ -1,19 +1,20 @@ -use bevy::{prelude::*, sprite::MaterialMesh2dBundle}; +use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*, sprite::MaterialMesh2dBundle}; use bevy_mod_raycast::{ DefaultRaycastingPlugin, Intersection, RaycastMesh, RaycastMethod, RaycastSource, RaycastSystem, }; fn main() { App::new() - .add_plugins(DefaultPlugins) - .add_plugin(DefaultRaycastingPlugin::::default()) - .add_system( - update_raycast_with_cursor - .in_base_set(CoreSet::First) - .before(RaycastSystem::BuildRays::), + .add_plugins(( + DefaultPlugins, + DefaultRaycastingPlugin::::default(), + )) + .add_systems( + First, + update_raycast_with_cursor.before(RaycastSystem::BuildRays::), ) - .add_system(intersection) - .add_startup_system(setup) + .add_systems(Startup, setup) + .add_systems(Update, intersection) .run(); } @@ -53,7 +54,10 @@ fn setup( mut materials: ResMut>, ) { commands - .spawn(Camera2dBundle::default()) + .spawn(Camera2dBundle { + tonemapping: Tonemapping::ReinhardLuminance, + ..default() + }) .insert(RaycastSource::::new()); // Designate the camera as our source; commands .spawn(MaterialMesh2dBundle { diff --git a/examples/ray_intersection_over_mesh.rs b/examples/ray_intersection_over_mesh.rs index fbf2a49..51ea4d9 100644 --- a/examples/ray_intersection_over_mesh.rs +++ b/examples/ray_intersection_over_mesh.rs @@ -1,6 +1,6 @@ use std::f32::consts::FRAC_PI_2; -use bevy::{prelude::*, window::PresentMode}; +use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*, window::PresentMode}; use bevy_mod_raycast::{ ray_intersection_over_mesh, Backfaces, DefaultPluginState, DefaultRaycastingPlugin, Ray3d, @@ -15,23 +15,22 @@ use bevy_mod_raycast::{ fn main() { App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - present_mode: PresentMode::AutoNoVsync, // Reduces input latency + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + present_mode: PresentMode::AutoNoVsync, // Reduces input latency + ..default() + }), ..default() }), - ..default() - })) - .add_plugin(DefaultRaycastingPlugin::::default()) - .add_startup_system(setup) - .add_startup_system(setup_ui) - .add_system( - update_raycast_with_cursor - .before(RaycastSystem::BuildRays::) - .in_base_set(CoreSet::First), + DefaultRaycastingPlugin::::default(), + )) + .add_systems(Startup, (setup, setup_ui)) + .add_systems( + First, + update_raycast_with_cursor.before(RaycastSystem::BuildRays::), ) - .add_system(check_path) - .add_system(move_origin) + .add_systems(Update, (check_path, move_origin)) .run(); } @@ -116,6 +115,7 @@ fn setup( commands .spawn(Camera3dBundle { transform: Transform::from_xyz(-5.0, 10.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + tonemapping: Tonemapping::ReinhardLuminance, ..Default::default() }) .insert(RaycastSource::::new()); diff --git a/examples/simplified_mesh.rs b/examples/simplified_mesh.rs index 6b95cff..8dda608 100644 --- a/examples/simplified_mesh.rs +++ b/examples/simplified_mesh.rs @@ -1,5 +1,6 @@ use bevy::{ - diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin}, + core_pipeline::tonemapping::Tonemapping, + diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}, prelude::*, window::PresentMode, }; @@ -14,27 +15,26 @@ use bevy_mod_raycast::{ fn main() { App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - present_mode: PresentMode::AutoNoVsync, // Reduces input lag. - ..Default::default() + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + present_mode: PresentMode::AutoNoVsync, // Reduces input lag. + ..Default::default() + }), + ..default() }), - ..default() - })) - .add_plugin(FrameTimeDiagnosticsPlugin::default()) - .add_plugin(DefaultRaycastingPlugin::::default()) + FrameTimeDiagnosticsPlugin::default(), + DefaultRaycastingPlugin::::default(), + )) // You will need to pay attention to what order you add systems! Putting them in the wrong // order can result in multiple frames of latency. Ray casting should probably happen after // the positions of your meshes have been updated in the UPDATE stage. - .add_system( - update_raycast_with_cursor_position - .before(RaycastSystem::BuildRays::) - .in_base_set(CoreSet::First), + .add_systems( + First, + update_raycast_with_cursor_position.before(RaycastSystem::BuildRays::), ) - .add_startup_system(setup_scene) - .add_startup_system(setup_ui) - .add_system(update_fps) - .add_system(manage_simplified_mesh) + .add_systems(Startup, (setup_scene, setup_ui)) + .add_systems(Update, (update_fps, manage_simplified_mesh)) .run(); } @@ -65,7 +65,10 @@ fn setup_scene( ) { commands.insert_resource(DefaultPluginState::::default().with_debug_cursor()); commands - .spawn(Camera3dBundle::default()) + .spawn(Camera3dBundle { + tonemapping: Tonemapping::ReinhardLuminance, + ..default() + }) .insert(RaycastSource::::new()); // Designate the camera as our source commands.spawn(( PbrBundle { @@ -191,7 +194,7 @@ fn manage_simplified_mesh( } } -fn update_fps(diagnostics: Res, mut query: Query<&mut Text, With>) { +fn update_fps(diagnostics: Res, mut query: Query<&mut Text, With>) { for mut text in &mut query { if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) { if let Some(average) = fps.average() { diff --git a/src/lib.rs b/src/lib.rs index 9ead924..2c56ec9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ use bevy::sprite::Mesh2dHandle; use bevy::{ math::Vec3A, prelude::*, + reflect::TypePath, render::{ camera::Camera, mesh::{Indices, Mesh, VertexAttributeValues}, @@ -31,9 +32,10 @@ pub use crate::{primitives::*, raycast::*}; pub use debug::*; pub struct DefaultRaycastingPlugin(pub PhantomData T>); -impl Plugin for DefaultRaycastingPlugin { +impl Plugin for DefaultRaycastingPlugin { fn build(&self, app: &mut App) { app.init_resource::>().add_systems( + First, ( build_rays:: .in_set(RaycastSystem::BuildRays::) @@ -45,17 +47,16 @@ impl Plugin for DefaultRaycastingPlu .in_set(RaycastSystem::UpdateIntersections::) .run_if(|state: Res>| state.update_raycast), ) - .chain() - .in_base_set(CoreSet::First), + .chain(), ); app.register_type::>() .register_type::>(); #[cfg(feature = "debug")] - app.add_system( + app.add_systems( + First, update_debug_cursor:: - .in_base_set(CoreSet::First) .in_set(RaycastSystem::UpdateDebugCursor::) .run_if(|state: Res>| state.update_debug_cursor) .after(RaycastSystem::UpdateIntersections::), @@ -75,7 +76,6 @@ pub enum RaycastSystem { UpdateIntersections, #[cfg(feature = "debug")] UpdateDebugCursor, - #[system_set(ignore_fields)] _Phantom(PhantomData T>), } impl PartialEq for RaycastSystem { @@ -153,15 +153,13 @@ impl DefaultPluginState { /// # Requirements /// /// The marked entity must also have a [Mesh] component. -#[derive(Component, Debug, Clone)] -pub struct RaycastMesh { +#[derive(Component, Debug, Clone, Reflect)] +pub struct RaycastMesh { + #[reflect(ignore)] _marker: PhantomData, } -bevy::reflect::impl_reflect_value!(RaycastMesh); -bevy::reflect::impl_from_reflect_value!(RaycastMesh); - -impl Default for RaycastMesh { +impl Default for RaycastMesh { fn default() -> Self { RaycastMesh { _marker: PhantomData, @@ -172,18 +170,18 @@ impl Default for RaycastMesh { /// The `RaycastSource` component is used to generate rays with the specified `cast_method`. A `ray` /// is generated when the RaycastSource is initialized, either by waiting for update_raycast system /// to process the ray, or by using a `with_ray` function.` -#[derive(Component, Clone)] -pub struct RaycastSource { +#[derive(Component, Clone, Reflect)] +pub struct RaycastSource { pub cast_method: RaycastMethod, + #[reflect(skip_serializing)] pub ray: Option, + #[reflect(ignore)] intersections: Vec<(Entity, IntersectionData)>, + #[reflect(ignore)] _marker: PhantomData T>, } -bevy::reflect::impl_reflect_value!(RaycastSource); -bevy::reflect::impl_from_reflect_value!(RaycastSource); - -impl Default for RaycastSource { +impl Default for RaycastSource { fn default() -> Self { RaycastSource { cast_method: RaycastMethod::Screenspace(Vec2::ZERO), @@ -194,7 +192,7 @@ impl Default for RaycastSource { } } -impl RaycastSource { +impl RaycastSource { /// Instantiates a [RaycastSource]. It will not be initialized until the update_raycast system /// runs, or one of the `with_ray` functions is run. pub fn new() -> RaycastSource { @@ -305,7 +303,7 @@ pub enum RaycastMethod { Transform, } -pub fn build_rays( +pub fn build_rays( mut pick_source_query: Query<( &mut RaycastSource, Option<&GlobalTransform>, @@ -357,7 +355,7 @@ pub fn build_rays( /// Iterates through all entities with the [RaycastMesh] component, checking for /// intersections. If these entities have bounding volumes, these will be checked first, greatly /// accelerating the process. -pub fn update_raycast( +pub fn update_raycast( // Resources meshes: Res>, // Queries @@ -495,7 +493,7 @@ pub fn update_raycast( } } } -pub fn update_intersections( +pub fn update_intersections( mut commands: Commands, mut intersections: Query<&mut Intersection>, sources: Query<&RaycastSource>, diff --git a/src/primitives.rs b/src/primitives.rs index 64b9604..0b56f9a 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -139,7 +139,7 @@ impl Intersection { pub mod rays { use super::Primitive3d; use bevy::{ - math::Vec3A, + math::{Ray, Vec3A}, prelude::*, render::{camera::Camera, primitives::Aabb}, }; @@ -179,7 +179,7 @@ pub mod rays { } /// A 3D ray, with an origin and direction. The direction is guaranteed to be normalized. - #[derive(Debug, PartialEq, Copy, Clone, Default)] + #[derive(Reflect, Debug, PartialEq, Copy, Clone, Default)] pub struct Ray3d { pub(crate) origin: Vec3A, pub(crate) direction: Vec3A, @@ -235,21 +235,9 @@ pub mod rays { camera: &Camera, camera_transform: &GlobalTransform, ) -> Option { - let view = camera_transform.compute_matrix(); - - let (viewport_min, viewport_max) = camera.logical_viewport_rect()?; - let screen_size = camera.logical_target_size()?; - let viewport_size = viewport_max - viewport_min; - let adj_cursor_pos = - cursor_pos_screen - Vec2::new(viewport_min.x, screen_size.y - viewport_max.y); - - let projection = camera.projection_matrix(); - let cursor_ndc = (adj_cursor_pos / viewport_size) * 2.0 - Vec2::ONE; - let ndc_to_world: Mat4 = view * projection.inverse(); - let near = ndc_to_world.project_point3(cursor_ndc.extend(1.)); - let far = ndc_to_world.project_point3(cursor_ndc.extend(f32::EPSILON)); - let ray_direction = far - near; - Some(Ray3d::new(near, ray_direction)) + camera + .viewport_to_world(camera_transform, cursor_pos_screen) + .map(Ray3d::from) } /// Checks if the ray intersects with an AABB of a mesh. @@ -318,6 +306,12 @@ pub mod rays { } } } + + impl From for Ray3d { + fn from(ray: Ray) -> Self { + Ray3d::new(ray.origin, ray.direction) + } + } } #[derive(Debug, PartialEq, Copy, Clone)]