From 213fc580a961853f5cbd73a182f266d018b7bda5 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Mon, 8 Jun 2020 18:40:50 -0400 Subject: [PATCH] Add Transform::{look_at_rh, look_at_lh} and deprecate look_at Corresponding functions have been added to Matrix4 and Decomposed and are now consistent. Matrix3, Matrix2, and the Rotation trait are only partially updated. --- src/matrix.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++ src/transform.rs | 31 +++++++++++++++++ tests/transform.rs | 37 ++++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/src/matrix.rs b/src/matrix.rs index ea0e9de..e5548a2 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -189,6 +189,7 @@ impl Matrix3 { /// Create a rotation matrix that will cause a vector to point at /// `dir`, using `up` for orientation. + #[deprecated = "Use Matrix3::look_at_lh"] pub fn look_at(dir: Vector3, up: Vector3) -> Matrix3 { let dir = dir.normalize(); let side = up.cross(dir).normalize(); @@ -197,6 +198,26 @@ impl Matrix3 { Matrix3::from_cols(side, up, dir).transpose() } + /// Create a rotation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_at_lh(dir: Vector3, up: Vector3) -> Matrix3 { + let dir = dir.normalize(); + let side = up.cross(dir).normalize(); + let up = dir.cross(side).normalize(); + + Matrix3::from_cols(side, up, dir).transpose() + } + + /// Create a rotation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_at_rh(dir: Vector3, up: Vector3) -> Matrix3 { + let dir = -dir.normalize(); + let side = up.cross(dir).normalize(); + let up = dir.cross(side).normalize(); + + Matrix3::from_cols(side, up, dir).transpose() + } + /// Create a rotation matrix from a rotation around the `x` axis (pitch). pub fn from_angle_x>>(theta: A) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations @@ -333,6 +354,7 @@ impl Matrix4 { /// Create a homogeneous transformation matrix that will cause a vector to point at /// `dir`, using `up` for orientation. + #[deprecated = "Use Matrix4::look_to_rh"] pub fn look_at_dir(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { let f = dir.normalize(); let s = f.cross(up).normalize(); @@ -347,12 +369,47 @@ impl Matrix4 { ) } + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_rh(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), + s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), + s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), + -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(), + ) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_lh(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { + Matrix4::look_to_rh(eye, -dir, up) + } + /// Create a homogeneous transformation matrix that will cause a vector to point at /// `center`, using `up` for orientation. + #[deprecated = "Use Matrix4::look_at_rh"] pub fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { Matrix4::look_at_dir(eye, center - eye, up) } + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `center`, using `up` for orientation. + pub fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_to_rh(eye, center - eye, up) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `center`, using `up` for orientation. + pub fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_to_lh(eye, center - eye, up) + } + /// Create a homogeneous transformation matrix from a rotation around the `x` axis (pitch). pub fn from_angle_x>>(theta: A) -> Matrix4 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations @@ -1043,6 +1100,16 @@ impl Transform> for Matrix3 { Matrix3::from(Matrix2::look_at(dir, up)) } + fn look_at_lh(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { + let dir = center - eye; + Matrix3::from(Matrix2::look_at(dir, up)) + } + + fn look_at_rh(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { + let dir = eye - center; + Matrix3::from(Matrix2::look_at(dir, up)) + } + fn transform_vector(&self, vec: Vector2) -> Vector2 { (self * vec.extend(S::zero())).truncate() } @@ -1066,6 +1133,16 @@ impl Transform> for Matrix3 { Matrix3::look_at(dir, up) } + fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { + let dir = center - eye; + Matrix3::look_at_lh(dir, up) + } + + fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { + let dir = center - eye; + Matrix3::look_at_rh(dir, up) + } + fn transform_vector(&self, vec: Vector3) -> Vector3 { self * vec } @@ -1084,10 +1161,19 @@ impl Transform> for Matrix3 { } impl Transform> for Matrix4 { + fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { Matrix4::look_at(eye, center, up) } + fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_lh(eye, center, up) + } + + fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_rh(eye, center, up) + } + fn transform_vector(&self, vec: Vector3) -> Vector3 { (self * vec.extend(S::zero())).truncate() } diff --git a/src/transform.rs b/src/transform.rs index 0b3453c..151bf3d 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -30,8 +30,17 @@ use std::ops::Mul; pub trait Transform: Sized + One { /// Create a transformation that rotates a vector to look at `center` from /// `eye`, using `up` for orientation. + #[deprecated = "Use look_at_rh or look_at_lh"] fn look_at(eye: P, center: P, up: P::Diff) -> Self; + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. + fn look_at_rh(eye: P, center: P, up: P::Diff) -> Self; + + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. + fn look_at_lh(eye: P, center: P, up: P::Diff) -> Self; + /// Transform a vector using this transform. fn transform_vector(&self, vec: P::Diff) -> P::Diff; @@ -113,6 +122,28 @@ where } } + #[inline] + fn look_at_lh(eye: P, center: P, up: P::Diff) -> Decomposed { + let rot = R::look_at(center - eye, up); + let disp = rot.rotate_vector(P::origin() - eye); + Decomposed { + scale: P::Scalar::one(), + rot: rot, + disp: disp, + } + } + + #[inline] + fn look_at_rh(eye: P, center: P, up: P::Diff) -> Decomposed { + let rot = R::look_at(eye - center, up); + let disp = rot.rotate_vector(P::origin() - eye); + Decomposed { + scale: P::Scalar::one(), + rot: rot, + disp: disp, + } + } + #[inline] fn transform_vector(&self, vec: P::Diff) -> P::Diff { self.rot.rotate_vector(vec * self.scale) diff --git a/tests/transform.rs b/tests/transform.rs index 1dcc357..708b822 100644 --- a/tests/transform.rs +++ b/tests/transform.rs @@ -88,6 +88,7 @@ fn test_inverse_vector() { } #[test] +#[allow(deprecated)] fn test_look_at() { let eye = Point3::new(0.0f64, 0.0, -5.0); let center = Point3::new(0.0f64, 0.0, 0.0); @@ -98,6 +99,42 @@ fn test_look_at() { assert_ulps_eq!(&t.transform_point(point), &view_point); } +#[test] +fn test_look_at_lh() { + let eye = Point3::new(0.0f64, 0.0, -5.0); + let center = Point3::new(0.0f64, 0.0, 0.0); + let up = Vector3::new(1.0f64, 0.0, 0.0); + let t: Decomposed, Quaternion> = Transform::look_at_lh(eye, center, up); + let point = Point3::new(1.0f64, 0.0, 0.0); + let view_point = Point3::new(0.0f64, 1.0, 5.0); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at_lh and Matrix4::look_at_lh should be consistent + let t: Matrix4 = Transform::look_at_lh(eye, center, up); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at is inconsistent and deprecated, but verify that the behvaior + // remains the same until removed. + #[allow(deprecated)] + let t: Decomposed, Quaternion> = Transform::look_at(eye, center, up); + assert_ulps_eq!(&t.transform_point(point), &view_point); +} + +#[test] +fn test_look_at_rh() { + let eye = Point3::new(0.0f64, 0.0, -5.0); + let center = Point3::new(0.0f64, 0.0, 0.0); + let up = Vector3::new(1.0f64, 0.0, 0.0); + let t: Decomposed, Quaternion> = Transform::look_at_rh(eye, center, up); + let point = Point3::new(1.0f64, 0.0, 0.0); + let view_point = Point3::new(0.0f64, 1.0, -5.0); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at_rh and Matrix4::look_at_rh should be consistent + let t: Matrix4 = Transform::look_at_rh(eye, center, up); + assert_ulps_eq!(&t.transform_point(point), &view_point); +} + #[cfg(feature = "serde")] #[test] fn test_serialize() {