From 9395dfbede91f9d210bba3fe52247bb5652ccd52 Mon Sep 17 00:00:00 2001 From: francy51 Date: Wed, 10 Jun 2026 10:01:57 -0400 Subject: [PATCH] fix(camera): use orbit rotation directly, normalize quaternion each frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace looking_at + with_rotation with a direct rotation assignment — orbit.rotation already encodes the correct look direction so the intermediate looking_at call was redundant and discarded. Also re-normalize the quaternion every frame to prevent floating-point drift from repeated multiplications. --- apps/game/src/camera.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/game/src/camera.rs b/apps/game/src/camera.rs index bb5b687..835d217 100644 --- a/apps/game/src/camera.rs +++ b/apps/game/src/camera.rs @@ -105,6 +105,12 @@ pub fn orbit_camera_control( // (local-axis rotation) — this preserves a stable horizon line as // long as `rotation` doesn't already pitch past 90°. orbit.rotation = yaw * orbit.rotation * pitch; + + // Re-normalize to counteract floating-point drift from repeated + // multiplications. Without this the quaternion gradually loses unit + // length, introducing an implicit scale that manifests as visual + // stretching / skewing of the scene. + orbit.rotation = orbit.rotation.normalize(); } } else { mouse_motion.clear(); @@ -125,11 +131,13 @@ pub fn orbit_camera_control( // the offset is `rotation * +Z * distance`. let offset = orbit.rotation * Vec3::new(0.0, 0.0, orbit.distance); let position = orbit.target + offset; - *transform = Transform::from_translation(position) - .looking_at(orbit.target, Vec3::Y) - // Re-apply rotation to recover the roll component that `looking_at` - // would otherwise discard (matters when the camera is upside-down). - .with_rotation(orbit.rotation); + + // Use `orbit.rotation` directly — it already encodes the correct look + // direction (rotation * -Z points toward the target). Do NOT call + // `looking_at` then `with_rotation`; that computes a correct rotation + // only to discard it, and hides the fact that the raw quaternion is the + // sole source of truth. + *transform = Transform::from_translation(position).with_rotation(orbit.rotation); } /// Resource: set by UI buttons (e.g. "Center View") to request the orbit camera