We mousing
This commit is contained in:
parent
dc5ed8eb9a
commit
eee0287d7f
4 changed files with 214 additions and 63 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
56
src/main.rs
56
src/main.rs
|
@ -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
|
||||
|
|
145
src/state.rs
145
src/state.rs
|
@ -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> {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue