103 lines
3.1 KiB
Rust
103 lines
3.1 KiB
Rust
use bevy::prelude::*;
|
|
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, (camera_orbit_controls,))
|
|
.run();
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct CameraController {
|
|
pub radius: f32,
|
|
pub theta: f32, // azimuthal angle
|
|
pub phi: f32, // polar angle
|
|
pub last_mouse_pos: Option<Vec2>,
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
// Camera with controller
|
|
let radius = 30.0;
|
|
let theta = 0.0;
|
|
let phi = std::f32::consts::FRAC_PI_4;
|
|
let cam_pos = spherical_to_cartesian(radius, theta, phi);
|
|
commands.spawn((
|
|
Camera3dBundle {
|
|
transform: Transform::from_translation(cam_pos).looking_at(Vec3::ZERO, Vec3::Y),
|
|
..default()
|
|
},
|
|
CameraController {
|
|
radius,
|
|
theta,
|
|
phi,
|
|
last_mouse_pos: None,
|
|
},
|
|
));
|
|
// Light
|
|
commands.spawn(PointLightBundle {
|
|
point_light: PointLight {
|
|
intensity: 1500.0,
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
transform: Transform::from_xyz(4.0, 8.0, 4.0),
|
|
..default()
|
|
});
|
|
// Add a sphere at the origin using the new Sphere primitive
|
|
let mesh = meshes.add(Mesh::from(Sphere { radius: 1.0, ..default() }));
|
|
let material = materials.add(StandardMaterial {
|
|
base_color: Color::BLUE,
|
|
..default()
|
|
});
|
|
commands.spawn(PbrBundle {
|
|
mesh,
|
|
material,
|
|
..default()
|
|
});
|
|
}
|
|
|
|
fn spherical_to_cartesian(radius: f32, theta: f32, phi: f32) -> Vec3 {
|
|
let x = radius * phi.sin() * theta.cos();
|
|
let y = radius * phi.cos();
|
|
let z = radius * phi.sin() * theta.sin();
|
|
Vec3::new(x, y, z)
|
|
}
|
|
|
|
fn camera_orbit_controls(
|
|
mut query: Query<(&mut Transform, &mut CameraController)>,
|
|
mut mouse_motion_events: EventReader<MouseMotion>,
|
|
mut mouse_wheel_events: EventReader<MouseWheel>,
|
|
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
|
windows: Query<&Window>,
|
|
) {
|
|
let window = if let Some(window) = windows.iter().next() { window } else { return; };
|
|
let mut delta = Vec2::ZERO;
|
|
for event in mouse_motion_events.read() {
|
|
delta += event.delta;
|
|
}
|
|
let mut scroll = 0.0;
|
|
for event in mouse_wheel_events.read() {
|
|
scroll += event.y;
|
|
}
|
|
for (mut transform, mut controller) in query.iter_mut() {
|
|
// Orbit (right mouse button)
|
|
if mouse_button_input.pressed(MouseButton::Right) {
|
|
let sensitivity = 0.01;
|
|
controller.theta -= delta.x * sensitivity;
|
|
controller.phi = (controller.phi - delta.y * sensitivity).clamp(0.05, std::f32::consts::PI - 0.05);
|
|
}
|
|
// Zoom
|
|
if scroll.abs() > 0.0 {
|
|
controller.radius = (controller.radius - scroll).clamp(3.0, 200.0);
|
|
}
|
|
// Update camera position
|
|
let pos = spherical_to_cartesian(controller.radius, controller.theta, controller.phi);
|
|
*transform = Transform::from_translation(pos).looking_at(Vec3::ZERO, Vec3::Y);
|
|
}
|
|
}
|