diff --git a/src/camera.rs b/src/camera.rs index 39189a0..bfda144 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -10,6 +10,7 @@ pub trait Camera { pub struct Flycam { // input + // currently held keys is_world_up_pressed: bool, is_world_down_pressed: bool, is_cam_up_pressed: bool, @@ -18,18 +19,26 @@ pub struct Flycam { is_backward_pressed: bool, is_left_pressed: bool, is_right_pressed: bool, + // accumulated mouse movement yet to be processed mouse_dx: f32, mouse_dy: f32, + // state + // timestamp last_update: Instant, - euler_y: f32, + // camera orientation euler_x: f32, + euler_y: f32, + // camera movement state velocity: Vec3, position: Vec3, + // constants - turn_sensitivity: f32, - thrust_mag: f32, - damping_coeff: f32, + // camera movement + turn_sensitivity: f32, // coefficient for mouse_dx/dy -> euler_x/y + thrust_mag: f32, // coefficient for thrust acceleration vector + damping_coeff: f32, // coefficient for damping acceleration vector + // camera frustum aspect: f32, fovy: f32, znear: f32, @@ -52,8 +61,8 @@ impl Flycam { mouse_dx: 0.0, mouse_dy: 0.0, last_update: Instant::now(), - euler_y: 0.0, euler_x: 0.0, + euler_y: 0.0, velocity: Vec3::new(0.0, 0.0, 0.0), position: Vec3::new(0.0, 0.5, 1.0), turn_sensitivity, @@ -68,6 +77,7 @@ impl Flycam { } impl Flycam { + /// update stored keyboard state for use in update() pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) { let is_pressed = state == ElementState::Pressed; match key { @@ -99,6 +109,7 @@ impl Flycam { } } + /// update accumulated mouse movement for use in update() pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { self.mouse_dx += mouse_dx as f32; self.mouse_dy += mouse_dy as f32; @@ -108,6 +119,7 @@ impl Flycam { self.aspect = (width as f32) / (height as f32); } + /// apply input and update camera movement pub fn update(&mut self) { let dt = self.last_update.elapsed(); self.last_update = Instant::now(); @@ -135,8 +147,8 @@ impl Flycam { } } + /// update velocity and position from acceleration using forward differences fn update_kinematic(&mut self, dt: f32) { - /// update velocity and position from acceleration using forward differences let net_acc = self.get_thrust_acc() + self.get_damping_acc(); let delta_vel = net_acc * dt; @@ -146,12 +158,15 @@ impl Flycam { self.position += delta_pos; } + /// use keyboard key pairs to trigger directional thrusters in camera and world coordinates + /// thrust_speed is the max speed (under drag) with a single thruster, but combinations can + /// produce higher speeds (e.g. forward and right, camera down and world down) fn get_thrust_acc(&self) -> glam::Vec3 { let axis = Self::key_axis; - let thruster_cam_x = axis(self.is_left_pressed, self.is_right_pressed); - let thruster_cam_y = axis(self.is_cam_down_pressed, self.is_cam_up_pressed); - let thruster_cam_z = -axis(self.is_backward_pressed, self.is_forward_pressed); // forward is -z + let thruster_cam_x = axis(self.is_left_pressed, self.is_right_pressed); + let thruster_cam_y = axis(self.is_cam_down_pressed, self.is_cam_up_pressed); + let thruster_cam_z = -axis(self.is_backward_pressed, self.is_forward_pressed); // forward is -z let thruster_world_y = axis(self.is_world_down_pressed, self.is_world_up_pressed); let thrusters_cam = Vec3::new(thruster_cam_x, thruster_cam_y, thruster_cam_z); @@ -163,10 +178,14 @@ impl Flycam { self.thrust_mag * thrusters_total } + /// calculate a damping force (proportional to velocity) + /// the damping coefficient is calculated in the constructor, which is parameterized in terms + /// of more physically meaningful values fn get_damping_acc(&self) -> glam::Vec3 { self.damping_coeff * -self.velocity } + /// a helper function to turn a pair of key states into a sign for thruster direction fn key_axis(negative: bool, positive: bool) -> f32 { if negative { if positive { @@ -183,8 +202,10 @@ impl Flycam { } } + /// the current camera orientation, which can be seen as a rotation (in quaternion form) from + /// camera axes to world axes + /// glam's YXZ ordering matches the standard roll-pitch-yaw Euler angles fn get_orientation(&self) -> glam::Quat { - // returns rotation from camera axes to world axes Quat::from_euler(glam::EulerRot::YXZ, self.euler_y, self.euler_x, 0.0) } }