From 5d27a8d3d1ac542b6a92857ee9e0395d80d4edee Mon Sep 17 00:00:00 2001 From: Duncan Fairbanks Date: Wed, 13 Dec 2023 16:12:51 -0800 Subject: [PATCH] use RayMap in the bevy_mod_raycast backend --- backends/bevy_picking_raycast/src/lib.rs | 116 +++++++++-------------- 1 file changed, 47 insertions(+), 69 deletions(-) diff --git a/backends/bevy_picking_raycast/src/lib.rs b/backends/bevy_picking_raycast/src/lib.rs index 401f7aa4..60923626 100644 --- a/backends/bevy_picking_raycast/src/lib.rs +++ b/backends/bevy_picking_raycast/src/lib.rs @@ -18,11 +18,9 @@ use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_reflect::prelude::*; use bevy_render::{prelude::*, view::RenderLayers}; -use bevy_transform::prelude::*; -use bevy_window::{PrimaryWindow, Window}; use bevy_mod_raycast::prelude::*; -use bevy_picking_core::backend::prelude::*; +use bevy_picking_core::{backend::prelude::*, ray::RayMap}; // Re-export for uses who want this pub use bevy_mod_raycast; @@ -63,81 +61,61 @@ impl Plugin for RaycastBackend { /// Raycasts into the scene using [`RaycastBackendSettings`] and [`PointerLocation`]s, then outputs /// [`PointerHits`]. pub fn update_hits( - pointers: Query<(&PointerId, &PointerLocation)>, - primary_window_entity: Query>, - primary_window: Query<&Window, With>, - picking_cameras: Query<( - Entity, - &Camera, - &GlobalTransform, - Option<&RaycastPickable>, - Option<&RenderLayers>, - )>, + backend_settings: Res, + ray_map: Res, + picking_cameras: Query<(&Camera, Option<&RaycastPickable>, Option<&RenderLayers>)>, pickables: Query<&Pickable>, marked_targets: Query<&RaycastPickable>, layers: Query<&RenderLayers>, - backend_settings: Res, mut raycast: Raycast, mut output_events: EventWriter, ) { - for (pointer_id, pointer_location) in &pointers { - let pointer_location = match pointer_location.location() { - Some(l) => l, - None => continue, + for (&ray_id, &ray) in ray_map.map().iter() { + let Ok((camera, cam_pickable, cam_layers)) = picking_cameras.get(ray_id.camera) else { + continue; }; - for (cam_entity, camera, ray, cam_layers) in picking_cameras - .iter() - .filter(|(_, camera, ..)| { - camera.is_active && pointer_location.is_in_viewport(camera, &primary_window_entity) - }) - .filter(|(.., marker, _)| marker.is_some() || !backend_settings.require_markers) - .filter_map(|(entity, camera, transform, _, layers)| { - Ray3d::from_screenspace( - pointer_location.position, - camera, - transform, - primary_window.single(), - ) - .map(|ray| (entity, camera, ray, layers)) - }) - { - let settings = RaycastSettings { - visibility: RaycastVisibility::MustBeVisibleAndInView, - filter: &|entity| { - let marker_requirement = - !backend_settings.require_markers || marked_targets.get(entity).is_ok(); + if backend_settings.require_markers && cam_pickable.is_none() { + continue; + } - // Cameras missing render layers intersect all layers - let cam_layers = cam_layers.copied().unwrap_or(RenderLayers::all()); - // Other entities missing render layers are on the default layer 0 - let entity_layers = layers.get(entity).copied().unwrap_or_default(); - let render_layers_match = cam_layers.intersects(&entity_layers); + // Cameras missing render layers intersect all layers + let cam_layers = cam_layers.copied().unwrap_or_else(RenderLayers::all); - marker_requirement && render_layers_match - }, - early_exit_test: &|entity_hit| { - pickables - .get(entity_hit) - .is_ok_and(|pickable| pickable.should_block_lower) - }, - }; - let picks = raycast - .cast_ray(ray, &settings) - .iter() - .map(|(entity, hit)| { - let hit_data = HitData::new( - cam_entity, - hit.distance(), - Some(hit.position()), - Some(hit.normal()), - ); - (*entity, hit_data) - }) - .collect::>(); - let order = camera.order as f32; - if !picks.is_empty() { - output_events.send(PointerHits::new(*pointer_id, picks, order)); - } + let ray = Ray3d::from(ray); + let settings = RaycastSettings { + visibility: RaycastVisibility::MustBeVisibleAndInView, + filter: &|entity| { + let marker_requirement = + !backend_settings.require_markers || marked_targets.get(entity).is_ok(); + + // Other entities missing render layers are on the default layer 0 + let entity_layers = layers.get(entity).copied().unwrap_or_default(); + let render_layers_match = cam_layers.intersects(&entity_layers); + + marker_requirement && render_layers_match + }, + early_exit_test: &|entity_hit| { + pickables + .get(entity_hit) + .is_ok_and(|pickable| pickable.should_block_lower) + }, + }; + let picks = raycast + .cast_ray(ray, &settings) + .iter() + .map(|(entity, hit)| { + let hit_data = HitData::new( + ray_id.camera, + hit.distance(), + Some(hit.position()), + Some(hit.normal()), + ); + (*entity, hit_data) + }) + .collect::>(); + let order = camera.order as f32; + if !picks.is_empty() { + output_events.send(PointerHits::new(ray_id.pointer, picks, order)); } } }