improve cam and example

This commit is contained in:
Aevyrie 2023-07-18 20:55:30 -07:00
parent c0113e51e3
commit 347f51a5d6
2 changed files with 91 additions and 49 deletions

View File

@ -1,7 +1,6 @@
use bevy::{
math::Vec3A,
prelude::*,
render::primitives::{Aabb, Sphere},
transform::TransformSystem,
window::{CursorGrabMode, PrimaryWindow, Window, WindowMode},
};
use big_space::{
@ -21,6 +20,10 @@ fn main() {
.insert_resource(ClearColor(Color::BLACK))
.add_systems(Startup, (setup, ui_setup))
.add_systems(Update, (cursor_grab_system, ui_text_system))
.add_systems(
PostUpdate,
highlight_nearest_sphere.after(TransformSystem::TransformPropagate),
)
.run()
}
@ -34,11 +37,17 @@ fn setup(
Camera3dBundle {
transform: Transform::from_xyz(0.0, 0.0, 8.0)
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
projection: Projection::Perspective(PerspectiveProjection {
near: 1e-16,
..default()
}),
..default()
},
GridCell::<i128>::default(), // All spatial entities need this component
FloatingOrigin, // Important: marks this as the entity to use as the floating origin
CameraController::default().with_max_speed(10e35), // Built-in camera controller
CameraController::default()
.with_max_speed(10e35)
.with_smoothness(0.9, 0.8), // Built-in camera controller
));
let mesh_handle = meshes.add(
@ -57,8 +66,8 @@ fn setup(
});
let mut translation = Vec3::ZERO;
for i in 1..=37_i128 {
let j = 10_f32.powf(i as f32 - 10.0);
for i in -12..=27 {
let j = 10_f32.powf(i as f32);
translation.x += j;
commands.spawn((
PbrBundle {
@ -67,10 +76,6 @@ fn setup(
transform: Transform::from_scale(Vec3::splat(j)).with_translation(translation),
..default()
},
Aabb::from(Sphere {
center: Vec3A::ZERO,
radius: j / 2.0,
}),
GridCell::<i128>::default(),
));
}
@ -93,7 +98,7 @@ fn ui_setup(mut commands: Commands) {
TextBundle::from_section(
"",
TextStyle {
font_size: 18.0,
font_size: 28.0,
color: Color::WHITE,
..default()
},
@ -109,6 +114,19 @@ fn ui_setup(mut commands: Commands) {
));
}
fn highlight_nearest_sphere(
cameras: Query<&CameraController>,
objects: Query<&GlobalTransform>,
mut gizmos: Gizmos,
) {
let Some((entity, _)) = cameras.single().nearest_object() else { return };
let Ok(transform) = objects.get(entity) else { return };
let (scale, rotation, translation) = transform.to_scale_rotation_translation();
gizmos
.sphere(translation, rotation, scale.x * 0.505, Color::RED)
.circle_segments(128);
}
fn ui_text_system(
mut text: Query<&mut Text, With<BigSpaceDebugText>>,
time: Res<Time>,
@ -136,18 +154,10 @@ fn ui_text_system(
let nearest_text = if let Some(nearest) = camera.single().nearest_object() {
let dia = objects.get(nearest.0).unwrap().scale.max_element();
let dia_fact = match dia {
d if d > 8.8e26 => "(Greater than the diameter of the observable universe)",
d if d > 1e21 => "(Greater than the diameter of the Milky Way galaxy)",
d if d > 7e12 => "(Greater than the diameter of Pluto's orbit)",
d if d > 1.4e9 => "(Greater than the diameter of the Sun)",
d if d > 1.4e8 => "(Greater than the diameter of Earth)",
d if d > 12e6 => "(Greater than the diameter of Earth)",
d if d > 3e6 => "(Greater than the diameter of the Moon)",
_ => "",
};
let (fact_dia, fact) = closest(dia);
let dist = nearest.1;
format!("Nearest sphere diameter: {dia:.0e} m {dia_fact}\nNearest sphere distance: {dist:.0e} m",)
let multiple = dia / fact_dia;
format!("\nNearest sphere distance: {dist:.0e} m\nNearest sphere diameter: {dia:.0e} m\n{multiple:.1}x {fact}",)
} else {
"".into()
};
@ -156,6 +166,43 @@ fn ui_text_system(
format!("{grid_text}\n{translation_text}\n{camera_text}\n{nearest_text}");
}
fn closest<'a>(diameter: f32) -> (f32, &'a str) {
let items = vec![
(8.8e26, "diameter of the observable universe"),
(9e25, "length of the Hercules-Corona Borealis Great Wall"),
(1e24, "diameter of the Local Supercluster"),
(9e22, "diameter of the Local Group"),
(1e21, "diameter of the Milky Way galaxy"),
(5e16, "length of the Pillars of Creation"),
(1.8e14, "diameter of Messier 87"),
(7e12, "diameter of Pluto's orbit"),
(24e9, "diameter of Sagittarius A"),
(1.4e9, "diameter of the Sun"),
(1.4e8, "diameter of Jupiter"),
(12e6, "diameter of Earth"),
(3e6, "diameter of the Moon"),
(9e3, "height of Mt. Everest"),
(2e0, "height of a human"),
(1e-1, "size of a cat"),
(1e-3, "size of an insect"),
(1e-4, "diameter of a eukaryotic cell"),
(1e-6, "diameter of a bacteria"),
(50e-9, "size of a phage"),
(5e-9, "size of a transistor"),
(100e-12, "diameter of a carbon atom"),
(40e-12, "diameter of a hydrogen atom"),
(4e-12, "diameter of an electron"),
];
let mut min = items[0];
for item in items.iter() {
if (item.0 - diameter).abs() < (min.0 - diameter).abs() {
min = item.to_owned();
}
}
min
}
fn cursor_grab_system(
mut windows: Query<&mut Window, With<PrimaryWindow>>,
mut cam: ResMut<CameraInput>,

View File

@ -23,7 +23,7 @@ impl<P: GridPrecision> Plugin for CameraControllerPlugin<P> {
default_camera_inputs
.before(camera_controller::<P>)
.run_if(|input: Res<CameraInput>| !input.defaults_disabled),
nearest_objects.before(camera_controller::<P>),
nearest_objects::<P>.before(camera_controller::<P>),
camera_controller::<P>.before(TransformSystem::TransformPropagate),
),
);
@ -163,23 +163,26 @@ pub fn default_camera_inputs(
}
/// Find the object nearest the camera
pub fn nearest_objects(
objects: Query<(Entity, &GlobalTransform, &Aabb)>,
mut camera: Query<(&GlobalTransform, &mut CameraController)>,
pub fn nearest_objects<T: GridPrecision>(
settings: Res<FloatingOriginSettings>,
objects: Query<(Entity, &GridCell<T>, &Transform, &Aabb)>,
mut camera: Query<(&mut CameraController, &GridCell<T>, &Transform)>,
) {
for (cam_global_transform, mut controller) in camera.iter_mut() {
let nearest_object = objects
.iter()
.map(|(entity, transform, aabb)| {
let dist = (transform.translation().as_dvec3() + aabb.center.as_dvec3()
- cam_global_transform.translation().as_dvec3())
.length()
- aabb.half_extents.as_dvec3().max_element();
(entity, dist)
})
.reduce(|nearest, this| if this.1 < nearest.1 { this } else { nearest });
controller.nearest_object = nearest_object;
}
let (mut camera, cam_cell, cam_transform) = camera.single_mut();
let nearest_object = objects
.iter()
.map(|(entity, cell, obj_transform, aabb)| {
let pos = settings.grid_position_double(&(cell - cam_cell), obj_transform)
- cam_transform.translation.as_dvec3();
let dist = pos.length()
- (aabb.half_extents.as_dvec3() * obj_transform.scale.as_dvec3())
.abs()
.max_element();
(entity, dist)
})
.filter(|v| v.1.is_finite())
.reduce(|nearest, this| if this.1 < nearest.1 { this } else { nearest });
camera.nearest_object = nearest_object;
}
/// Uses [`CameraInput`] state to update the camera position.
@ -191,7 +194,7 @@ pub fn camera_controller<P: GridPrecision>(
) {
for (mut cam_transform, mut controller, mut cell) in camera.iter_mut() {
let speed = match (controller.nearest_object, controller.slow_near_objects) {
(Some(nearest), true) => nearest.1,
(Some(nearest), true) => nearest.1.abs(),
_ => controller.max_speed,
} * (1.0 + input.boost as usize as f64);
@ -213,16 +216,8 @@ pub fn camera_controller<P: GridPrecision>(
cam_transform.rotation *= new_rotation.as_f32();
// Store the new velocity to be used in the next frame
controller.vel_translation = if vel_t_next.length().abs() < 0.001 {
DVec3::ZERO
} else {
vel_t_next
};
controller.vel_rotation = if new_rotation.to_axis_angle().1.abs() < 0.001 {
DQuat::IDENTITY
} else {
new_rotation
};
controller.vel_translation = vel_t_next;
controller.vel_rotation = new_rotation;
input.reset();
}