From ed711671c6a46f12366a4ffd45c81838e9f1a256 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 24 Jun 2026 17:35:26 +0300 Subject: [PATCH] fix(viewport): keep MSPACE camera target in f64 to stop UTM jitter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit camera_from_view computed the camera target in f32 (view_target cast to f32 before folding view_center), quantizing it to ~0.5 m at UTM scale. Panning/zooming inside a floating viewport nudges view_target by sub-metre f64 steps, so the camera snapped along the f32 grid and the drawn content jittered — while the model view (f64 target) stayed smooth. Compute the target in f64 (axis directions stay f32 — orientation only), matching the model camera's precision. Co-Authored-By: Claude Opus 4.8 --- src/scene/mod.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 9c7a069f1..12b2fe663 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -6311,17 +6311,23 @@ impl Scene { let view_up = rotation * glam::Vec3::Y; // view_target is WCS; wire-space subtracts world_offset. view_center is // a DCS (screen-plane) offset, so fold it through the view basis. - let base = glam::Vec3::new( - (view_target.x - world_offset[0]) as f32, - (view_target.y - world_offset[1]) as f32, - (view_target.z - world_offset[2]) as f32, + // Keep the target in f64: casting it to f32 first quantizes the camera + // to ~0.5 m at UTM scale, so panning/zooming inside a floating viewport + // (which nudges view_target by sub-metre f64 steps) made the content + // jump on the f32 grid. The axis directions stay f32 (orientation only); + // only the position must stay precise — matching the model camera. + let base = glam::DVec3::new( + view_target.x - world_offset[0], + view_target.y - world_offset[1], + view_target.z - world_offset[2], ); - let target = - base + view_right * view_center.x as f32 + view_up * view_center.y as f32; + let target = base + + view_right.as_dvec3() * view_center.x + + view_up.as_dvec3() * view_center.y; let fov_y = 45.0_f32.to_radians(); let distance = ((view_height as f32 / 2.0) / (fov_y * 0.5).tan()).max(0.001); Some(Camera { - target: target.as_dvec3(), + target, rotation, distance, fov_y,