From 0885267ea30f422b59a182d63c00a75605b57692 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 17 Feb 2020 15:28:17 +0000 Subject: [PATCH] Smoothed camera motion, gentler orientation lerping --- voxygen/src/scene/camera.rs | 45 ++++++++++++++++++++++++++++++------- voxygen/src/scene/mod.rs | 2 +- voxygen/src/scene/simple.rs | 2 +- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 3847b0293e..020263f035 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -8,6 +8,7 @@ const FAR_PLANE: f32 = 100000.0; const FIRST_PERSON_INTERP_TIME: f32 = 0.1; const THIRD_PERSON_INTERP_TIME: f32 = 0.1; +const LERP_ORI_RATE: f32 = 15.0; pub const MIN_ZOOM: f32 = 0.1; // Possible TODO: Add more modes @@ -31,6 +32,7 @@ pub struct Dependents { pub struct Camera { tgt_focus: Vec3, focus: Vec3, + tgt_ori: Vec3, ori: Vec3, tgt_dist: f32, dist: f32, @@ -49,6 +51,7 @@ impl Camera { Self { tgt_focus: Vec3::unit_z() * 10.0, focus: Vec3::unit_z() * 10.0, + tgt_ori: Vec3::zero(), ori: Vec3::zero(), tgt_dist: 10.0, dist: 10.0, @@ -121,21 +124,33 @@ impl Camera { /// accordingly. pub fn rotate_by(&mut self, delta: Vec3) { // Wrap camera yaw - self.ori.x = (self.ori.x + delta.x) % (2.0 * PI); + self.tgt_ori.x = (self.tgt_ori.x + delta.x).rem_euclid(2.0 * PI); // Clamp camera pitch to the vertical limits - self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0); + self.tgt_ori.y = (self.tgt_ori.y + delta.y) + .min(PI / 2.0 - 0.0001) + .max(-PI / 2.0 + 0.0001); // Wrap camera roll - self.ori.z = (self.ori.z + delta.z) % (2.0 * PI); + self.tgt_ori.z = (self.tgt_ori.z + delta.z).rem_euclid(2.0 * PI); } /// Set the orientation of the camera about its focus. - pub fn set_orientation(&mut self, orientation: Vec3) { + pub fn set_orientation(&mut self, ori: Vec3) { // Wrap camera yaw - self.ori.x = orientation.x % (2.0 * PI); + self.tgt_ori.x = ori.x.rem_euclid(2.0 * PI); // Clamp camera pitch to the vertical limits - self.ori.y = orientation.y.min(PI / 2.0).max(-PI / 2.0); + self.tgt_ori.y = ori.y.min(PI / 2.0 - 0.0001).max(-PI / 2.0 + 0.0001); // Wrap camera roll - self.ori.z = orientation.z % (2.0 * PI); + self.tgt_ori.z = ori.z.rem_euclid(2.0 * PI); + } + + /// Set the orientation of the camera about its focus without lerping. + pub fn set_ori_instant(&mut self, ori: Vec3) { + // Wrap camera yaw + self.ori.x = ori.x.rem_euclid(2.0 * PI); + // Clamp camera pitch to the vertical limits + self.ori.y = ori.y.min(PI / 2.0 - 0.0001).max(-PI / 2.0 + 0.0001); + // Wrap camera roll + self.ori.z = ori.z.rem_euclid(2.0 * PI); } /// Zoom the camera by the given delta, limiting the input accordingly. @@ -175,7 +190,7 @@ impl Camera { /// Set the distance of the camera from the target (i.e., zoom). pub fn set_distance(&mut self, dist: f32) { self.tgt_dist = dist; } - pub fn update(&mut self, time: f64) { + pub fn update(&mut self, time: f64, dt: f32) { // This is horribly frame time dependent, but so is most of the game let delta = self.last_time.replace(time).map_or(0.0, |t| time - t); if (self.dist - self.tgt_dist).abs() > 0.01 { @@ -193,6 +208,20 @@ impl Camera { (delta as f32) / self.interp_time(), ); } + + let lerp_angle = |a: f32, b: f32, rate: f32| { + let offs = [-2.0 * PI, 0.0, 2.0 * PI] + .iter() + .min_by_key(|offs: &&f32| ((a - (b + *offs)).abs() * 1000.0) as i32) + .unwrap(); + Lerp::lerp(a, b + *offs, rate) + }; + + self.set_ori_instant(Vec3::new( + lerp_angle(self.ori.x, self.tgt_ori.x, LERP_ORI_RATE * dt), + Lerp::lerp(self.ori.y, self.tgt_ori.y, LERP_ORI_RATE * dt), + lerp_angle(self.ori.z, self.tgt_ori.z, LERP_ORI_RATE * dt), + )); } pub fn interp_time(&self) -> f32 { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index d8a2fbe300..4689ea6fc2 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -240,7 +240,7 @@ impl Scene { ); // Tick camera for interpolation. - self.camera.update(scene_data.state.get_time()); + self.camera.update(scene_data.state.get_time(), scene_data.state.get_delta_time()); // Compute camera matrices. self.camera.compute_dependents(&*scene_data.state.terrain()); diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index e663fb841f..7a17754231 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -146,7 +146,7 @@ impl Scene { } pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: SceneData) { - self.camera.update(scene_data.time); + self.camera.update(scene_data.time, 1.0 / 60.0); self.camera.compute_dependents(&VoidVol); let camera::Dependents {