use glam::{Mat4, Vec3};
use crate::aabb::Aabb;
#[derive(Debug, Clone)]
pub struct OrbitCamera {
pub target: Vec3,
pub yaw: f32,
pub pitch: f32,
pub distance: f32,
pub fov_y: f32,
pub near: f32,
pub far: f32,
pub aspect_ratio: f32,
}
impl OrbitCamera {
pub fn new(target: Vec3, distance: f32) -> Self {
Self {
target,
yaw: -0.785, pitch: 0.615, distance,
fov_y: std::f32::consts::FRAC_PI_4, near: 0.01,
far: 1000.0,
aspect_ratio: 16.0 / 9.0,
}
}
pub fn position(&self) -> Vec3 {
let cos_pitch = self.pitch.cos();
let offset = Vec3::new(
self.distance * cos_pitch * self.yaw.sin(),
self.distance * self.pitch.sin(),
self.distance * cos_pitch * self.yaw.cos(),
);
self.target + offset
}
pub fn right(&self) -> Vec3 {
let forward = (self.target - self.position()).normalize();
forward.cross(Vec3::Y).normalize()
}
pub fn up(&self) -> Vec3 {
let forward = (self.target - self.position()).normalize();
let right = forward.cross(Vec3::Y).normalize();
right.cross(forward).normalize()
}
pub fn view_matrix(&self) -> Mat4 {
Mat4::look_at_rh(self.position(), self.target, Vec3::Y)
}
pub fn projection_matrix(&self) -> Mat4 {
Mat4::perspective_rh(self.fov_y, self.aspect_ratio, self.near, self.far)
}
pub fn view_projection(&self) -> Mat4 {
self.projection_matrix() * self.view_matrix()
}
pub fn orbit(&mut self, delta_yaw: f32, delta_pitch: f32) {
self.yaw += delta_yaw;
self.pitch = (self.pitch + delta_pitch).clamp(
-std::f32::consts::FRAC_PI_2 + 0.01,
std::f32::consts::FRAC_PI_2 - 0.01,
);
}
pub fn pan(&mut self, delta_x: f32, delta_y: f32) {
let right = self.right();
let up = self.up();
self.target += right * delta_x + up * delta_y;
}
pub fn zoom(&mut self, delta: f32) {
self.distance *= 1.0 - delta;
self.distance = self.distance.clamp(0.1, 500.0);
}
pub fn fit_to_aabb(&mut self, aabb: Aabb) {
if !aabb.is_valid() {
return;
}
self.target = aabb.center();
let radius = aabb.diagonal() * 0.5;
self.distance = (radius / (self.fov_y * 0.5).sin()).max(0.5);
}
pub fn view_front(&mut self) {
self.yaw = 0.0;
self.pitch = 0.0;
}
pub fn view_top(&mut self) {
self.yaw = 0.0;
self.pitch = std::f32::consts::FRAC_PI_2 - 0.01;
}
pub fn view_right(&mut self) {
self.yaw = -std::f32::consts::FRAC_PI_2;
self.pitch = 0.0;
}
pub fn view_iso(&mut self) {
self.yaw = -0.785;
self.pitch = 0.615;
}
}
impl Default for OrbitCamera {
fn default() -> Self {
Self::new(Vec3::ZERO, 5.0)
}
}