1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Provides the [`Momentum`] settings.
use std::time::Duration;
use bevy_math::{DVec2, DVec3};
use bevy_reflect::prelude::*;
/// Defines momentum behavior of this [`super::component::EditorCam`].
#[derive(Debug, Clone, Copy, Reflect)]
pub struct Momentum {
/// Momentum decay scales with velocity.
pub pan_damping: u8,
/// Momentum decay is constant.
pub pan_friction: f64,
// The sampling window to use when a movement ends to determine the velocity of the camera when
/// momentum decay begins. The higher this value, the easier it is to "flick" the camera, but
/// the more of a velocity discontinuity will be present when momentum starts.
pub init_pan: Duration,
/// Momentum decay scales with velocity.
pub orbit_damping: u8,
/// Momentum decay is constant.
pub orbit_friction: f64,
/// The sampling window to use when a movement ends to determine the velocity of the camera when
/// momentum decay begins. The higher this value, the easier it is to "flick" the camera, but
/// the more of a velocity discontinuity will be present when momentum starts.
pub init_orbit: Duration,
}
impl Default for Momentum {
fn default() -> Self {
Self {
pan_damping: 160,
pan_friction: 0.3,
init_pan: Duration::from_millis(40),
orbit_damping: 160,
orbit_friction: 0.3,
init_orbit: Duration::from_millis(60),
}
}
}
impl Momentum {
fn decay_velocity_orbit(self, velocity: DVec2, delta_time: Duration) -> DVec2 {
let velocity =
velocity * (self.orbit_damping as f64 / 256.0).powf(delta_time.as_secs_f64() * 10.0);
let static_decay =
velocity.normalize() * self.orbit_friction * delta_time.as_secs_f64() * 120.0;
let static_decay_clamped = static_decay.abs().min(velocity.abs()) * velocity.signum();
velocity - static_decay_clamped
}
fn decay_velocity_pan(self, velocity: DVec2, delta_time: Duration) -> DVec2 {
let velocity =
velocity * (self.pan_damping as f64 / 256.0).powf(delta_time.as_secs_f64() * 10.0);
let static_decay =
velocity.normalize() * self.pan_friction * delta_time.as_secs_f64() * 120.0;
let static_decay_clamped = static_decay.abs().min(velocity.abs()) * velocity.signum();
velocity - static_decay_clamped
}
}
/// The velocity of the camera.
#[derive(Debug, Clone, Copy, Default, Reflect)]
pub enum Velocity {
/// The velocity is zero and the camera will transition into the Stationary state.
#[default]
None,
///Camera is spinning.
Orbit {
/// The anchor of rotation being orbited about.
anchor: DVec3,
/// The current velocity of the camera about the anchor.
velocity: DVec2,
},
/// Camera is sliding.
Pan {
/// The anchor point that should stick to the pointer during panning.
anchor: DVec3,
/// The current panning velocity of the camera.
velocity: DVec2,
},
}
impl Velocity {
const DECAY_THRESHOLD: f64 = 1e-3;
/// Decay the velocity based on the momentum setting.
pub fn decay(&mut self, momentum: Momentum, delta_time: Duration) {
let is_none = match self {
Velocity::None => true,
Velocity::Orbit {
ref mut velocity, ..
} => {
*velocity = momentum.decay_velocity_orbit(*velocity, delta_time);
velocity.length() <= Self::DECAY_THRESHOLD
}
Velocity::Pan {
ref mut velocity, ..
} => {
*velocity = momentum.decay_velocity_pan(*velocity, delta_time);
velocity.length() <= Self::DECAY_THRESHOLD
}
};
if is_none {
*self = Velocity::None;
}
}
}