2023-05-15 08:28:40 +00:00
|
|
|
use cgmath::{Vector3, Point3, InnerSpace, Deg, Rad};
|
2023-05-13 09:41:36 +00:00
|
|
|
|
2023-05-16 09:58:36 +00:00
|
|
|
use crate::input::Input;
|
2023-05-13 09:41:36 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Camera {
|
|
|
|
pub position: Point3<f32>,
|
2023-05-15 08:28:40 +00:00
|
|
|
pub rot_x: Deg<f32>,
|
|
|
|
pub rot_y: Deg<f32>,
|
2023-05-13 09:41:36 +00:00
|
|
|
|
|
|
|
aspect: f32,
|
2023-05-15 08:28:40 +00:00
|
|
|
fovy: Deg<f32>,
|
2023-05-13 09:41:36 +00:00
|
|
|
znear: f32,
|
|
|
|
zfar: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Camera {
|
|
|
|
pub fn new<
|
|
|
|
V: Into<Point3<f32>>,
|
|
|
|
>(
|
|
|
|
dimensions: winit::dpi::PhysicalSize<u32>,
|
|
|
|
|
|
|
|
position: V,
|
2023-05-15 13:45:55 +00:00
|
|
|
rot_x: Deg<f32>,
|
|
|
|
rot_y: Deg<f32>
|
2023-05-13 09:41:36 +00:00
|
|
|
) -> Self {
|
2023-05-16 10:07:08 +00:00
|
|
|
return Self {
|
2023-05-13 09:41:36 +00:00
|
|
|
position: position.into(),
|
2023-05-15 13:45:55 +00:00
|
|
|
rot_x: rot_x,
|
|
|
|
rot_y: rot_y,
|
2023-05-13 09:41:36 +00:00
|
|
|
|
|
|
|
aspect: dimensions.width as f32 / dimensions.height as f32,
|
2023-05-15 08:28:40 +00:00
|
|
|
fovy: Deg(45.0),
|
2023-05-13 09:41:36 +00:00
|
|
|
znear: 0.1,
|
|
|
|
zfar: 100.0,
|
2023-05-16 10:07:08 +00:00
|
|
|
};
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Camera {
|
|
|
|
pub fn reconfigure(&mut self, dimensions: winit::dpi::PhysicalSize<u32>) {
|
|
|
|
self.aspect = dimensions.width as f32 / dimensions.height as f32;
|
2023-05-16 10:07:08 +00:00
|
|
|
return;
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
|
2023-05-15 19:21:01 +00:00
|
|
|
pub fn update_pos(&mut self, input: &Input, dt: f32) {
|
2023-05-15 08:28:40 +00:00
|
|
|
let (yaw_sin, yaw_cos) = Rad::from(self.rot_x).0.sin_cos();
|
2023-05-13 09:41:36 +00:00
|
|
|
let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
|
|
|
|
let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
|
2023-05-15 08:19:56 +00:00
|
|
|
self.position += forward * (input.amount_forward - input.amount_backward) * (input.speed * dt);
|
|
|
|
self.position += right * (input.amount_right - input.amount_left) * (input.speed * dt);
|
|
|
|
|
|
|
|
self.position.y += (input.amount_up - input.amount_down) * (input.speed * dt);
|
2023-05-16 10:07:08 +00:00
|
|
|
|
|
|
|
return;
|
2023-05-15 13:45:55 +00:00
|
|
|
}
|
2023-05-13 09:41:36 +00:00
|
|
|
|
2023-05-15 19:21:01 +00:00
|
|
|
pub fn update_rot(&mut self, input: &Input, sf: f32) {
|
2023-05-16 09:58:36 +00:00
|
|
|
// doesn't need dt because the input is not continuous.
|
2023-05-15 08:19:56 +00:00
|
|
|
let (dx, dy) = input.mouse_moved;
|
2023-05-13 09:41:36 +00:00
|
|
|
|
2023-05-15 19:21:01 +00:00
|
|
|
self.rot_x += Deg((dx / input.dots_per_deg) * sf);
|
2023-05-15 08:28:40 +00:00
|
|
|
let pitch_lim = 90.0 - 0.0001;
|
2023-05-15 19:21:01 +00:00
|
|
|
let pitch = self.rot_y.0 + ((-dy / input.dots_per_deg) * sf);
|
2023-05-15 08:28:40 +00:00
|
|
|
self.rot_y = Deg(pitch.clamp(-pitch_lim, pitch_lim));
|
2023-05-16 10:07:08 +00:00
|
|
|
|
|
|
|
return;
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
2023-05-20 17:33:25 +00:00
|
|
|
|
|
|
|
pub fn position(&self, t: f32) -> Point3<f32> {
|
|
|
|
let (sin_yaw, cos_yaw) = Rad::from(self.rot_x).0.sin_cos();
|
|
|
|
let (sin_pitch, cos_pitch) = Rad::from(self.rot_y).0.sin_cos();
|
|
|
|
|
|
|
|
let target = Vector3::new(
|
|
|
|
cos_pitch * cos_yaw,
|
|
|
|
sin_pitch,
|
|
|
|
cos_pitch * sin_yaw
|
|
|
|
).normalize();
|
|
|
|
return self.position + (target * t);
|
|
|
|
}
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CameraUniform {
|
|
|
|
buffer: wgpu::Buffer,
|
|
|
|
}
|
|
|
|
impl<'a> CameraUniform {
|
|
|
|
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,
|
|
|
|
);
|
|
|
|
const SIZE: usize = std::mem::size_of::<[[f32; 4]; 4]>();
|
|
|
|
|
|
|
|
pub fn new(device: &wgpu::Device) -> Self {
|
2023-05-16 10:07:08 +00:00
|
|
|
return Self {
|
2023-05-13 09:41:36 +00:00
|
|
|
buffer: device.create_buffer(
|
|
|
|
&(wgpu::BufferDescriptor {
|
|
|
|
label: Some("Camera Buffer"),
|
|
|
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
|
|
|
size: Self::SIZE as u64,
|
|
|
|
mapped_at_creation: false,
|
|
|
|
})
|
|
|
|
),
|
2023-05-16 10:07:08 +00:00
|
|
|
};
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
pub fn set_view_projection_matrix(&self, queue: &wgpu::Queue, camera: &Camera) {
|
2023-05-15 08:28:40 +00:00
|
|
|
let (sin_yaw, cos_yaw) = Rad::from(camera.rot_x).0.sin_cos();
|
|
|
|
let (sin_pitch, cos_pitch) = Rad::from(camera.rot_y).0.sin_cos();
|
2023-05-13 09:41:36 +00:00
|
|
|
|
|
|
|
let target = Vector3::new(
|
|
|
|
cos_pitch * cos_yaw,
|
|
|
|
sin_pitch,
|
|
|
|
cos_pitch * sin_yaw
|
|
|
|
).normalize();
|
|
|
|
|
|
|
|
let view = cgmath::Matrix4::look_to_rh(camera.position, target, Vector3::unit_y());
|
|
|
|
let proj = cgmath::perspective(camera.fovy, camera.aspect, camera.znear, camera.zfar);
|
|
|
|
let transformed_proj: [[f32; 4]; 4] = (Self::OPENGL_TO_WGPU_MATRIX * proj * view).into();
|
|
|
|
queue.write_buffer(&(self.buffer), 0, bytemuck::cast_slice(&(transformed_proj)));
|
2023-05-16 10:07:08 +00:00
|
|
|
|
|
|
|
return;
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
pub fn as_entire_binding(&self) -> wgpu::BindingResource {
|
2023-05-16 10:07:08 +00:00
|
|
|
return self.buffer.as_entire_binding();
|
2023-05-13 09:41:36 +00:00
|
|
|
}
|
|
|
|
}
|