We mousing

This commit is contained in:
Sijmen 2021-05-28 23:21:20 +02:00
parent dc5ed8eb9a
commit eee0287d7f
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
4 changed files with 214 additions and 63 deletions

View file

@ -1,3 +1,5 @@
use cgmath::InnerSpace;
#[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
1.0, 0.0, 0.0, 0.0,
@ -7,19 +9,63 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
);
pub struct Camera {
pub eye: cgmath::Point3<f32>,
pub target: cgmath::Point3<f32>,
pub up: cgmath::Vector3<f32>,
pub aspect: f32,
pub fovy: f32,
pub znear: f32,
pub zfar: f32,
pub position: cgmath::Point3<f32>,
pub yaw: cgmath::Rad<f32>,
pub pitch: cgmath::Rad<f32>,
}
impl Camera {
pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4<f32> {
let view = cgmath::Matrix4::look_at_rh(self.eye, self.target, self.up);
let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
OPENGL_TO_WGPU_MATRIX * proj * view
pub fn new(
position: cgmath::Point3<f32>,
yaw: cgmath::Rad<f32>,
pitch: cgmath::Rad<f32>,
) -> Self {
Self {
position,
yaw,
pitch,
}
}
pub fn calculate_matrix(&self) -> cgmath::Matrix4<f32> {
cgmath::Matrix4::look_to_rh(
self.position,
cgmath::Vector3::new(self.yaw.0.cos(), self.pitch.0.sin(), self.yaw.0.sin())
.normalize(),
cgmath::Vector3::unit_y(),
)
}
}
pub struct Projection {
pub aspect_ratio: f32,
pub fov_y: cgmath::Rad<f32>,
pub z_near: f32,
pub z_far: f32,
}
impl Projection {
pub fn new<Fov: Into<cgmath::Rad<f32>>>(
width: u32,
height: u32,
fov_y: Fov,
z_near: f32,
z_far: f32,
) -> Self {
Self {
aspect_ratio: width as f32 / height as f32,
fov_y: fov_y.into(),
z_near,
z_far,
}
}
pub fn resize(&mut self, width: u32, height: u32) {
self.aspect_ratio = width as f32 / height as f32;
}
pub fn calculate_matrix(&self) -> cgmath::Matrix4<f32> {
OPENGL_TO_WGPU_MATRIX
* cgmath::perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far)
}
}

View file

@ -10,7 +10,7 @@ mod vertex;
use std::time::Instant;
use winit::{
dpi::{PhysicalSize, Size},
event::{Event, WindowEvent},
event::{ElementState, Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -37,26 +37,48 @@ fn main() {
let mut frames = 0;
let mut instant = Instant::now();
let mut last_render_time = Instant::now();
event_loop.run(move |event, _, control_flow| {
match event {
Event::DeviceEvent { ref event, .. } => state.input(event),
Event::WindowEvent {
ref event,
window_id,
} if window_id == window.id() => {
if !state.input(event) {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
} if window_id == window.id() => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => {
let _ = window.set_cursor_grab(false);
window.set_cursor_visible(true);
state.mouse_grabbed = false;
}
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
state.resize(**new_inner_size);
}
WindowEvent::MouseInput {
state: mouse_state,
button,
..
} => {
if *button == MouseButton::Left && *mouse_state == ElementState::Pressed {
let _ = window.set_cursor_grab(true);
window.set_cursor_visible(false);
state.mouse_grabbed = true;
}
}
}
_ => {}
},
Event::RedrawRequested(_) => {
frames += 1;
if frames % 1000 == 0 {
@ -66,7 +88,11 @@ fn main() {
instant = Instant::now();
}
state.update();
let now = Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Recreate the swap_chain if lost

View file

@ -1,9 +1,14 @@
use cgmath::Rotation3;
use std::time::Duration;
use cgmath::{InnerSpace, Rotation3};
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use winit::{event::WindowEvent, window::Window};
use winit::{
event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode},
window::Window,
};
use crate::{
camera::Camera,
camera::{Camera, Projection},
cube,
instance::{Instance, InstanceRaw},
light::Light,
@ -29,9 +34,16 @@ pub struct State {
instances: Vec<Instance>,
instance_buffer: wgpu::Buffer,
depth_texture: Texture,
light: Light,
light_buffer: wgpu::Buffer,
_light: Light,
_light_buffer: wgpu::Buffer,
light_bind_group: wgpu::BindGroup,
right_speed: f32,
forward_speed: f32,
camera: Camera,
uniforms: Uniforms,
projection: Projection,
uniform_buffer: wgpu::Buffer,
pub mouse_grabbed: bool,
}
impl State {
@ -205,24 +217,36 @@ impl State {
(texture_bind_group_layout, texture_bind_group)
}
fn create_camera(swap_chain_descriptor: &wgpu::SwapChainDescriptor) -> Camera {
Camera {
eye: (0.0, 5.0, 10.0).into(), // position the camera one unit up and 2 units back
target: (0.0, 0.0, 0.0).into(), // have it look at the origin
up: cgmath::Vector3::unit_y(),
aspect: swap_chain_descriptor.width as f32 / swap_chain_descriptor.height as f32,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
}
fn create_camera(swap_chain_descriptor: &wgpu::SwapChainDescriptor) -> (Camera, Projection) {
let camera = Camera::new(
(0.0, 5.0, 10.0).into(),
cgmath::Deg(-90.0).into(),
cgmath::Deg(-20.0).into(),
);
let projection = Projection::new(
swap_chain_descriptor.width,
swap_chain_descriptor.height,
cgmath::Deg(45.0),
0.1,
100.0,
);
(camera, projection)
}
fn create_uniforms(
camera: &Camera,
projection: &Projection,
render_device: &wgpu::Device,
) -> (wgpu::BindGroupLayout, wgpu::BindGroup) {
) -> (
Uniforms,
wgpu::Buffer,
wgpu::BindGroupLayout,
wgpu::BindGroup,
) {
let mut uniforms = Uniforms::new();
uniforms.update_view_proj(camera);
uniforms.update_view_projection(camera, projection);
let uniform_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("uniform_buffer"),
@ -254,7 +278,12 @@ impl State {
label: Some("uniform_bind_group"),
});
(uniform_bind_group_layout, uniform_bind_group)
(
uniforms,
uniform_buffer,
uniform_bind_group_layout,
uniform_bind_group,
)
}
fn create_light(
@ -345,9 +374,10 @@ impl State {
let (texture_layout, texture_bind_group) = Self::create_textures(&render_device, &queue);
let camera = Self::create_camera(&swap_chain_descriptor);
let (camera, projection) = Self::create_camera(&swap_chain_descriptor);
let (uniform_layout, uniform_bind_group) = Self::create_uniforms(&camera, &render_device);
let (uniforms, uniform_buffer, uniform_layout, uniform_bind_group) =
Self::create_uniforms(&camera, &projection, &render_device);
let (light, light_buffer, light_layout, light_bind_group) =
Self::create_light(&render_device);
@ -382,14 +412,22 @@ impl State {
render_pipeline,
vertex_buffer,
index_buffer,
uniforms,
uniform_buffer,
uniform_bind_group,
texture_bind_group,
camera,
projection,
instances,
instance_buffer,
depth_texture,
light,
light_buffer,
_light: light,
_light_buffer: light_buffer,
light_bind_group,
mouse_grabbed: false,
right_speed: 0.0,
forward_speed: 0.0,
}
}
@ -399,6 +437,8 @@ impl State {
self.swap_chain_descriptor.width = new_size.width;
self.swap_chain_descriptor.height = new_size.height;
self.projection.resize(new_size.width, new_size.height);
self.depth_texture = Texture::create_depth_texture(
&self.render_device,
&self.swap_chain_descriptor,
@ -410,19 +450,58 @@ impl State {
.create_swap_chain(&self.render_surface, &self.swap_chain_descriptor);
}
#[allow(unused_variables)]
pub fn input(&mut self, event: &WindowEvent) -> bool {
false
fn input_keyboard(&mut self, key_code: &VirtualKeyCode, state: &ElementState) {
let amount = if state == &ElementState::Pressed {
1.0
} else {
-1.0
};
match key_code {
VirtualKeyCode::W => self.forward_speed += amount,
VirtualKeyCode::S => self.forward_speed -= amount,
VirtualKeyCode::A => self.right_speed -= amount,
VirtualKeyCode::D => self.right_speed += amount,
_ => (),
}
}
pub fn update(&mut self) {
let old_position: cgmath::Vector3<_> = self.light.position.into();
self.light.position =
(cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0))
* old_position)
.into();
self.queue
.write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light]));
fn input_mouse(&mut self, dx: f64, dy: f64) {
if self.mouse_grabbed {
self.camera.yaw += cgmath::Rad(dx as f32 * 0.005);
self.camera.pitch -= cgmath::Rad(dy as f32 * 0.005);
}
}
pub fn input(&mut self, event: &DeviceEvent) {
match event {
DeviceEvent::Key(KeyboardInput {
virtual_keycode: Some(key),
state,
..
}) => self.input_keyboard(key, state),
DeviceEvent::MouseMotion { delta: (dx, dy) } => self.input_mouse(*dx, *dy),
_ => (),
}
}
pub fn update(&mut self, dt: Duration) {
let dt_secs = dt.as_secs_f32();
// Move forward/backward and left/right
let (yaw_sin, yaw_cos) = self.camera.yaw.0.sin_cos();
let forward = cgmath::Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
let right = cgmath::Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
self.camera.position += forward * self.forward_speed * 6.0 * dt_secs;
self.camera.position += right * self.right_speed * 6.0 * dt_secs;
self.uniforms
.update_view_projection(&self.camera, &self.projection);
self.queue.write_buffer(
&self.uniform_buffer,
0,
bytemuck::cast_slice(&[self.uniforms]),
);
}
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {

View file

@ -1,6 +1,6 @@
use cgmath::SquareMatrix;
use crate::camera::Camera;
use crate::camera::{Camera, Projection};
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
@ -17,8 +17,8 @@ impl Uniforms {
}
}
pub fn update_view_proj(&mut self, camera: &Camera) {
self.view_position = camera.eye.to_homogeneous().into();
self.view_projection = camera.build_view_projection_matrix().into();
pub fn update_view_projection(&mut self, camera: &Camera, projection: &Projection) {
self.view_position = camera.position.to_homogeneous().into();
self.view_projection = (projection.calculate_matrix() * camera.calculate_matrix()).into();
}
}