adding camera controller
This commit is contained in:
+22
-8
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user