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 winit::{window::Window, dpi::PhysicalSize, event::WindowEvent};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
@@ -6,6 +8,7 @@ use crate::vertex::Vertex;
|
|||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
use crate::uniforms::Uniforms;
|
use crate::uniforms::Uniforms;
|
||||||
|
use crate::camera_controller::CameraController;
|
||||||
|
|
||||||
const VERTICES: &[Vertex] = &[
|
const VERTICES: &[Vertex] = &[
|
||||||
Vertex { position: [-1.0, 1.0, 0.0], uv: [0.0, 0.0] },
|
Vertex { position: [-1.0, 1.0, 0.0], uv: [0.0, 0.0] },
|
||||||
@@ -35,7 +38,9 @@ pub struct App {
|
|||||||
// Texture
|
// Texture
|
||||||
bind_group: wgpu::BindGroup,
|
bind_group: wgpu::BindGroup,
|
||||||
// Camera
|
// Camera
|
||||||
camera: Camera
|
camera: Camera,
|
||||||
|
camera_controller: CameraController,
|
||||||
|
uniforms: Uniforms
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -46,7 +51,7 @@ impl App {
|
|||||||
format: adapter.get_swap_chain_preferred_format(&surface),
|
format: adapter.get_swap_chain_preferred_format(&surface),
|
||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
present_mode: wgpu::PresentMode::Mailbox, // Fifo = Vsync
|
||||||
};
|
};
|
||||||
let swapchain = device.create_swap_chain(&surface, &swapchain_desc);
|
let swapchain = device.create_swap_chain(&surface, &swapchain_desc);
|
||||||
(swapchain_desc, swapchain)
|
(swapchain_desc, swapchain)
|
||||||
@@ -209,9 +214,10 @@ impl App {
|
|||||||
|
|
||||||
// Cam
|
// Cam
|
||||||
let aspect = swapchain_desc.width as f32 / swapchain_desc.height as f32;
|
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();
|
let mut uniforms = Uniforms::new();
|
||||||
uniforms.update_projection_matrix(&camera);
|
uniforms.update_projection_matrix(&camera);
|
||||||
|
let camera_controller = CameraController::new(2.0);
|
||||||
|
|
||||||
// Buffers
|
// Buffers
|
||||||
let vertex_buffer = Self::create_buffer(&device, wgpu::BufferUsage::VERTEX, bytemuck::cast_slice(VERTICES));
|
let vertex_buffer = Self::create_buffer(&device, wgpu::BufferUsage::VERTEX, bytemuck::cast_slice(VERTICES));
|
||||||
@@ -229,7 +235,7 @@ impl App {
|
|||||||
|
|
||||||
// Save values in app
|
// Save values in app
|
||||||
println!("Initialized");
|
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>>) {
|
pub fn resize(&mut self, new_size: Option<PhysicalSize<u32>>) {
|
||||||
@@ -239,20 +245,28 @@ impl App {
|
|||||||
// Recreate swapchain
|
// Recreate swapchain
|
||||||
self.swapchain_desc.width = size.width;
|
self.swapchain_desc.width = size.width;
|
||||||
self.swapchain_desc.height = size.height;
|
self.swapchain_desc.height = size.height;
|
||||||
|
// Update camera
|
||||||
|
self.camera.set_aspect(size.width as f32 / size.height as f32);
|
||||||
}
|
}
|
||||||
// Recreate swapchain
|
// Recreate swapchain
|
||||||
self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc);
|
self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, _event: &WindowEvent) -> bool {
|
pub fn input(&mut self, event: Arc<Event<()>>) -> bool {
|
||||||
false
|
self.camera_controller.handle_input(event.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self, delta_time: f32) {
|
||||||
// Nothing right now
|
// 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> {
|
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
|
||||||
|
|
||||||
// Get next frame to render to
|
// Get next frame to render to
|
||||||
let frame = self.swapchain.get_current_frame()?.output;
|
let frame = self.swapchain.get_current_frame()?.output;
|
||||||
// Create encoder that will build command buffer for us
|
// 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 {
|
pub struct Camera {
|
||||||
pos: Point3<f32>,
|
pub position: Point3<f32>,
|
||||||
target: Point3<f32>,
|
pub forward: Vector3<f32>,
|
||||||
up: Vector3<f32>,
|
pub up: Vector3<f32>,
|
||||||
aspect: f32,
|
aspect: f32,
|
||||||
fovy: f32,
|
fovy: f32,
|
||||||
znear: f32,
|
znear: f32,
|
||||||
@@ -20,10 +20,10 @@ pub struct Camera {
|
|||||||
|
|
||||||
impl 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 {
|
Self {
|
||||||
pos,
|
position,
|
||||||
target,
|
forward,
|
||||||
up: Vector3::unit_y(),
|
up: Vector3::unit_y(),
|
||||||
aspect,
|
aspect,
|
||||||
fovy: 45.0,
|
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> {
|
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);
|
let proj = cgmath::perspective(Deg(self.fovy), self.aspect, self.znear, self.zfar);
|
||||||
return OPENGL_TO_WGPU_MATRIX * proj * view;
|
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::{
|
use winit::{
|
||||||
event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode},
|
event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
@@ -10,6 +11,7 @@ mod texture;
|
|||||||
mod uniforms;
|
mod uniforms;
|
||||||
mod camera;
|
mod camera;
|
||||||
mod app;
|
mod app;
|
||||||
|
mod camera_controller;
|
||||||
use app::App;
|
use app::App;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -28,12 +30,20 @@ fn main() {
|
|||||||
|
|
||||||
let mut fps_timer = std::time::Instant::now();
|
let mut fps_timer = std::time::Instant::now();
|
||||||
let mut fps_counter = 0;
|
let mut fps_counter = 0;
|
||||||
|
let mut delta_timer = std::time::Instant::now();
|
||||||
|
|
||||||
// Run event loop
|
// Run event loop
|
||||||
events.run(move |e, _, c| {
|
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
|
// Window event
|
||||||
Event::WindowEvent { ref event, .. } => if !app.input(event) {
|
Event::WindowEvent { ref event, .. } => {
|
||||||
match event {
|
match event {
|
||||||
// Window closed
|
// Window closed
|
||||||
WindowEvent::CloseRequested => {
|
WindowEvent::CloseRequested => {
|
||||||
@@ -69,18 +79,20 @@ fn main() {
|
|||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
|
|
||||||
// Display FPS
|
// Display FPS
|
||||||
let elapsed = fps_timer.elapsed().as_millis();
|
let elapsed = fps_timer.elapsed().as_secs_f64();
|
||||||
if elapsed >= 1000 {
|
if elapsed >= 0.5 {
|
||||||
let elapsed_sec = (elapsed as f32) / 1000.0;
|
let fps = (fps_counter as f64) / elapsed;
|
||||||
let fps = (fps_counter as f32) / elapsed_sec;
|
println!("FPS: {}", (fps*100.0_f64).floor()/100.0);
|
||||||
println!("FPS: {}", fps);
|
|
||||||
fps_timer = std::time::Instant::now();
|
fps_timer = std::time::Instant::now();
|
||||||
fps_counter = 0;
|
fps_counter = 0;
|
||||||
}
|
}
|
||||||
fps_counter += 1;
|
fps_counter += 1;
|
||||||
|
|
||||||
// Update and Render
|
// Update and Render
|
||||||
app.update();
|
app.update(delta_timer.elapsed().as_secs_f32());
|
||||||
|
delta_timer = std::time::Instant::now();
|
||||||
|
|
||||||
|
// Render
|
||||||
match app.render() {
|
match app.render() {
|
||||||
Ok(_) => { }
|
Ok(_) => { }
|
||||||
// Recreate the swap_chain if lost
|
// Recreate the swap_chain if lost
|
||||||
|
|||||||
+2
-1
@@ -47,7 +47,8 @@ impl Texture {
|
|||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_w: 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,
|
min_filter: wgpu::FilterMode::Nearest,
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
Reference in New Issue
Block a user