Somewhat working camera controller

This commit is contained in:
Marco Thomas
2021-08-28 15:08:58 +02:00
parent d841a0da12
commit 9476eca47c
3 changed files with 139 additions and 91 deletions

View File

@@ -1,27 +1,23 @@
use winit::event::*; use cgmath::Vector2;
use cgmath::Point3;
#[derive(Debug)] use winit::{dpi::PhysicalPosition, event::*};
struct IsPressed(bool);
impl From<bool> for IsPressed {
fn from(item: bool) -> Self {
IsPressed(item)
}
}
#[derive(Debug)] #[derive(Debug)]
enum ButtonPress { enum ButtonPress {
Up(IsPressed), Up(ElementState),
Down(IsPressed), Down(ElementState),
Left(IsPressed), Left(ElementState),
Right(IsPressed), Right(ElementState),
Forward(IsPressed), Forward(ElementState),
Backward(IsPressed), Backward(ElementState),
Reset(ElementState),
} }
pub struct CameraController { pub struct CameraController {
speed: f32, speed: f32,
button_press: Option<ButtonPress>, button_press: Option<ButtonPress>,
old_mouse: PhysicalPosition<f64>,
mouse_movement: Vector2<f64>,
} }
impl CameraController { impl CameraController {
@@ -29,10 +25,12 @@ impl CameraController {
Self { Self {
speed, speed,
button_press: None, button_press: None,
old_mouse: PhysicalPosition::new(0.0, 0.0),
mouse_movement: Vector2::new(0.0, 0.0),
} }
} }
pub fn process_events(&mut self, event: &WindowEvent) -> bool { pub fn input(&mut self, event: &WindowEvent) {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: input:
@@ -42,55 +40,103 @@ impl CameraController {
.. ..
}, },
.. ..
} => { } => match key {
let pressed = (*state == ElementState::Pressed).into(); VirtualKeyCode::W => {
match key { self.button_press = Some(ButtonPress::Forward(*state));
VirtualKeyCode::W => {
self.button_press = Some(ButtonPress::Forward(pressed));
true
}
VirtualKeyCode::A => {
self.button_press = Some(ButtonPress::Left(pressed));
true
}
VirtualKeyCode::S => {
self.button_press = Some(ButtonPress::Backward(pressed));
true
}
VirtualKeyCode::D => {
self.button_press = Some(ButtonPress::Right(pressed));
true
}
VirtualKeyCode::Space => {
self.button_press = Some(ButtonPress::Up(pressed));
true
}
VirtualKeyCode::LShift => {
self.button_press = Some(ButtonPress::Down(pressed));
true
}
_ => false,
} }
VirtualKeyCode::A => {
self.button_press = Some(ButtonPress::Left(*state));
}
VirtualKeyCode::S => {
self.button_press = Some(ButtonPress::Backward(*state));
}
VirtualKeyCode::D => {
self.button_press = Some(ButtonPress::Right(*state));
}
VirtualKeyCode::Space => {
self.button_press = Some(ButtonPress::Up(*state));
}
VirtualKeyCode::LShift => {
self.button_press = Some(ButtonPress::Down(*state));
}
VirtualKeyCode::Return => {
self.button_press = Some(ButtonPress::Reset(*state));
}
_ => {},
},
WindowEvent::CursorMoved { position, .. } => {
self.mouse_movement = Vector2 {
x: (*position).x - self.old_mouse.x,
y: (*position).y - self.old_mouse.y,
};
self.old_mouse = *position;
} }
_ => false, _ => {},
} }
} }
pub fn update_camera(&self, camera: &mut crate::camera::Camera) { /// Update the camera vectors
/// Vectors are casted from (0, 0, 0) to both the target and the eye
pub fn update_camera(&mut self, camera: &mut crate::camera::Camera) {
// TODO what about delta time?
use cgmath::InnerSpace; use cgmath::InnerSpace;
// Casted eye -> target
let forward = camera.target - camera.eye; let forward = camera.target - camera.eye;
let forward_norm = forward.normalize(); let forward_norm = forward.normalize();
let forward_mag = forward.magnitude(); let forward_mag = forward.magnitude();
// cross product of forwards and up => perpendicular right
let right = forward_norm.cross(camera.up);
let right_norm = right.normalize();
match self.button_press { match self.button_press {
Some(ButtonPress::Forward(IsPressed(true))) if forward_mag > self.speed => { // keyboard buttons:
// target stays in place
// eye moves
// check movement vector, if too close
Some(ButtonPress::Forward(ElementState::Pressed)) if forward_mag > self.speed => {
camera.eye += forward_norm * self.speed; camera.eye += forward_norm * self.speed;
} }
Some(ButtonPress::Backward(IsPressed(true))) => { Some(ButtonPress::Backward(ElementState::Pressed)) => {
camera.eye -= forward_norm * self.speed; camera.eye -= forward_norm * self.speed;
} }
Some(ButtonPress::Right(ElementState::Pressed)) => {
let vector = right_norm * self.speed;
camera.eye += vector;
camera.target += vector;
}
Some(ButtonPress::Left(ElementState::Pressed)) => {
let vector = right_norm * self.speed;
camera.eye -= vector;
camera.target -= vector;
}
Some(ButtonPress::Up(ElementState::Pressed)) => {
let vector = camera.up.normalize() * self.speed;
camera.eye += vector;
camera.target += vector;
}
Some(ButtonPress::Down(ElementState::Pressed)) => {
let vector = camera.up.normalize() * self.speed;
camera.eye -= vector;
camera.target -= vector;
}
Some(ButtonPress::Reset(ElementState::Pressed)) => {
camera.target = Point3::new(0.0, 0.0, 0.0);
}
_ => {} _ => {}
} }
// TODO add rest of the movement
// mouse movement:
// target moves
// eye stays in place
let decr = 200.0;
camera.target.x += (self.mouse_movement.x as f32) / decr;
camera.target.y -= (self.mouse_movement.y as f32) / decr;
self.mouse_movement = Vector2 { x: 0.0, y: 0.0 };
dbg!(&camera.eye);
dbg!(&camera.target);
dbg!(self.mouse_movement);
} }
} }

View File

@@ -1,8 +1,4 @@
use winit::{ use winit::{dpi::PhysicalPosition, event::*, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder};
event::*,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
mod state; mod state;
mod vertex; mod vertex;
@@ -16,7 +12,12 @@ use crate::state::State;
fn main() { fn main() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let mut window = WindowBuilder::new()
.build(&event_loop)
.unwrap();
//window.set_cursor_visible(false);
//window.set_cursor_grab(true).unwrap();
// wait until Future is ready // wait until Future is ready
let mut state = pollster::block_on(State::new(&window)); let mut state = pollster::block_on(State::new(&window));
@@ -24,33 +25,14 @@ fn main() {
Event::WindowEvent { Event::WindowEvent {
ref event, // forward event ref event, // forward event
window_id window_id
} if window_id == window.id() // be sure to only use the current one } if window_id == window.id() => {
=> if !state.input(event) { // don't continue if input hasn't been processed yet state.input(event, control_flow);
match event { }
// TODO can't this be moved to state.input()
WindowEvent::CloseRequested |
WindowEvent::KeyboardInput {
input: KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
// ignore the other entries
..
},
// ignore the other entries
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size)
},
WindowEvent::ScaleFactorChanged {new_inner_size, ..} => {
state.resize(**new_inner_size);
},
// Discard all other WindowEvents
_ => {}
}
},
Event::RedrawRequested(_) => { Event::RedrawRequested(_) => {
state.update(); // update the entire scene
state.update(&mut window);
// render the update
match state.render() { match state.render() {
Ok(_) => {}, Ok(_) => {},
// recreate swap_chain // recreate swap_chain

View File

@@ -2,10 +2,7 @@ use wgpu::{
PrimitiveTopology, PrimitiveTopology,
util::DeviceExt, util::DeviceExt,
}; };
use winit::{ use winit::{dpi::PhysicalPosition, event::*, window::Window, event_loop::{ControlFlow}};
event::*,
window::Window,
};
/// Hold state with important information /// Hold state with important information
pub struct State { pub struct State {
@@ -135,7 +132,7 @@ impl State {
// x, y, z // x, y, z
// 1 up, 2 back // 1 up, 2 back
// +z is out of the screen // +z is out of the screen
eye: (0.0, 1.0, 2.0).into(), eye: (0.0, 0.0, 2.0).into(),
// look at the center // look at the center
target: (0.0, 0.0, 0.0).into(), target: (0.0, 0.0, 0.0).into(),
// which way is up // which way is up
@@ -307,9 +304,26 @@ impl State {
} }
} }
/// Idicate, whether an event has been fully processed /// Process input of the WindowEvent
pub fn input(&mut self, event: &WindowEvent) -> bool { pub fn input(&mut self, event: &WindowEvent, control_flow: &mut ControlFlow) {
match event { match event {
WindowEvent::CloseRequested |
WindowEvent::KeyboardInput {
input: KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
// ignore the other entries
..
},
// ignore the other entries
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
self.resize(*physical_size)
},
WindowEvent::ScaleFactorChanged {new_inner_size, ..} => {
self.resize(**new_inner_size);
},
// WindowEvent::CursorMoved { position, .. } => { // WindowEvent::CursorMoved { position, .. } => {
// let x = (position.x as f64) / self.size.width as f64; // let x = (position.x as f64) / self.size.width as f64;
// let y = (position.y as f64) / self.size.height as f64; // let y = (position.y as f64) / self.size.height as f64;
@@ -327,14 +341,20 @@ impl State {
// self.use_pentagon = !self.use_pentagon; // self.use_pentagon = !self.use_pentagon;
// true // true
// } // }
_ => self.camera_controller.process_events(event) _ => self.camera_controller.input(event)
} }
} }
/// Update State before render() /// Update State before render()
pub fn update(&mut self) { pub fn update(&mut self, window: &mut winit::window::Window) {
// reposition camera // reposition camera
self.camera_controller.update_camera(&mut self.camera); self.camera_controller.update_camera(&mut self.camera);
// always move cursor back to center after controller update,
// so we don't loose it
window.set_cursor_position(PhysicalPosition::new(
self.size.width / 2,
self.size.height / 2,
)).unwrap();
// update projection for uniform buffer // update projection for uniform buffer
self.uniform.update_view_proj(&self.camera); self.uniform.update_view_proj(&self.camera);
// write uniform buffer to queue // write uniform buffer to queue