Skip to content

Commit

Permalink
use RayMap in the bevy_mod_raycast backend
Browse files Browse the repository at this point in the history
  • Loading branch information
bonsairobo committed Dec 14, 2023
1 parent 92ece0a commit 5d27a8d
Showing 1 changed file with 47 additions and 69 deletions.
116 changes: 47 additions & 69 deletions backends/bevy_picking_raycast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Entity, With<PrimaryWindow>>,
primary_window: Query<&Window, With<PrimaryWindow>>,
picking_cameras: Query<(
Entity,
&Camera,
&GlobalTransform,
Option<&RaycastPickable>,
Option<&RenderLayers>,
)>,
backend_settings: Res<RaycastBackendSettings>,
ray_map: Res<RayMap>,
picking_cameras: Query<(&Camera, Option<&RaycastPickable>, Option<&RenderLayers>)>,
pickables: Query<&Pickable>,
marked_targets: Query<&RaycastPickable>,
layers: Query<&RenderLayers>,
backend_settings: Res<RaycastBackendSettings>,
mut raycast: Raycast,
mut output_events: EventWriter<PointerHits>,
) {
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::<Vec<_>>();
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::<Vec<_>>();
let order = camera.order as f32;
if !picks.is_empty() {
output_events.send(PointerHits::new(ray_id.pointer, picks, order));
}
}
}

0 comments on commit 5d27a8d

Please sign in to comment.