From de392a007c6168b64b4c6fda385fbfc67186c9df Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 6 Feb 2024 20:12:09 +0100 Subject: [PATCH 1/2] Fix rounding error in camera eye interpolation at t=0 and t=1 --- crates/re_space_view_spatial/src/eye.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/re_space_view_spatial/src/eye.rs b/crates/re_space_view_spatial/src/eye.rs index 9fead86394a7..07efc7896157 100644 --- a/crates/re_space_view_spatial/src/eye.rs +++ b/crates/re_space_view_spatial/src/eye.rs @@ -209,13 +209,19 @@ impl OrbitEye { } pub fn lerp(&self, other: &Self, t: f32) -> Self { - Self { - orbit_center: self.orbit_center.lerp(other.orbit_center, t), - orbit_radius: lerp(self.orbit_radius..=other.orbit_radius, t), - world_from_view_rot: self.world_from_view_rot.slerp(other.world_from_view_rot, t), - fov_y: egui::lerp(self.fov_y..=other.fov_y, t), - up: self.up.lerp(other.up, t).normalize_or_zero(), - velocity: self.velocity.lerp(other.velocity, t), + if t == 0.0 { + *self // avoid rounding errors + } else if t == 1.0 { + *other // avoid rounding errors + } else { + Self { + orbit_center: self.orbit_center.lerp(other.orbit_center, t), + orbit_radius: lerp(self.orbit_radius..=other.orbit_radius, t), + world_from_view_rot: self.world_from_view_rot.slerp(other.world_from_view_rot, t), + fov_y: egui::lerp(self.fov_y..=other.fov_y, t), + up: self.up.lerp(other.up, t).normalize_or_zero(), + velocity: self.velocity.lerp(other.velocity, t), + } } } From d20d34685e6aaba1daf5c6417e1bb39d22448d40 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 6 Feb 2024 20:13:02 +0100 Subject: [PATCH 2/2] Small code cleanup --- crates/re_space_view_spatial/src/ui_3d.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index dbe604b725ee..d06fee7aedbf 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -147,10 +147,6 @@ impl View3DState { let t = t.clamp(0.0, 1.0); let t = ease_out(t); - if t < 1.0 { - response.ctx.request_repaint(); - } - if let Some(target_orbit) = &cam_interpolation.target_orbit { *orbit_eye = cam_interpolation.start.lerp(target_orbit, t); } else if let Some(target_eye) = &cam_interpolation.target_eye { @@ -160,12 +156,12 @@ impl View3DState { self.eye_interpolation = None; } - if 1.0 <= t { - // We have arrived at our target - self.eye_interpolation = None; - } else { + if t < 1.0 { // There's more frames to render to finish interpolation. response.ctx.request_repaint(); + } else { + // We have arrived at our target + self.eye_interpolation = None; } } @@ -256,6 +252,10 @@ impl View3DState { // the user wants to move the camera somewhere, so stop spinning self.spin = false; + if self.orbit_eye == Some(target) { + return; // We're already there. + } + // Don't restart interpolation if we're already on it. if let Some(eye_interpolation) = &self.eye_interpolation { if eye_interpolation.target_orbit == Some(target) { @@ -329,7 +329,8 @@ impl EyeInterpolation { .angle_between(stop.world_from_rub_view.rotation()); // Threshold to avoid doing pointless interpolations that trigger frame requests. - if angle_difference < 0.01 && start.pos_in_world().distance(stop.pos_in_world()) < 0.0001 { + let distance = start.pos_in_world().distance(stop.pos_in_world()); + if angle_difference < 0.01 && distance < 0.0001 { None } else { Some(egui::remap_clamp(