From 2aa308fe43a23f57b5736e4e1535279882d5ece5 Mon Sep 17 00:00:00 2001 From: Alan Everett Date: Wed, 13 Nov 2024 07:36:15 -0500 Subject: [PATCH] Scale camera zoom based on distance to target (#40) * Scale camera zoom based on distance to target * Fix screen2ray scaling with zoom * Fix zoom_towards when point is not target * Add zoom function * Safety check --------- Co-authored-by: Asger Nyman Christiansen --- src/camera.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 647ced1..34ce012 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -298,6 +298,7 @@ impl Camera { Point3::from_vec(self.target), self.up, ); + self.view[3][3] *= position.distance(target); self.update_screen2ray(); self.update_frustrum(); } @@ -557,6 +558,7 @@ impl Camera { fn update_screen2ray(&mut self) { let mut v = self.view; + v /= v[3][3]; if let ProjectionType::Perspective { .. } = self.projection_type { v[3] = vec4(0.0, 0.0, 0.0, 1.0); } @@ -676,8 +678,17 @@ impl Camera { } } + /// + /// Moves the camera towards the camera target by the amount delta while keeping the given minimum and maximum distance to the target. + /// + pub fn zoom(&mut self, delta: f32, minimum_distance: f32, maximum_distance: f32) { + let target = self.target; + self.zoom_towards(&target, delta, minimum_distance, maximum_distance); + } + /// /// Moves the camera towards the given point by the amount delta while keeping the given minimum and maximum distance to the point. + /// Note that the camera target is also updated so that the view direction is the same. /// pub fn zoom_towards( &mut self, @@ -694,17 +705,15 @@ impl Camera { let position = *self.position(); let distance = point.distance(position); - let direction = (point - position).normalize(); - let target = *self.target(); - let up = self.up; - let new_distance = (distance - delta).clamp(minimum_distance, maximum_distance); - let new_position = point - direction * new_distance; - self.set_view(new_position, new_position + (target - position), up); - if let ProjectionType::Orthographic { height } = self.projection_type() { - let h = new_distance * height / distance; - let z_near = self.z_near(); - let z_far = self.z_far(); - self.set_orthographic_projection(h, z_near, z_far); + if distance > f32::EPSILON { + let delta_clamped = + distance - (distance - delta).clamp(minimum_distance, maximum_distance); + let v = (point - position) * delta_clamped / distance; + self.set_view( + self.position + v, + self.target + v - v.project_on(self.view_direction()), + self.up, + ); } } }