Add simple camera movement
This commit is contained in:
26
src/camera.rs
Normal file
26
src/camera.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#[rustfmt::skip]
|
||||
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.5, 0.0,
|
||||
0.0, 0.0, 0.5, 1.0,
|
||||
);
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
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 projection =
|
||||
cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
|
||||
return OPENGL_TO_WGPU_MATRIX * projection * view;
|
||||
}
|
||||
}
|
||||
96
src/camera_controller.rs
Normal file
96
src/camera_controller.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use winit::event::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IsPressed(bool);
|
||||
|
||||
impl From<bool> for IsPressed {
|
||||
fn from(item: bool) -> Self {
|
||||
IsPressed(item)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ButtonPress {
|
||||
Up(IsPressed),
|
||||
Down(IsPressed),
|
||||
Left(IsPressed),
|
||||
Right(IsPressed),
|
||||
Forward(IsPressed),
|
||||
Backward(IsPressed),
|
||||
}
|
||||
|
||||
pub struct CameraController {
|
||||
speed: f32,
|
||||
button_press: Option<ButtonPress>,
|
||||
}
|
||||
|
||||
impl CameraController {
|
||||
pub fn new(speed: f32) -> Self {
|
||||
Self {
|
||||
speed,
|
||||
button_press: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_events(&mut self, event: &WindowEvent) -> bool {
|
||||
match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
state,
|
||||
virtual_keycode: Some(key),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
let pressed = (*state == ElementState::Pressed).into();
|
||||
match key {
|
||||
VirtualKeyCode::W => {
|
||||
self.button_press = Some(ButtonPress::Forward(pressed));
|
||||
true
|
||||
}
|
||||
VirtualKeyCode::A => {
|
||||
self.button_press = Some(ButtonPress::Left(pressed));
|
||||
true
|
||||
}
|
||||
VirtualKeyCode::S => {
|
||||
self.button_press = Some(ButtonPress::Backward(pressed));
|
||||
true
|
||||
}
|
||||
VirtualKeyCode::D => {
|
||||
self.button_press = Some(ButtonPress::Right(pressed));
|
||||
true
|
||||
}
|
||||
VirtualKeyCode::Space => {
|
||||
self.button_press = Some(ButtonPress::Up(pressed));
|
||||
true
|
||||
}
|
||||
VirtualKeyCode::LShift => {
|
||||
self.button_press = Some(ButtonPress::Down(pressed));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_camera(&self, camera: &mut crate::camera::Camera) {
|
||||
use cgmath::InnerSpace;
|
||||
let forward = camera.target - camera.eye;
|
||||
let forward_norm = forward.normalize();
|
||||
let forward_mag = forward.magnitude();
|
||||
|
||||
match self.button_press {
|
||||
Some(ButtonPress::Forward(IsPressed(true))) if forward_mag > self.speed => {
|
||||
camera.eye += forward_norm * self.speed;
|
||||
}
|
||||
Some(ButtonPress::Backward(IsPressed(true))) => {
|
||||
camera.eye -= forward_norm * self.speed;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// TODO add rest of the movement
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ use winit::{
|
||||
mod state;
|
||||
mod vertex;
|
||||
mod texture;
|
||||
mod camera;
|
||||
mod uniform;
|
||||
mod camera_controller;
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
// Vertex shader
|
||||
[[block]]
|
||||
struct Uniform {
|
||||
view_projection: mat4x4<f32>;
|
||||
};
|
||||
|
||||
[[group(1), binding(0)]]
|
||||
var<uniform> uniform: Uniform;
|
||||
|
||||
struct VertexInput {
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(1)]] texture_coords: vec2<f32>;
|
||||
@@ -12,7 +20,7 @@ struct VertexOutput {
|
||||
[[stage(vertex)]]
|
||||
fn main(model: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.clip_coordinate = vec4<f32>(model.position, 1.0);
|
||||
out.clip_coordinate = uniform.view_projection * vec4<f32>(model.position, 1.0);
|
||||
out.texture_coords = model.texture_coords;
|
||||
return out;
|
||||
}
|
||||
|
||||
98
src/state.rs
98
src/state.rs
@@ -7,8 +7,6 @@ use winit::{
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use crate::{texture, vertex::Vertex};
|
||||
|
||||
/// Hold state with important information
|
||||
pub struct State {
|
||||
surface: wgpu::Surface,
|
||||
@@ -19,7 +17,6 @@ pub struct State {
|
||||
swap_chain: wgpu::SwapChain,
|
||||
pub size: winit::dpi::PhysicalSize<u32>,
|
||||
|
||||
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
|
||||
vertex_buffer: wgpu::Buffer,
|
||||
@@ -27,7 +24,14 @@ pub struct State {
|
||||
num_indices: u32,
|
||||
|
||||
aqua_bind_group: wgpu::BindGroup,
|
||||
aqua_texture: texture::Texture,
|
||||
aqua_texture: crate::texture::Texture,
|
||||
|
||||
camera: crate::camera::Camera,
|
||||
camera_controller: crate::camera_controller::CameraController,
|
||||
|
||||
uniform: crate::uniform::Uniform,
|
||||
uniform_buffer: wgpu::Buffer,
|
||||
uniform_bind_group: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@@ -79,7 +83,7 @@ impl State {
|
||||
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||
|
||||
let aqua_bytes = include_bytes!("../img/aqua.png");
|
||||
let aqua_texture = texture::Texture::from_bytes(&device, &queue, aqua_bytes, "aqua").unwrap();
|
||||
let aqua_texture = crate::texture::Texture::from_bytes(&device, &queue, aqua_bytes, "aqua").unwrap();
|
||||
|
||||
let texture_bind_group_layout = device.create_bind_group_layout(
|
||||
&wgpu::BindGroupLayoutDescriptor {
|
||||
@@ -127,6 +131,61 @@ impl State {
|
||||
}
|
||||
);
|
||||
|
||||
let camera = crate::camera::Camera {
|
||||
// x, y, z
|
||||
// 1 up, 2 back
|
||||
// +z is out of the screen
|
||||
eye: (0.0, 1.0, 2.0).into(),
|
||||
// look at the center
|
||||
target: (0.0, 0.0, 0.0).into(),
|
||||
// which way is up
|
||||
up: cgmath::Vector3::unit_y(),
|
||||
aspect: size.width as f32 / size.height as f32,
|
||||
fovy: 45.0,
|
||||
znear: 0.1,
|
||||
zfar: 100.0,
|
||||
};
|
||||
|
||||
let camera_controller = crate::camera_controller::CameraController::new(0.05);
|
||||
|
||||
let mut uniform = crate::uniform::Uniform::new();
|
||||
uniform.update_view_proj(&camera);
|
||||
|
||||
let uniform_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Uniform Buffer"),
|
||||
contents: bytemuck::cast_slice(&[uniform]),
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
}
|
||||
);
|
||||
|
||||
let uniform_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}
|
||||
],
|
||||
label: Some("uniform_bind_group_layout"),
|
||||
});
|
||||
|
||||
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &uniform_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform_buffer.as_entire_binding(),
|
||||
}
|
||||
],
|
||||
label: Some("uniform_bind_group"),
|
||||
});
|
||||
|
||||
// load shader file
|
||||
let shader = device.create_shader_module(
|
||||
&wgpu::ShaderModuleDescriptor {
|
||||
@@ -139,7 +198,10 @@ impl State {
|
||||
let render_pipeline_layout = device.create_pipeline_layout(
|
||||
&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layput"),
|
||||
bind_group_layouts: &[&texture_bind_group_layout],
|
||||
bind_group_layouts: &[
|
||||
&texture_bind_group_layout,
|
||||
&uniform_bind_group_layout,
|
||||
],
|
||||
push_constant_ranges: &[],
|
||||
}
|
||||
);
|
||||
@@ -154,7 +216,7 @@ impl State {
|
||||
// function name in shader.wgsl for [[stage(vertex)]]
|
||||
entry_point: "main",
|
||||
// specify memory layout
|
||||
buffers: &[Vertex::desc()],
|
||||
buffers: &[crate::vertex::Vertex::desc()],
|
||||
|
||||
},
|
||||
// needed to sotre color data to swap_chain
|
||||
@@ -212,15 +274,26 @@ impl State {
|
||||
surface,
|
||||
device,
|
||||
queue,
|
||||
|
||||
sc_desc, // saved, so we can create a new swap_chain later
|
||||
swap_chain,
|
||||
size,
|
||||
|
||||
render_pipeline,
|
||||
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_indices,
|
||||
|
||||
aqua_bind_group,
|
||||
aqua_texture,
|
||||
|
||||
camera,
|
||||
camera_controller,
|
||||
|
||||
uniform,
|
||||
uniform_buffer,
|
||||
uniform_bind_group,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,12 +327,18 @@ impl State {
|
||||
// self.use_pentagon = !self.use_pentagon;
|
||||
// true
|
||||
// }
|
||||
_ => false
|
||||
_ => self.camera_controller.process_events(event)
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Update State before render()
|
||||
pub fn update(&mut self) {
|
||||
// reposition camera
|
||||
self.camera_controller.update_camera(&mut self.camera);
|
||||
// update projection for uniform buffer
|
||||
self.uniform.update_view_proj(&self.camera);
|
||||
// write uniform buffer to queue
|
||||
self.queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[self.uniform]));
|
||||
}
|
||||
|
||||
/// Generate commands for gpu to render to frame
|
||||
@@ -296,6 +375,7 @@ impl State {
|
||||
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||
render_pass.set_bind_group(0, &self.aqua_bind_group, &[]);
|
||||
render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
|
||||
// draw triangle
|
||||
render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
|
||||
//render_pass.draw(0..self.num_vertices, 0..1);
|
||||
|
||||
18
src/uniform.rs
Normal file
18
src/uniform.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Uniform {
|
||||
view_projection: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
impl Uniform {
|
||||
pub fn new() -> Self {
|
||||
use cgmath::SquareMatrix;
|
||||
Self {
|
||||
view_projection: cgmath::Matrix4::identity().into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_view_proj(&mut self, camera: &crate::camera::Camera) {
|
||||
self.view_projection = camera.build_view_projection_matrix().into();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user