summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-10-25 21:15:41 +0200
committerHampusM <hampus@hampusmat.com>2023-10-25 21:16:10 +0200
commitfd535654369b31e1283a609ba8e8fcf0df42100b (patch)
tree2509bd71d835a4389ff7578dc6314d6019e31d01
parent0c0dc186b542bf6bdd7645ba091dc2a47a03fa97 (diff)
feat(engine): make camera look at a target position
-rw-r--r--engine/src/camera.rs47
-rw-r--r--engine/src/matrix.rs35
-rw-r--r--engine/src/renderer/mod.rs2
-rw-r--r--engine/src/vector.rs97
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
+ }
+}