Somewhat working camera controller
This commit is contained in:
@@ -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();
|
|
||||||
match key {
|
|
||||||
VirtualKeyCode::W => {
|
VirtualKeyCode::W => {
|
||||||
self.button_press = Some(ButtonPress::Forward(pressed));
|
self.button_press = Some(ButtonPress::Forward(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::A => {
|
VirtualKeyCode::A => {
|
||||||
self.button_press = Some(ButtonPress::Left(pressed));
|
self.button_press = Some(ButtonPress::Left(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::S => {
|
VirtualKeyCode::S => {
|
||||||
self.button_press = Some(ButtonPress::Backward(pressed));
|
self.button_press = Some(ButtonPress::Backward(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::D => {
|
VirtualKeyCode::D => {
|
||||||
self.button_press = Some(ButtonPress::Right(pressed));
|
self.button_press = Some(ButtonPress::Right(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Space => {
|
VirtualKeyCode::Space => {
|
||||||
self.button_press = Some(ButtonPress::Up(pressed));
|
self.button_press = Some(ButtonPress::Up(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::LShift => {
|
VirtualKeyCode::LShift => {
|
||||||
self.button_press = Some(ButtonPress::Down(pressed));
|
self.button_press = Some(ButtonPress::Down(*state));
|
||||||
true
|
|
||||||
}
|
}
|
||||||
_ => 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;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/main.rs
44
src/main.rs
@@ -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
|
||||||
|
|||||||
38
src/state.rs
38
src/state.rs
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user