adding camera controller

This commit is contained in:
Piotrek
2021-04-13 16:34:42 +02:00
parent 7a0d14d8d6
commit 026a21c9db
5 changed files with 147 additions and 24 deletions
+22 -8
View File
@@ -1,3 +1,5 @@
use std::sync::Arc;
use winit::event::Event;
use winit::{window::Window, dpi::PhysicalSize, event::WindowEvent};
use wgpu::util::DeviceExt;
use futures::executor::block_on;
@@ -6,6 +8,7 @@ use crate::vertex::Vertex;
use crate::texture::Texture;
use crate::camera::Camera;
use crate::uniforms::Uniforms;
use crate::camera_controller::CameraController;
const VERTICES: &[Vertex] = &[
Vertex { position: [-1.0, 1.0, 0.0], uv: [0.0, 0.0] },
@@ -35,7 +38,9 @@ pub struct App {
// Texture
bind_group: wgpu::BindGroup,
// Camera
camera: Camera
camera: Camera,
camera_controller: CameraController,
uniforms: Uniforms
}
impl App {
@@ -46,7 +51,7 @@ impl App {
format: adapter.get_swap_chain_preferred_format(&surface),
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
present_mode: wgpu::PresentMode::Mailbox, // Fifo = Vsync
};
let swapchain = device.create_swap_chain(&surface, &swapchain_desc);
(swapchain_desc, swapchain)
@@ -209,9 +214,10 @@ impl App {
// Cam
let aspect = swapchain_desc.width as f32 / swapchain_desc.height as f32;
let camera = Camera::new((0.0, 1.0, 2.0).into(), (0.0, 0.0, 0.0).into(), aspect);
let camera = Camera::new((0.0, 0.0, 2.0).into(), (0.0, 0.0, -1.0).into(), aspect);
let mut uniforms = Uniforms::new();
uniforms.update_projection_matrix(&camera);
let camera_controller = CameraController::new(2.0);
// Buffers
let vertex_buffer = Self::create_buffer(&device, wgpu::BufferUsage::VERTEX, bytemuck::cast_slice(VERTICES));
@@ -229,7 +235,7 @@ impl App {
// Save values in app
println!("Initialized");
Self { surface, device, queue, swapchain_desc, swapchain, pipeline, vertex_buffer, index_buffer, uniform_buffer, bind_group, uniform_bind_group, camera, }
Self { surface, device, queue, swapchain_desc, swapchain, pipeline, vertex_buffer, index_buffer, uniform_buffer, bind_group, uniform_bind_group, camera, uniforms, camera_controller }
}
pub fn resize(&mut self, new_size: Option<PhysicalSize<u32>>) {
@@ -239,20 +245,28 @@ impl App {
// Recreate swapchain
self.swapchain_desc.width = size.width;
self.swapchain_desc.height = size.height;
// Update camera
self.camera.set_aspect(size.width as f32 / size.height as f32);
}
// Recreate swapchain
self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc);
}
pub fn input(&mut self, _event: &WindowEvent) -> bool {
false
pub fn input(&mut self, event: Arc<Event<()>>) -> bool {
self.camera_controller.handle_input(event.as_ref())
}
pub fn update(&mut self) {
// Nothing right now
pub fn update(&mut self, delta_time: f32) {
// Update camera
self.camera_controller.update_camera(&mut self.camera, delta_time);
// Update projection matrix buffer
self.uniforms.update_projection_matrix(&self.camera);
self.queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[self.uniforms]));
}
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
// Get next frame to render to
let frame = self.swapchain.get_current_frame()?.output;
// Create encoder that will build command buffer for us
+11 -7
View File
@@ -9,9 +9,9 @@ const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
);
pub struct Camera {
pos: Point3<f32>,
target: Point3<f32>,
up: Vector3<f32>,
pub position: Point3<f32>,
pub forward: Vector3<f32>,
pub up: Vector3<f32>,
aspect: f32,
fovy: f32,
znear: f32,
@@ -20,10 +20,10 @@ pub struct Camera {
impl Camera {
pub fn new(pos: Point3<f32>, target: Point3<f32>, aspect: f32) -> Self {
pub fn new(position: Point3<f32>, forward: Vector3<f32>, aspect: f32) -> Self {
Self {
pos,
target,
position,
forward,
up: Vector3::unit_y(),
aspect,
fovy: 45.0,
@@ -32,8 +32,12 @@ impl Camera {
}
}
pub fn set_aspect(&mut self, aspect: f32) {
self.aspect = aspect;
}
pub fn projection_matrix(&self) -> Matrix4<f32> {
let view = Matrix4::look_at_rh(self.pos, self.target, self.up);
let view = Matrix4::look_to_rh(self.position, self.forward, self.up);
let proj = cgmath::perspective(Deg(self.fovy), self.aspect, self.znear, self.zfar);
return OPENGL_TO_WGPU_MATRIX * proj * view;
}
+92
View File
@@ -0,0 +1,92 @@
use winit::event::Event;
use winit::event::{WindowEvent, DeviceEvent, KeyboardInput, ElementState, VirtualKeyCode};
use cgmath::InnerSpace;
use crate::camera::Camera;
#[derive(Default)]
struct CameraMovement {
pub up: bool,
pub down: bool,
pub fwd: bool,
pub back: bool,
pub left: bool,
pub right: bool,
}
struct CameraRotation {
pub yaw: f32, // vertical axis
pub pitch: f32, // horizontal axis
pub last_update: Option<std::time::Instant>
}
pub struct CameraController {
movement: CameraMovement,
rotation: CameraRotation,
speed: f32
}
impl CameraController {
pub fn new(speed: f32) -> Self {
let rotation = CameraRotation { yaw: 0.0, pitch: 0.0, last_update: None };
Self { movement: CameraMovement::default(), rotation, speed }
}
pub fn handle_input(&mut self, event: &Event<()>) -> bool {
match event {
Event::WindowEvent { ref event, .. } => {
match event {
WindowEvent::KeyboardInput { input: KeyboardInput { state, virtual_keycode: Some(keycode), .. }, .. } => {
let is_pressed = *state == ElementState::Pressed;
match keycode {
VirtualKeyCode::Space => { self.movement.up = is_pressed; true }
VirtualKeyCode::LShift => { self.movement.down = is_pressed; true }
VirtualKeyCode::W | VirtualKeyCode::Up => { self.movement.fwd = is_pressed; true }
VirtualKeyCode::A | VirtualKeyCode::Left => { self.movement.left = is_pressed; true }
VirtualKeyCode::S | VirtualKeyCode::Down => { self.movement.back = is_pressed; true }
VirtualKeyCode::D | VirtualKeyCode::Right => { self.movement.right = is_pressed; true }
_ => false,
}
}
_ => false
}
},
Event::DeviceEvent { device_id: _, event } => {
match event {
DeviceEvent::MouseMotion { delta } => {
if let Some(last_update) = self.rotation.last_update {
let elapsed = last_update.elapsed().as_secs_f32();
self.rotation.yaw += (delta.0 as f32) / elapsed;
self.rotation.pitch += (delta.1 as f32) / elapsed;
}
self.rotation.last_update = Some(std::time::Instant::now());
true
}
_ => false
}
}
_ => false
}
}
pub fn update_camera(&mut self, camera: &mut Camera, delta_time: f32) {
// Movement amount
let amount = delta_time * self.speed;
// Forward and backwards
if self.movement.fwd && camera.forward.magnitude() > amount { camera.position += camera.forward.normalize() * amount; }
if self.movement.back { camera.position -= camera.forward.normalize() * amount; }
// Up and down
if self.movement.up { camera.position += camera.up.normalize() * amount; }
if self.movement.down { camera.position -= camera.up.normalize() * amount; }
// Left and right
let right = camera.forward.cross(camera.up);
if self.movement.right { camera.position += right * amount; }
if self.movement.left { camera.position -= right * amount; }
println!("Yaw: {}", self.rotation.yaw);
}
}
+20 -8
View File
@@ -1,3 +1,4 @@
use std::sync::Arc;
use winit::{
event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode},
event_loop::{ControlFlow, EventLoop},
@@ -10,6 +11,7 @@ mod texture;
mod uniforms;
mod camera;
mod app;
mod camera_controller;
use app::App;
fn main() {
@@ -28,12 +30,20 @@ fn main() {
let mut fps_timer = std::time::Instant::now();
let mut fps_counter = 0;
let mut delta_timer = std::time::Instant::now();
// Run event loop
events.run(move |e, _, c| {
match e {
let ev = Arc::new(e);
if app.input(ev.clone()) {
// Event consumed
return;
}
match ev.as_ref() {
// Window event
Event::WindowEvent { ref event, .. } => if !app.input(event) {
Event::WindowEvent { ref event, .. } => {
match event {
// Window closed
WindowEvent::CloseRequested => {
@@ -69,18 +79,20 @@ fn main() {
Event::RedrawRequested(_) => {
// Display FPS
let elapsed = fps_timer.elapsed().as_millis();
if elapsed >= 1000 {
let elapsed_sec = (elapsed as f32) / 1000.0;
let fps = (fps_counter as f32) / elapsed_sec;
println!("FPS: {}", fps);
let elapsed = fps_timer.elapsed().as_secs_f64();
if elapsed >= 0.5 {
let fps = (fps_counter as f64) / elapsed;
println!("FPS: {}", (fps*100.0_f64).floor()/100.0);
fps_timer = std::time::Instant::now();
fps_counter = 0;
}
fps_counter += 1;
// Update and Render
app.update();
app.update(delta_timer.elapsed().as_secs_f32());
delta_timer = std::time::Instant::now();
// Render
match app.render() {
Ok(_) => { }
// Recreate the swap_chain if lost
+2 -1
View File
@@ -47,7 +47,8 @@ impl Texture {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
//mag_filter: wgpu::FilterMode::Linear,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()