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::*;
#[derive(Debug)]
struct IsPressed(bool);
impl From<bool> for IsPressed {
fn from(item: bool) -> Self {
IsPressed(item)
}
}
use cgmath::Vector2;
use cgmath::Point3;
use winit::{dpi::PhysicalPosition, event::*};
#[derive(Debug)]
enum ButtonPress {
Up(IsPressed),
Down(IsPressed),
Left(IsPressed),
Right(IsPressed),
Forward(IsPressed),
Backward(IsPressed),
Up(ElementState),
Down(ElementState),
Left(ElementState),
Right(ElementState),
Forward(ElementState),
Backward(ElementState),
Reset(ElementState),
}
pub struct CameraController {
speed: f32,
button_press: Option<ButtonPress>,
old_mouse: PhysicalPosition<f64>,
mouse_movement: Vector2<f64>,
}
impl CameraController {
@@ -29,10 +25,12 @@ impl CameraController {
Self {
speed,
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 {
WindowEvent::KeyboardInput {
input:
@@ -42,55 +40,103 @@ impl CameraController {
..
},
..
} => {
let pressed = (*state == ElementState::Pressed).into();
match key {
} => match key {
VirtualKeyCode::W => {
self.button_press = Some(ButtonPress::Forward(pressed));
true
self.button_press = Some(ButtonPress::Forward(*state));
}
VirtualKeyCode::A => {
self.button_press = Some(ButtonPress::Left(pressed));
true
self.button_press = Some(ButtonPress::Left(*state));
}
VirtualKeyCode::S => {
self.button_press = Some(ButtonPress::Backward(pressed));
true
self.button_press = Some(ButtonPress::Backward(*state));
}
VirtualKeyCode::D => {
self.button_press = Some(ButtonPress::Right(pressed));
true
self.button_press = Some(ButtonPress::Right(*state));
}
VirtualKeyCode::Space => {
self.button_press = Some(ButtonPress::Up(pressed));
true
self.button_press = Some(ButtonPress::Up(*state));
}
VirtualKeyCode::LShift => {
self.button_press = Some(ButtonPress::Down(pressed));
true
self.button_press = Some(ButtonPress::Down(*state));
}
_ => false,
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;
// Casted eye -> target
let forward = camera.target - camera.eye;
let forward_norm = forward.normalize();
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 {
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;
}
Some(ButtonPress::Backward(IsPressed(true))) => {
Some(ButtonPress::Backward(ElementState::Pressed)) => {
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::{
event::*,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use winit::{dpi::PhysicalPosition, event::*, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder};
mod state;
mod vertex;
@@ -16,7 +12,12 @@ use crate::state::State;
fn main() {
env_logger::init();
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
let mut state = pollster::block_on(State::new(&window));
@@ -24,33 +25,14 @@ fn main() {
Event::WindowEvent {
ref event, // forward event
window_id
} if window_id == window.id() // be sure to only use the current one
=> if !state.input(event) { // don't continue if input hasn't been processed yet
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
_ => {}
} if window_id == window.id() => {
state.input(event, control_flow);
}
},
Event::RedrawRequested(_) => {
state.update();
// update the entire scene
state.update(&mut window);
// render the update
match state.render() {
Ok(_) => {},
// recreate swap_chain

View File

@@ -2,10 +2,7 @@ use wgpu::{
PrimitiveTopology,
util::DeviceExt,
};
use winit::{
event::*,
window::Window,
};
use winit::{dpi::PhysicalPosition, event::*, window::Window, event_loop::{ControlFlow}};
/// Hold state with important information
pub struct State {
@@ -135,7 +132,7 @@ impl State {
// x, y, z
// 1 up, 2 back
// +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
target: (0.0, 0.0, 0.0).into(),
// which way is up
@@ -307,9 +304,26 @@ impl State {
}
}
/// Idicate, whether an event has been fully processed
pub fn input(&mut self, event: &WindowEvent) -> bool {
/// Process input of the WindowEvent
pub fn input(&mut self, event: &WindowEvent, control_flow: &mut ControlFlow) {
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, .. } => {
// let x = (position.x as f64) / self.size.width 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;
// true
// }
_ => self.camera_controller.process_events(event)
_ => self.camera_controller.input(event)
}
}
/// Update State before render()
pub fn update(&mut self) {
pub fn update(&mut self, window: &mut winit::window::Window) {
// reposition 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
self.uniform.update_view_proj(&self.camera);
// write uniform buffer to queue