Skip to content

Commit

Permalink
Merge pull request #669 from chrisprice/rotate-relative-to-camera
Browse files Browse the repository at this point in the history
Rotate around axis relative to camera
  • Loading branch information
hannobraun authored Jun 7, 2022
2 parents e305aca + e2f87e7 commit 9dc8d43
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 7 deletions.
43 changes: 43 additions & 0 deletions crates/fj-math/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ impl Transform {
pub fn data(&self) -> &[f64] {
self.0.matrix().data.as_slice()
}

/// Extract the rotation component of this transform
pub fn extract_rotation(&self) -> Transform {
Self(nalgebra::Transform::from_matrix_unchecked(
self.0.matrix().fixed_resize::<3, 3>(0.).to_homogeneous(),
))
}

/// Extract the translation component of this transform
pub fn extract_translation(&self) -> Transform {
*self * self.extract_rotation().inverse()
}
}

impl ops::Mul<Self> for Transform {
Expand Down Expand Up @@ -169,4 +181,35 @@ mod tests {
epsilon = 1e-8,
);
}

#[test]
fn extract_rotation_translation() {
let rotation =
Transform::rotation(Vector::unit_z() * (Scalar::PI / 2.));
let translation = Transform::translation([1., 2., 3.]);

assert_abs_diff_eq!(
(translation * rotation).extract_rotation().data(),
rotation.data(),
epsilon = 1e-8,
);

assert_abs_diff_eq!(
(translation * rotation).extract_translation().data(),
translation.data(),
epsilon = 1e-8,
);

assert_abs_diff_eq!(
(rotation * translation).extract_rotation().data(),
rotation.data(),
epsilon = 1e-8,
);

assert_abs_diff_eq!(
(rotation * translation).extract_translation().data(),
Transform::translation([-2., 1., 3.]).data(),
epsilon = 1e-8,
);
}
}
31 changes: 24 additions & 7 deletions crates/fj-viewer/src/input/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,33 @@ impl Rotation {
let angle_x = diff_y * f;
let angle_y = diff_x * f;

let trans = Transform::translation(rotate_around);
let rotate_around = Transform::translation(rotate_around);

let aa_x = Vector::unit_x() * angle_x;
let aa_y = Vector::unit_y() * angle_y;
let rot_x = Transform::rotation(aa_x);
let rot_y = Transform::rotation(aa_y);
// the model rotates not the camera, so invert the transform
let camera_rotation = camera.rotation.inverse();
let right_vector = right_vector(&camera_rotation);
let up_vector = up_vector(&camera_rotation);

let inv = trans.inverse();
let rotation = Transform::rotation(right_vector * angle_x)
* Transform::rotation(up_vector * angle_y);

camera.rotation = camera.rotation * trans * rot_y * rot_x * inv;
let transform = camera.camera_to_model()
* rotate_around
* rotation
* rotate_around.inverse();

camera.rotation = transform.extract_rotation();
camera.translation = transform.extract_translation();
}
}
}

fn up_vector(rotation: &Transform) -> Vector<3> {
let d = rotation.data();
Vector::from_components_f64([d[4], d[5], d[6]])
}

fn right_vector(rotation: &Transform) -> Vector<3> {
let d = rotation.data();
Vector::from_components_f64([d[0], d[1], d[2]])
}

0 comments on commit 9dc8d43

Please sign in to comment.