use glam::{Mat4, Vec3};
pub struct Camera {
pub angle: f32,
pub elevation: f32,
pub distance: f32,
pub fov_y: f32,
pub aspect: f32,
}
impl Camera {
pub fn new(aspect: f32) -> Self {
Self {
angle: 0.0,
elevation: 0.4,
distance: 6.0,
fov_y: 0.8,
aspect,
}
}
pub fn orbit(&mut self, delta_angle: f32) {
self.angle += delta_angle;
}
pub fn view_proj(&self) -> Mat4 {
let eye = Vec3::new(
self.distance * self.elevation.cos() * self.angle.cos(),
self.distance * self.elevation.cos() * self.angle.sin(),
self.distance * self.elevation.sin(),
);
let view = Mat4::look_at_rh(eye, Vec3::ZERO, Vec3::Z);
let proj = Mat4::perspective_rh(self.fov_y, self.aspect, 0.1, 50.0);
proj * view
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn orbit_increments_angle() {
let mut cam = Camera::new(1.0);
cam.orbit(0.5);
assert!((cam.angle - 0.5).abs() < 1e-6);
}
#[test]
fn view_proj_is_finite() {
let cam = Camera::new(16.0 / 9.0);
let vp = cam.view_proj();
for row in vp.to_cols_array_2d() {
for v in row {
assert!(v.is_finite(), "view_proj contains non-finite value: {v}");
}
}
}
}