diff options
author | HampusM <hampus@hampusmat.com> | 2023-10-25 21:15:41 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2023-10-25 21:16:10 +0200 |
commit | fd535654369b31e1283a609ba8e8fcf0df42100b (patch) | |
tree | 2509bd71d835a4389ff7578dc6314d6019e31d01 /engine | |
parent | 0c0dc186b542bf6bdd7645ba091dc2a47a03fa97 (diff) |
feat(engine): make camera look at a target position
Diffstat (limited to 'engine')
-rw-r--r-- | engine/src/camera.rs | 47 | ||||
-rw-r--r-- | engine/src/matrix.rs | 35 | ||||
-rw-r--r-- | engine/src/renderer/mod.rs | 2 | ||||
-rw-r--r-- | engine/src/vector.rs | 97 |
4 files changed, 168 insertions, 13 deletions
diff --git a/engine/src/camera.rs b/engine/src/camera.rs index b98f3f4..1546960 100644 --- a/engine/src/camera.rs +++ b/engine/src/camera.rs @@ -1,34 +1,57 @@ -use crate::transform::Transform; +use crate::matrix::Matrix; use crate::vector::Vec3; #[derive(Debug)] pub struct Camera { - transform: Transform, + position: Vec3<f32>, + target: Vec3<f32>, } impl Camera { - pub fn translate(&mut self, translation: Vec3<f32>) + pub fn set_position(&mut self, position: Vec3<f32>) { - self.transform.set_translation(translation); + self.position = position; } - pub(crate) fn new() -> Self + #[must_use] + pub fn position(&self) -> &Vec3<f32> + { + &self.position + } + + pub fn set_target(&mut self, target: Vec3<f32>) + { + self.target = target; + } + + #[must_use] + pub fn target(&self) -> &Vec3<f32> { - let mut transform = Transform::new(); + &self.target + } - transform.set_translation(Vec3 { + pub(crate) fn new() -> Self + { + let position = Vec3 { x: 0.0, y: 0.0, - z: -3.0, - }); + z: 3.0, + }; - Self { transform } + Self { + position, + target: Vec3::default(), + } } - pub(crate) fn transform(&self) -> &Transform + pub(crate) fn as_matrix(&self) -> Matrix<f32, 4, 4> { - &self.transform + let mut matrix = Matrix::new(); + + matrix.look_at(&self.position, &self.target, &Vec3::UP); + + matrix } } diff --git a/engine/src/matrix.rs b/engine/src/matrix.rs index c060b59..85a3721 100644 --- a/engine/src/matrix.rs +++ b/engine/src/matrix.rs @@ -71,4 +71,39 @@ impl Matrix<f32, 4, 4> self.set_cell(2, 2, scaling.z); self.set_cell(3, 3, 1.0); } + + pub fn look_at(&mut self, eye: &Vec3<f32>, target: &Vec3<f32>, up: &Vec3<f32>) + { + let rev_target_direction = (eye - target).normalize(); + + let camera_right = up.cross(&rev_target_direction).normalize(); + + let camera_up = rev_target_direction.cross(&camera_right); + + self.set_cell(0, 0, camera_right.x); + self.set_cell(0, 1, camera_right.y); + self.set_cell(0, 2, camera_right.z); + + self.set_cell(1, 0, camera_up.x); + self.set_cell(1, 1, camera_up.y); + self.set_cell(1, 2, camera_up.z); + + self.set_cell(2, 0, rev_target_direction.x); + self.set_cell(2, 1, rev_target_direction.y); + self.set_cell(2, 2, rev_target_direction.z); + + // The vector is negated since we want the world to be translated in the opposite + // direction of where we want the camera to move. + let camera_pos = -Vec3 { + x: camera_right.dot(eye), + y: camera_up.dot(eye), + z: rev_target_direction.dot(eye), + }; + + self.set_cell(0, 3, camera_pos.x); + self.set_cell(1, 3, camera_pos.y); + self.set_cell(2, 3, camera_pos.z); + + self.set_cell(3, 3, 1.0); + } } diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs index 4dcc075..b9494b6 100644 --- a/engine/src/renderer/mod.rs +++ b/engine/src/renderer/mod.rs @@ -221,7 +221,7 @@ fn apply_transformation_matrices( .shader_program .set_uniform_matrix_4fv(cstr!("model"), &object.transform().as_matrix()); - let view = camera.transform().as_matrix(); + let view = camera.as_matrix(); object .renderable() diff --git a/engine/src/vector.rs b/engine/src/vector.rs index c25a258..88a8198 100644 --- a/engine/src/vector.rs +++ b/engine/src/vector.rs @@ -1,3 +1,5 @@ +use std::ops::{Neg, Sub}; + #[derive(Debug)] pub struct Vec2<Value> { @@ -18,3 +20,98 @@ pub struct Vec3<Value> pub y: Value, pub z: Value, } + +impl Vec3<f32> +{ + pub const UP: Self = Self { + x: 0.0, + y: 1.0, + z: 0.0, + }; + + /// Returns the length of the vector. + #[must_use] + pub fn length(&self) -> f32 + { + (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt() + } + + /// Normalizes the vector, returning a unit vector. + #[must_use] + pub fn normalize(&self) -> Self + { + let length = self.length(); + + Self { + x: self.x / length, + y: self.y / length, + z: self.z / length, + } + } + + /// Returns the cross product of this and another vector. + #[must_use] + pub fn cross(&self, rhs: &Self) -> Self + { + Self { + x: (self.y * rhs.z) - (self.z * rhs.y), + y: (self.z * rhs.x) - (self.x * rhs.z), + z: (self.x * rhs.y) - (self.y * rhs.x), + } + } + + /// Returns the dot product of this and another vector. + #[must_use] + pub fn dot(&self, rhs: &Self) -> f32 + { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } +} + +impl<Value> Sub for Vec3<Value> +where + Value: Sub<Value, Output = Value>, +{ + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output + { + Self::Output { + x: self.x - rhs.x, + y: self.y - rhs.y, + z: self.z - rhs.z, + } + } +} + +impl<Value> Sub for &Vec3<Value> +where + for<'a, 'b> &'a Value: Sub<&'b Value, Output = Value>, +{ + type Output = Vec3<Value>; + + fn sub(self, rhs: Self) -> Self::Output + { + Self::Output { + x: &self.x - &rhs.x, + y: &self.y - &rhs.y, + z: &self.z - &rhs.z, + } + } +} + +impl<Value> Neg for Vec3<Value> +where + Value: Neg<Output = Value>, +{ + type Output = Self; + + fn neg(mut self) -> Self::Output + { + self.x = -self.x; + self.y = -self.y; + self.z = -self.z; + + self + } +} |