use cgmath::{Matrix4, Point3, Vector3, Deg, perspective, InnerSpace, Rotation, Quaternion, Rotation3, Rad}; #[derive(Debug)] pub struct Camera { pub eye: Point3, pub target: Point3, pub up: Vector3, pub fov_y: Deg, 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 { 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 { 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) { 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; } }