use std::ops::Range;
use glam::*;
pub trait CameraTrait {
fn view(&self) -> Mat4;
fn projection(&self, aspect_ratio: f32) -> Mat4;
}
#[derive(Debug, Clone)]
pub struct Camera {
pub pos: Vec3,
pub z: Range<f32>,
pub vertical_fov: f32,
pub pitch: f32,
pub yaw: f32,
}
impl Camera {
pub const UP: Vec3 = Vec3::Y;
pub const PITCH_LIMIT: Range<f32> =
-std::f32::consts::FRAC_PI_2 + 1e-6..std::f32::consts::FRAC_PI_2 - 1e-6;
pub fn new(z: Range<f32>, vertical_fov: f32) -> Self {
Self {
pos: Vec3::ZERO,
z,
vertical_fov,
pitch: 0.0,
yaw: 0.0,
}
}
pub fn move_by(&mut self, forward: f32, right: f32) {
self.pos += self.get_forward() * forward + self.get_right() * right;
}
pub fn move_up(&mut self, up: f32) {
self.pos += Self::UP * up;
}
pub fn pitch_by(&mut self, delta: f32) {
self.pitch = (self.pitch + delta).clamp(Self::PITCH_LIMIT.start, Self::PITCH_LIMIT.end);
}
pub fn yaw_by(&mut self, delta: f32) {
self.yaw = (self.yaw + delta).rem_euclid(2.0 * std::f32::consts::PI);
}
pub fn get_forward(&self) -> Vec3 {
Vec3::new(
self.pitch.cos() * self.yaw.sin(),
self.pitch.sin(),
self.pitch.cos() * self.yaw.cos(),
)
}
pub fn get_right(&self) -> Vec3 {
self.get_forward().cross(Self::UP).normalize()
}
}
impl CameraTrait for Camera {
fn view(&self) -> Mat4 {
Mat4::look_to_rh(self.pos, self.get_forward(), Self::UP)
}
fn projection(&self, aspect_ratio: f32) -> Mat4 {
Mat4::perspective_rh(self.vertical_fov, aspect_ratio, self.z.start, self.z.end)
}
}