 1cc4d1e8ac
			
		
	
	
		1cc4d1e8ac
		
			
		
	
	
	
	
		
			
			# Objective The `RayCastSettings` type is only used in the context of ray casts with the `MeshRayCast` system parameter. The current name is somewhat inconsistent with other existing types, like `MeshRayCast` and `MeshPickingSettings`, but more importantly, it easily conflicts with physics, and forces those crates to opt for some other name like `RayCastConfig` or `RayCastOptions`. We should rename `RayCastSettings` to `MeshRayCastSettings` to avoid naming conflicts and improve consistency. ## Solution Rename `RayCastSettings` to `MeshRayCastSettings`. --- ## Migration Guide `RayCastSettings` has been renamed to `MeshRayCastSettings` to avoid naming conflicts with other ray casting backends and types.
		
			
				
	
	
		
			116 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Demonstrates how to use the [`MeshRayCast`] system parameter to chain multiple ray casts
 | |
| //! and bounce off of surfaces.
 | |
| 
 | |
| use std::f32::consts::{FRAC_PI_2, PI};
 | |
| 
 | |
| use bevy::{
 | |
|     color::palettes::css,
 | |
|     core_pipeline::{bloom::Bloom, tonemapping::Tonemapping},
 | |
|     math::vec3,
 | |
|     picking::backend::ray::RayMap,
 | |
|     prelude::*,
 | |
| };
 | |
| 
 | |
| fn main() {
 | |
|     App::new()
 | |
|         .add_plugins(DefaultPlugins)
 | |
|         .add_systems(Startup, setup)
 | |
|         .add_systems(Update, bouncing_raycast)
 | |
|         .insert_resource(ClearColor(Color::BLACK))
 | |
|         .run();
 | |
| }
 | |
| 
 | |
| const MAX_BOUNCES: usize = 64;
 | |
| const LASER_SPEED: f32 = 0.03;
 | |
| 
 | |
| fn bouncing_raycast(
 | |
|     mut ray_cast: MeshRayCast,
 | |
|     mut gizmos: Gizmos,
 | |
|     time: Res<Time>,
 | |
|     // The ray map stores rays cast by the cursor
 | |
|     ray_map: Res<RayMap>,
 | |
| ) {
 | |
|     // Cast an automatically moving ray and bounce it off of surfaces
 | |
|     let t = ops::cos((time.elapsed_secs() - 4.0).max(0.0) * LASER_SPEED) * PI;
 | |
|     let ray_pos = Vec3::new(ops::sin(t), ops::cos(3.0 * t) * 0.5, ops::cos(t)) * 0.5;
 | |
|     let ray_dir = Dir3::new(-ray_pos).unwrap();
 | |
|     let ray = Ray3d::new(ray_pos, ray_dir);
 | |
|     gizmos.sphere(ray_pos, 0.1, Color::WHITE);
 | |
|     bounce_ray(ray, &mut ray_cast, &mut gizmos, Color::from(css::RED));
 | |
| 
 | |
|     // Cast a ray from the cursor and bounce it off of surfaces
 | |
|     for (_, ray) in ray_map.iter() {
 | |
|         bounce_ray(*ray, &mut ray_cast, &mut gizmos, Color::from(css::GREEN));
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Bounces a ray off of surfaces `MAX_BOUNCES` times.
 | |
| fn bounce_ray(mut ray: Ray3d, ray_cast: &mut MeshRayCast, gizmos: &mut Gizmos, color: Color) {
 | |
|     let mut intersections = Vec::with_capacity(MAX_BOUNCES + 1);
 | |
|     intersections.push((ray.origin, Color::srgb(30.0, 0.0, 0.0)));
 | |
| 
 | |
|     for i in 0..MAX_BOUNCES {
 | |
|         // Cast the ray and get the first hit
 | |
|         let Some((_, hit)) = ray_cast
 | |
|             .cast_ray(ray, &MeshRayCastSettings::default())
 | |
|             .first()
 | |
|         else {
 | |
|             break;
 | |
|         };
 | |
| 
 | |
|         // Draw the point of intersection and add it to the list
 | |
|         let brightness = 1.0 + 10.0 * (1.0 - i as f32 / MAX_BOUNCES as f32);
 | |
|         intersections.push((hit.point, Color::BLACK.mix(&color, brightness)));
 | |
|         gizmos.sphere(hit.point, 0.005, Color::BLACK.mix(&color, brightness * 2.0));
 | |
| 
 | |
|         // Reflect the ray off of the surface
 | |
|         ray.direction = Dir3::new(ray.direction.reflect(hit.normal)).unwrap();
 | |
|         ray.origin = hit.point + ray.direction * 1e-6;
 | |
|     }
 | |
|     gizmos.linestrip_gradient(intersections);
 | |
| }
 | |
| 
 | |
| // Set up a simple 3D scene
 | |
| fn setup(
 | |
|     mut commands: Commands,
 | |
|     mut meshes: ResMut<Assets<Mesh>>,
 | |
|     mut materials: ResMut<Assets<StandardMaterial>>,
 | |
| ) {
 | |
|     // Make a box of planes facing inward so the laser gets trapped inside
 | |
|     let plane_mesh = meshes.add(Plane3d::default());
 | |
|     let plane_material = materials.add(Color::from(css::GRAY).with_alpha(0.01));
 | |
|     let create_plane = move |translation, rotation| {
 | |
|         (
 | |
|             Transform::from_translation(translation)
 | |
|                 .with_rotation(Quat::from_scaled_axis(rotation)),
 | |
|             Mesh3d(plane_mesh.clone()),
 | |
|             MeshMaterial3d(plane_material.clone()),
 | |
|         )
 | |
|     };
 | |
| 
 | |
|     commands.spawn(create_plane(vec3(0.0, 0.5, 0.0), Vec3::X * PI));
 | |
|     commands.spawn(create_plane(vec3(0.0, -0.5, 0.0), Vec3::ZERO));
 | |
|     commands.spawn(create_plane(vec3(0.5, 0.0, 0.0), Vec3::Z * FRAC_PI_2));
 | |
|     commands.spawn(create_plane(vec3(-0.5, 0.0, 0.0), Vec3::Z * -FRAC_PI_2));
 | |
|     commands.spawn(create_plane(vec3(0.0, 0.0, 0.5), Vec3::X * -FRAC_PI_2));
 | |
|     commands.spawn(create_plane(vec3(0.0, 0.0, -0.5), Vec3::X * FRAC_PI_2));
 | |
| 
 | |
|     // Light
 | |
|     commands.spawn((
 | |
|         DirectionalLight::default(),
 | |
|         Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -0.1, 0.2, 0.0)),
 | |
|     ));
 | |
| 
 | |
|     // Camera
 | |
|     commands.spawn((
 | |
|         Camera3d::default(),
 | |
|         Camera {
 | |
|             hdr: true,
 | |
|             ..default()
 | |
|         },
 | |
|         Transform::from_xyz(1.5, 1.5, 1.5).looking_at(Vec3::ZERO, Vec3::Y),
 | |
|         Tonemapping::TonyMcMapface,
 | |
|         Bloom::default(),
 | |
|     ));
 | |
| }
 |