Skip to content

Commit

Permalink
make early exit an option
Browse files Browse the repository at this point in the history
  • Loading branch information
aevyrie committed Aug 3, 2023
1 parent db5b442 commit 267bba0
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 18 deletions.
2 changes: 1 addition & 1 deletion examples/bounding_volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {

commands.spawn((
Camera3dBundle::default(),
RaycastSource::<MyRaycastSet>::new(), // Designate the camera as our source
RaycastSource::<MyRaycastSet>::default().with_early_exit(true), // Designate camera as our source
));

// Spawn multiple mesh to raycast on
Expand Down
2 changes: 1 addition & 1 deletion examples/immediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn immediate_mode_raycast(raycast: Raycast<MyRaycastSet>, mut gizmos: Gizmos, ti
gizmos.sphere(ray_pos, Quat::IDENTITY, 0.1, Color::YELLOW);

// This is all that is needed to raycast into the world!
let hits = raycast.cast_ray(ray, false);
let hits = raycast.cast_ray(ray, false, true);

// Go through the intersections and render them as a pink circle
if let Some((_, hit)) = hits.first() {
Expand Down
4 changes: 2 additions & 2 deletions examples/reflecting_laser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() {
}

const MAX_BOUNCES: usize = 128;
const LASER_MOVE_SPEED: f32 = 0.005;
const LASER_MOVE_SPEED: f32 = 0.05;

#[derive(Reflect)]
struct Laser;
Expand All @@ -29,7 +29,7 @@ fn bouncing_raycast(raycast: Raycast<Laser>, mut gizmos: Gizmos, time: Res<Time>

for i in 0..MAX_BOUNCES {
let ray = Ray3d::new(ray_pos, ray_dir);
if let Some((_, hit)) = raycast.cast_ray(ray, false).first() {
if let Some((_, hit)) = raycast.cast_ray(ray, false, true).first() {
let a = 0.2 + 0.8 * (1.0 - i as f32 / MAX_BOUNCES as f32);
let color = Color::rgba(1.0, 0.0, 0.0, a);
intersections.push((hit.position(), color));
Expand Down
25 changes: 20 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ impl<T: TypePath> Default for RaycastMesh<T> {
#[reflect(Component)]
pub struct RaycastSource<T: TypePath> {
pub cast_method: RaycastMethod,
/// Should raycasts early-out, only hitting the topmost entity? This is generally more
/// performant.
pub should_early_exit: bool,
#[reflect(skip_serializing)]
pub ray: Option<Ray3d>,
#[reflect(ignore)]
Expand All @@ -201,6 +204,7 @@ impl<T: TypePath> Default for RaycastSource<T> {
fn default() -> Self {
RaycastSource {
cast_method: RaycastMethod::Screenspace(Vec2::ZERO),
should_early_exit: true,
ray: None,
intersections: Vec::new(),
_marker: PhantomData,
Expand All @@ -224,19 +228,26 @@ impl<T: TypePath> RaycastSource<T> {
RaycastSource {
cast_method: RaycastMethod::Screenspace(cursor_pos_screen),
ray: Ray3d::from_screenspace(cursor_pos_screen, camera, camera_transform),
intersections: self.intersections,
_marker: self._marker,
..self
}
}
/// Initializes a [RaycastSource] with a valid ray derived from a transform.
pub fn with_ray_transform(self, transform: Mat4) -> Self {
RaycastSource {
cast_method: RaycastMethod::Transform,
ray: Some(Ray3d::from_transform(transform)),
intersections: self.intersections,
_marker: self._marker,
..self
}
}

/// Set the `should_early_exit` field of this raycast source.
pub fn with_early_exit(self, should_early_exit: bool) -> Self {
Self {
should_early_exit,
..self
}
}

/// Instantiates and initializes a [RaycastSource] with a valid screenspace ray.
pub fn new_screenspace(
cursor_pos_screen: Vec2,
Expand Down Expand Up @@ -382,7 +393,11 @@ pub fn update_raycast<T: TypePath + Send + Sync + 'static>(
for mut pick_source in &mut pick_source_query {
if let Some(ray) = pick_source.ray {
pick_source.intersections.clear();
pick_source.intersections = raycast.cast_ray(ray, pick_source.is_screenspace());
pick_source.intersections = raycast.cast_ray(
ray,
pick_source.is_screenspace(),
pick_source.should_early_exit,
);
}
}
}
Expand Down
29 changes: 20 additions & 9 deletions src/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl<'w, 's, T: TypePath + Send + Sync> Raycast<'w, 's, T> {
&self,
ray: Ray3d,
should_frustum_cull: bool,
should_early_exit: bool,
) -> Vec<(Entity, IntersectionData)> {
let ray_cull = info_span!("ray culling");
let ray_cull_guard = ray_cull.enter();
Expand Down Expand Up @@ -112,12 +113,14 @@ impl<'w, 's, T: TypePath + Send + Sync> Raycast<'w, 's, T> {
return
};

// Is it even possible the mesh could be closer than the current best?
let Some(&nearest_hit) = nearest_hit_lock.read().as_deref().ok() else {
return
};
if aabb_near > nearest_hit {
return;
if should_early_exit {
// Is it even possible the mesh could be closer than the current best?
let Some(&nearest_hit) = nearest_hit_lock.read().as_deref().ok() else {
return
};
if aabb_near > nearest_hit {
return;
}
}

let mesh_handle = simplified_mesh.map(|m| &m.mesh).unwrap_or(mesh_handle);
Expand All @@ -134,8 +137,10 @@ impl<'w, 's, T: TypePath + Send + Sync> Raycast<'w, 's, T> {
let intersection = ray_intersection_over_mesh(mesh, &transform, &ray, backfaces);
if let Some(intersection) = intersection {
let distance = FloatOrd(intersection.distance());
if let Ok(nearest_hit) = nearest_hit_lock.write().as_deref_mut() {
*nearest_hit = distance.min(*nearest_hit);
if should_early_exit {
if let Ok(nearest_hit) = nearest_hit_lock.write().as_deref_mut() {
*nearest_hit = distance.min(*nearest_hit);
}
}
hits_tx.send((distance, (entity, intersection))).ok();
};
Expand All @@ -156,6 +161,12 @@ impl<'w, 's, T: TypePath + Send + Sync> Raycast<'w, 's, T> {
);
let mut hits: Vec<_> = hits_rx.try_iter().collect();
hits.sort_by_key(|(k, _)| *k);
hits.drain(..).map(|(_, v)| v).collect()
if should_early_exit {
hits.first()
.map(|(_, (e, i))| vec![(*e, i.clone())])
.unwrap_or_default()
} else {
hits.drain(..).map(|(_, v)| v).collect()
}
}
}

0 comments on commit 267bba0

Please sign in to comment.