Dummy scene with mostly-working camera

This commit is contained in:
Matthew Gordon 2024-08-22 23:37:47 -03:00
parent 7e77e51b14
commit 78f6d3d0ff
3 changed files with 145 additions and 0 deletions

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "terroir"
version = "0.1.0"
edition = "2021"
[dependencies]
bevy = { version = "0.14.1", features = ["dynamic_linking"] }
[profile.dev]
opt-level = 1
[profile.dev.package."*"]
opt-level = 3
[profile.release]
codegen-units = 1
lto = "thin"

94
src/camera.rs Normal file
View File

@ -0,0 +1,94 @@
use {
bevy::{input::mouse::MouseMotion, prelude::*, window::CursorGrabMode},
std::f32::consts::{FRAC_PI_2, FRAC_PI_4, PI, TAU},
};
#[derive(Bundle, Default)]
pub struct PanOrbitCameraBundle {
pub camera: Camera3dBundle,
pub state: PanOrbitState,
pub settings: PanOrbitSettings,
}
#[derive(Component)]
pub struct PanOrbitState {
pub center: Vec3,
pub radius: f32,
pub pitch: f32,
pub yaw: f32,
}
impl Default for PanOrbitState {
fn default() -> Self {
PanOrbitState {
center: Vec3::ZERO,
radius: 2.0,
pitch: -FRAC_PI_4,
yaw: 0.0,
}
}
}
/// The configuration of the pan-orbit controller
#[derive(Component)]
pub struct PanOrbitSettings {
/// World units per pixel of mouse motion
pub pan_sensitivity: f32,
/// Radians per pixel of mouse motion
pub orbit_sensitivity: f32,
/// Exponent per pixel of mouse motion
pub zoom_sensitivity: f32,
}
impl Default for PanOrbitSettings {
fn default() -> Self {
PanOrbitSettings {
pan_sensitivity: 0.001, // 1000 pixels per world unit
orbit_sensitivity: 0.1f32.to_radians(), // 0.1 degree per pixel
zoom_sensitivity: 0.01,
}
}
}
pub fn update(
mut evr_motion: EventReader<MouseMotion>,
mouse: Res<ButtonInput<MouseButton>>,
mut q_camera: Query<(&PanOrbitSettings, &mut PanOrbitState, &mut Transform)>,
mut q_window: Query<&mut Window>,
) {
let mouse_motion: Vec2 = evr_motion.read().map(|ev| ev.delta).sum();
for (settings, mut state, mut transform) in &mut q_camera {
if mouse.any_pressed([MouseButton::Left, MouseButton::Right]) {
q_window.single_mut().cursor.grab_mode = CursorGrabMode::Locked;
} else {
q_window.single_mut().cursor.grab_mode = CursorGrabMode::None;
}
if mouse.pressed(MouseButton::Right) {
state.pitch = (state.pitch - settings.orbit_sensitivity * mouse_motion.y)
.clamp(-FRAC_PI_2, FRAC_PI_2);
state.yaw += settings.orbit_sensitivity * mouse_motion.x;
if state.yaw > PI {
state.yaw -= TAU;
}
if state.yaw < -PI {
state.yaw += TAU;
}
}
if mouse.pressed(MouseButton::Left) {
// TODO this needs to take the current rotation into account
state.center += (settings.pan_sensitivity * mouse_motion * -1.0)
.extend(0.0)
.xzy();
}
if mouse.pressed(MouseButton::Middle) {
state.radius = (state.radius + settings.zoom_sensitivity * mouse_motion.y).max(0.0);
}
transform.rotation = Quat::from_euler(EulerRot::YXZ, state.yaw, state.pitch, 0.0);
transform.translation = state.center + transform.back() * state.radius;
}
}

34
src/main.rs Normal file
View File

@ -0,0 +1,34 @@
use bevy::prelude::*;
mod camera;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, camera::update)
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(PbrBundle {
mesh: meshes.add(Cuboid::new(1.0, 0.2, 1.0)),
material: materials.add(Color::srgb_u8(124, 144, 255)),
transform: Transform::from_xyz(0.0, -0.2, 0.0),
..default()
});
commands.spawn(PointLightBundle {
point_light: PointLight {
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
commands.spawn(camera::PanOrbitCameraBundle::default());
}