cgmath_dolly/drivers/
smooth.rs

1use std::marker::PhantomData;
2
3use cgmath::{Quaternion, Vector3};
4
5use crate::{
6    driver::RigDriver,
7    handedness::Handedness,
8    rig::RigUpdateParams,
9    transform::Transform,
10    util::{ExpSmoothed, ExpSmoothingParams},
11};
12
13/// Smooths the parent transformation.
14#[derive(Debug)]
15pub struct Smooth {
16    /// Exponential smoothing factor for the position
17    pub position_smoothness: f32,
18
19    /// Exponential smoothing factor for the rotation
20    pub rotation_smoothness: f32,
21
22    // The scale with which smoothing should be applied
23    output_offset_scale: f32,
24
25    smoothed_position: ExpSmoothed<Vector3<f32>>,
26    smoothed_rotation: ExpSmoothed<Quaternion<f32>>,
27}
28
29impl Default for Smooth {
30    fn default() -> Self {
31        Self {
32            position_smoothness: 1.0,
33            rotation_smoothness: 1.0,
34            output_offset_scale: 1.0,
35            smoothed_position: Default::default(),
36            smoothed_rotation: Default::default(),
37        }
38    }
39}
40
41impl Smooth {
42    /// Only smooth position
43    pub fn new_position(position_smoothness: f32) -> Self {
44        Self {
45            position_smoothness,
46            rotation_smoothness: 0.0,
47            ..Default::default()
48        }
49    }
50
51    /// Only smooth rotation
52    pub fn new_rotation(rotation_smoothness: f32) -> Self {
53        Self {
54            rotation_smoothness, 
55            position_smoothness: 0.0,
56            ..Default::default()
57        }
58    }
59
60    /// Smooth both position and rotation
61    pub fn new_position_rotation(position_smoothness: f32, rotation_smoothness: f32) -> Self {
62        Self {
63            position_smoothness,
64            rotation_smoothness,
65            ..Default::default()
66        }
67    }
68
69    /// Reverse the smoothing, causing the camera to look ahead of the parent transform
70    ///
71    /// This can be useful on top of [`Position`], and before another `Smooth`
72    /// in the chain to create a soft yet responsive follower camera.
73    ///
74    /// [`Position`]: struct.Position.html
75    /// [`Smooth`]: struct.Smooth.html
76    pub fn predictive(mut self, predictive: bool) -> Self {
77        self.output_offset_scale = if predictive { -1.0 } else { 1.0 };
78        self
79    }
80}
81
82impl<H: Handedness> RigDriver<H> for Smooth {
83    fn update(&mut self, params: RigUpdateParams<H>) -> Transform<H> {
84        let position = self.smoothed_position.exp_smooth_towards(
85            &params.parent.position,
86            ExpSmoothingParams {
87                smoothness: self.position_smoothness,
88                output_offset_scale: self.output_offset_scale,
89                delta_time_seconds: params.delta_time_seconds,
90            },
91        );
92
93        let rotation = self.smoothed_rotation.exp_smooth_towards(
94            &params.parent.rotation,
95            ExpSmoothingParams {
96                smoothness: self.rotation_smoothness,
97                output_offset_scale: self.output_offset_scale,
98                delta_time_seconds: params.delta_time_seconds,
99            },
100        );
101
102        Transform {
103            position,
104            rotation,
105            phantom: PhantomData,
106        }
107    }
108}