2025-05-05 20:07:20 +02:00
|
|
|
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
|
|
|
|
|
}
|
2025-05-07 19:45:35 +02:00
|
|
|
|
|
|
|
|
pub fn build_view_matrix(&self) -> Matrix4<f32> {
|
|
|
|
|
Matrix4::look_at_rh(self.eye, self.target, self.up)
|
|
|
|
|
}
|
2025-05-05 20:07:20 +02:00
|
|
|
|
|
|
|
|
pub fn rotate_yaw_pitch(&mut self, yaw: f32, pitch: f32) {
|
2025-05-07 21:54:37 +02:00
|
|
|
let offset = self.eye - self.target;
|
|
|
|
|
let distance = offset.magnitude();
|
2025-05-05 20:07:20 +02:00
|
|
|
|
|
|
|
|
let yaw_q = Quaternion::from_axis_angle(Vector3::unit_y(), Rad(yaw.to_radians()));
|
2025-05-07 21:54:37 +02:00
|
|
|
let right = offset.cross(self.up).normalize();
|
|
|
|
|
let pitch_q = Quaternion::from_axis_angle(right, Rad(pitch.to_radians()));
|
2025-05-05 20:07:20 +02:00
|
|
|
|
|
|
|
|
let rotation = yaw_q * pitch_q;
|
2025-05-07 21:54:37 +02:00
|
|
|
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();
|
2025-05-05 20:07:20 +02:00
|
|
|
|
2025-05-07 21:54:37 +02:00
|
|
|
self.eye += horizontal * translation.x + vertical * translation.y;
|
|
|
|
|
self.target += horizontal * translation.x + vertical * translation.y;
|
2025-05-05 20:07:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|