diff --git a/src/camera.rs b/src/camera.rs index 3729487..209cb5b 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,40 +1,51 @@ -use glam::{Mat3, Vec3}; +use glam::{Vec3, vec3}; -pub fn ypr_to_mat(ypr: Vec3) -> Mat3 { - glam::Mat3::from_euler(glam::EulerRot::ZXZEx, ypr.x, ypr.y, ypr.z) +/// A camera always directed at the origin. +#[derive(Debug, Clone, Copy)] +pub struct OrbitalCamera { + /// Horizontal position (angle), in radians from +X towards +Y. + pub position_yaw: f32, + + /// Vertical position (angle), in radians from XY plane towards +Z. + pub position_pitch: f32, + + /// Distance from the origin. + pub distance: f32, +} + +impl OrbitalCamera { + pub fn position(&self) -> Vec3 { + let (y, x) = self.position_yaw.sin_cos(); + let (z, xy) = self.position_pitch.sin_cos(); + self.distance * vec3(xy * x, xy * y, z) + } } #[cfg(test)] mod tests { - use std::f32::consts::PI; - use approx::assert_ulps_eq; use glam::vec3; use super::*; #[test] - fn test_ypr_to_mat() { - assert_ulps_eq!(ypr_to_mat(vec3(0., 0., 0.)), Mat3::IDENTITY, max_ulps = 3); - assert_ulps_eq!( - ypr_to_mat(vec3(PI / 2., 0., 0.)), - Mat3::from_cols_array_2d(&[[0., 1., 0.], [-1., 0., 0.], [0., 0., 1.]]), - max_ulps = 3, - ); - assert_ulps_eq!( - ypr_to_mat(vec3(0., 0., PI / 2.)), - Mat3::from_cols_array_2d(&[[0., 1., 0.], [-1., 0., 0.], [0., 0., 1.]]), - max_ulps = 3, - ); - assert_ulps_eq!( - ypr_to_mat(vec3(0., PI / 2., 0.)), - Mat3::from_cols_array_2d(&[[1., 0., 0.], [0., 0., 1.], [0., -1., 0.]]), - max_ulps = 3, - ); - assert_ulps_eq!( - ypr_to_mat(vec3(PI / 2., PI / 2., 0.)), - Mat3::from_cols_array_2d(&[[0., 0., 1.], [-1., 0., 0.], [0., -1., 0.]]), - max_ulps = 3, - ); + fn test_orbital_camera_position() { + fn camera_pos_deg(yaw: f32, pitch: f32) -> Vec3 { + OrbitalCamera { + position_yaw: yaw.to_radians(), + position_pitch: pitch.to_radians(), + distance: 1.0, + } + .position() + } + assert_ulps_eq!(camera_pos_deg(0., 0.), vec3(1., 0., 0.), max_ulps = 3); + assert_ulps_eq!(camera_pos_deg(90., 0.), vec3(0., 1., 0.), max_ulps = 3); + assert_ulps_eq!(camera_pos_deg(0., 90.), vec3(0., 0., 1.), max_ulps = 3); + assert_ulps_eq!(camera_pos_deg(90., 90.), vec3(0., 0., 1.), max_ulps = 3); + + let s2 = 0.5f32.sqrt(); + assert_ulps_eq!(camera_pos_deg(45., 0.), vec3(s2, s2, 0.), max_ulps = 3); + assert_ulps_eq!(camera_pos_deg(0., 45.), vec3(s2, 0., s2), max_ulps = 3); + assert_ulps_eq!(camera_pos_deg(45., 45.), vec3(0.5, 0.5, s2), max_ulps = 3); } }