70 lines
2.2 KiB
Rust

use cgmath::{Matrix4, Point3, Vector3, Deg, perspective, InnerSpace, Rotation, Quaternion, Rotation3, Rad};
#[derive(Debug)]
pub struct Camera {
pub eye: Point3<f32>,
pub target: Point3<f32>,
pub up: Vector3<f32>,
pub fov_y: Deg<f32>,
pub aspect: f32,
pub znear: f32,
pub zfar: f32,
}
impl Camera {
pub fn new(aspect: f32) -> Self {
Self {
eye: Point3::new(0.0, 0.0, 5.0),
target: Point3::new(0.0, 0.0, 0.0),
up: Vector3::unit_y(),
fov_y: Deg(45.0),
aspect,
znear: 0.1,
zfar: 100.0,
}
}
pub fn build_view_projection_matrix(&self) -> Matrix4<f32> {
let view = Matrix4::look_at_rh(self.eye, self.target, self.up);
let proj = perspective(self.fov_y, self.aspect, self.znear, self.zfar);
proj * view
}
pub fn build_view_matrix(&self) -> Matrix4<f32> {
Matrix4::look_at_rh(self.eye, self.target, self.up)
}
pub fn rotate_yaw_pitch(&mut self, yaw: f32, pitch: f32) {
let offset = self.eye - self.target;
let distance = offset.magnitude();
let yaw_q = Quaternion::from_axis_angle(Vector3::unit_y(), Rad(yaw.to_radians()));
let right = offset.cross(self.up).normalize();
let pitch_q = Quaternion::from_axis_angle(right, Rad(pitch.to_radians()));
let rotation = yaw_q * pitch_q;
let new_offset = rotation.rotate_vector(offset);
self.eye = self.target + new_offset;
self.up = rotation.rotate_vector(self.up);
}
pub fn translate(&mut self, translation: Vector3<f32>) {
let dir = (self.target - self.eye).normalize();
let horizontal = Vector3::unit_y().cross(dir).normalize();
let vertical = horizontal.cross(dir).normalize();
self.eye += horizontal * translation.x + vertical * translation.y;
self.target += horizontal * translation.x + vertical * translation.y;
}
pub fn zoom(&mut self, amount: f32) {
let dir = (self.target - self.eye).normalize();
self.eye += dir * amount;
}
pub fn set_aspect(&mut self, aspect: f32) {
self.aspect = aspect;
}
}