make camera follow player

This commit is contained in:
aiden 2023-05-22 17:18:35 +01:00
parent fb86f3a038
commit 56c05ccfdf
Signed by: aiden
GPG Key ID: EFA9C74AEBF806E0
3 changed files with 66 additions and 48 deletions

@ -1,11 +1,12 @@
use cgmath::{Vector3, Point3, InnerSpace, Deg, Rad};
use cgmath::{Vector3, Point3, InnerSpace, Deg, Rad, Matrix4};
use crate::input::Input;
use crate::{input::Input, player::Player};
#[derive(Debug)]
pub struct Camera {
pub position: Point3<f32>,
pub rot_x: Deg<f32>,
pub target: Point3<f32>,
pub rot_y: Deg<f32>,
aspect: f32,
@ -14,6 +15,10 @@ pub struct Camera {
zfar: f32,
}
fn pitch_clamp(pitch: f32) -> Deg<f32> {
const PITCH_LIM: f32 = 90.0 - 0.0001;
return Deg(pitch.clamp(-PITCH_LIM, PITCH_LIM));
}
impl Camera {
pub fn new<
V: Into<Point3<f32>>,
@ -21,63 +26,50 @@ impl Camera {
dimensions: winit::dpi::PhysicalSize<u32>,
position: V,
rot_x: Deg<f32>,
rot_y: Deg<f32>
rot_y: Deg<f32>,
) -> Self {
return Self {
position: position.into(),
rot_x: rot_x,
rot_y: rot_y,
target: (0.0, 0.0, 0.0).into(),
rot_y: pitch_clamp(rot_y.0),
aspect: dimensions.width as f32 / dimensions.height as f32,
fovy: Deg(45.0),
fovy: Deg(40.0),
znear: 0.1,
zfar: 100.0,
};
}
}
impl Camera {
pub fn reconfigure(&mut self, dimensions: winit::dpi::PhysicalSize<u32>) {
self.aspect = dimensions.width as f32 / dimensions.height as f32;
return;
}
pub fn update_pos(&mut self, input: &Input, dt: f32) {
let (yaw_sin, yaw_cos) = Rad::from(self.rot_x).0.sin_cos();
let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
self.position += forward * (input.amount_forward - input.amount_backward) * (input.speed * dt);
self.position += right * (input.amount_right - input.amount_left) * (input.speed * dt);
pub fn update_pos(&mut self, player: &Player) {
self.target = player.position;
self.position.y += (input.amount_up - input.amount_down) * (input.speed * dt);
let (sin_yaw, cos_yaw) = Rad::from(player.rot_x).0.sin_cos();
let (sin_pitch, cos_pitch) = Rad::from(self.rot_y).0.sin_cos();
let v = Vector3::new(
cos_pitch * cos_yaw,
sin_pitch,
cos_pitch * sin_yaw
).normalize();
self.position = self.target - v;
return;
}
pub fn update_rot(&mut self, input: &Input, sf: f32) {
// doesn't need dt because the input is not continuous.
let (dx, dy) = input.mouse_moved;
let (_, dy) = input.mouse_moved;
self.rot_x += Deg((dx / input.dots_per_deg) * sf);
let pitch_lim = 90.0 - 0.0001;
let pitch = self.rot_y.0 + ((-dy / input.dots_per_deg) * sf);
self.rot_y = Deg(pitch.clamp(-pitch_lim, pitch_lim));
self.rot_y = pitch_clamp(self.rot_y.0 + ((-dy / input.dots_per_deg) * sf));
return;
}
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);
}
}
pub struct CameraUniform {
@ -105,16 +97,15 @@ impl<'a> CameraUniform {
};
}
pub fn set_view_projection_matrix(&self, queue: &wgpu::Queue, camera: &Camera) {
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();
/*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();
let target = Vector3::new(
cos_pitch * cos_yaw,
sin_pitch,
cos_pitch * sin_yaw
).normalize();
).normalize();*/
let view = cgmath::Matrix4::look_to_rh(camera.position, target, Vector3::unit_y());
let view = Matrix4::look_to_rh(camera.position, camera.target - camera.position, 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)));

@ -1,7 +1,30 @@
use cgmath::{Point3, Deg};
use cgmath::{Point3, Deg, Vector3, Rad, InnerSpace};
use crate::input::Input;
pub struct Player {
pub position: Point3<f32>,
pub rot_x: Deg<f32>,
pub buffer: wgpu::Buffer,
}
impl Player {
pub fn update_pos(&mut self, input: &Input, dt: f32) {
let (sin, cos) = Rad::from(self.rot_x).0.sin_cos();
let forward = Vector3::new(cos, 0.0, sin).normalize();
let right = Vector3::new(-sin, 0.0, cos).normalize();
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);
return;
}
pub fn update_rot(&mut self, input: &Input, sf: f32) {
// doesn't need dt because the input is not continuous.
let (dx, _) = input.mouse_moved;
self.rot_x += Deg((dx / input.dots_per_deg) * sf);
return;
}
}

@ -1,4 +1,4 @@
use cgmath::{Deg, Vector3, Matrix3, Quaternion, Rad, Point3, EuclideanSpace};
use cgmath::{Deg, Rad, Point3, EuclideanSpace};
use winit::window::Window;
use wgpu::{util::DeviceExt, BufferAddress};
@ -128,7 +128,7 @@ impl State {
mapped_at_creation: false,
}));
let camera = Camera::new(size, (0.25, 1.0, 0.0), Deg(0.0), Deg(-90.0));
let camera = Camera::new(size, (0.25, 1.0, 0.0), Deg(-90.0));
let camera_bind_group_layout = &(device.create_bind_group_layout(&(wgpu::BindGroupLayoutDescriptor {
entries: &[
@ -217,7 +217,8 @@ impl State {
}));
let player = Player {
position: (0.0, 0.0, 0.0).into(),
position: (1.0, 0.0, -1.0).into(),
rot_x: Deg(0.0),
buffer: device.create_buffer(&(wgpu::BufferDescriptor {
label: Some("player_buffer"),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
@ -396,7 +397,7 @@ impl State {
vertices[0],
];
}
// render the player in-front of the camera
// (USED TO) render the player in-front of the camera
// this should really be done the other way
// around though; the camera should be placed
// *behind the player*, and the camera should
@ -405,9 +406,9 @@ impl State {
// (the camera should rotate around the player,
// and the player should also rotate so that
// its back is facing the camera.)
self.queue.write_buffer(&(&self.player.buffer), 0, bytemuck::cast_slice(&(rot_rect(
0.1, 0.2, Rad::from(self.camera.rot_x)
).map(|point| Vertex { position: (self.camera.position(1.0) + point.to_vec()).into(), color: [1.0, 1.0, 1.0] }))));
self.queue.write_buffer(&(self.player.buffer), 0, bytemuck::cast_slice(&(rot_rect(
0.1, 0.2, Rad::from(self.player.rot_x)
).map(|point| Vertex { position: (self.player.position + point.to_vec()).into(), color: [1.0, 1.0, 1.0] }))));
render_pass.set_vertex_buffer(0, self.player.buffer.slice(..));
render_pass.draw(0..6, 0..1);
@ -441,8 +442,11 @@ impl State {
}
pub fn update_camera(&mut self, dt: f32, sf: f32) {
self.camera.update_pos(&(self.input), dt);
self.player.update_pos(&(self.input), dt);
self.player.update_rot(&(self.input), sf);
self.camera.update_rot(&(self.input), sf);
self.camera.update_pos(&(self.player));
return;
}
pub fn process_key(&mut self, key: winit::event::VirtualKeyCode, state: winit::event::ElementState) {