Skip to main content

ranim_anims/
camera.rs

1//! Camera frame animations.
2
3use ranim_core::{
4    animation::eval::{Eval, EvalExt},
5    core_item::camera_frame::CameraFrame,
6    glam::DVec3,
7};
8
9// MARK: Anim Trait
10/// The methods to create animations for [`CameraFrame`].
11pub trait CameraFrameAnim {
12    /// Create an orbit animation that rotates the camera around `target`
13    /// by `total_angle` radians in the XY plane (Z-up).
14    ///
15    /// The camera's current position is used to derive the spherical
16    /// coordinates (distance, elevation) which are kept constant during the orbit.
17    ///
18    /// # Example
19    /// ```ignore
20    /// use std::f64::consts::TAU;
21    ///
22    /// let mut cam = CameraFrame::from_spherical(phi, theta, distance);
23    /// r.play(
24    ///     cam.orbit(DVec3::ZERO, TAU)
25    ///         .with_duration(8.0)
26    ///         .with_rate_func(linear),
27    /// );
28    /// ```
29    fn orbit(&mut self, target: DVec3, total_angle: f64) -> Orbit;
30}
31
32impl CameraFrameAnim for CameraFrame {
33    fn orbit(&mut self, target: DVec3, total_angle: f64) -> Orbit {
34        let offset = self.pos - target;
35        let distance = offset.length();
36        let phi = if distance > 0.0 {
37            (offset.z / distance).acos()
38        } else {
39            0.0
40        };
41        let theta0 = offset.y.atan2(offset.x);
42
43        Orbit {
44            src: self.clone(),
45            target,
46            distance,
47            phi,
48            theta0,
49            total_angle,
50        }
51        .apply_to(self)
52    }
53}
54
55// MARK: Impl
56/// An orbit animation rotating the camera around a target.
57pub struct Orbit {
58    /// The camera state at the start of the orbit.
59    pub src: CameraFrame,
60    /// The orbit target.
61    pub target: DVec3,
62    /// Distance from the target.
63    pub distance: f64,
64    /// Elevation angle kept constant during the orbit.
65    pub phi: f64,
66    /// Initial azimuth angle.
67    pub theta0: f64,
68    /// Total angle to rotate, in radians.
69    pub total_angle: f64,
70}
71
72impl Eval for Orbit {
73    type Output = CameraFrame;
74
75    fn eval_alpha(&self, alpha: f64) -> Self::Output {
76        let theta = self.theta0 + self.total_angle * alpha;
77        let mut result = self.src.clone();
78        result.set_spherical(self.phi, theta, self.distance, self.target);
79        result
80    }
81}