From 1789f26ea1d67d3c4aad569ccd84ea08b595fc29 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 25 Jan 2014 10:54:54 -0500 Subject: [PATCH] look_at() implemented as a part of Transform trait --- README.md | 2 +- src/cgmath/approx.rs | 2 +- src/cgmath/matrix.rs | 17 +++++++++++------ src/cgmath/point.rs | 12 ++---------- src/cgmath/quaternion.rs | 5 ----- src/cgmath/rotation.rs | 29 +++++++++++++++++++++++------ src/cgmath/transform.rs | 20 +++++++++++++++++++- src/test/transform.rs | 14 +++++++++++++- 8 files changed, 70 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 11125f9..05db369 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The library provides: - angle units: `Rad`, `Deg` - points: `Point2`, `Point3` - rays: `Ray2`, `Ray3` -- a plane: `Plane` +- a plane type: `Plane` - perspective projections: `Perspective`, `PerspectiveFov`, `Ortho` - a view frustum: `Frustrum` - spatial transformations: `AffineMatrix3`, `Transform3D` diff --git a/src/cgmath/approx.rs b/src/cgmath/approx.rs index fa62e4f..6d39d9d 100644 --- a/src/cgmath/approx.rs +++ b/src/cgmath/approx.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The CGMath Developers. For a full listing of the authors, +// Copyright 2014 The CGMath Developers. For a full listing of the authors, // refer to the AUTHORS file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/cgmath/matrix.rs b/src/cgmath/matrix.rs index 041ed23..f7a757c 100644 --- a/src/cgmath/matrix.rs +++ b/src/cgmath/matrix.rs @@ -68,7 +68,12 @@ impl Mat2 { } } -impl Mat2 { +impl> Mat2 { + pub fn look_at(dir: &Vec2, up: &Vec2) -> Mat2 { + //TODO: verify look_at 2D + Mat2::from_cols(up.clone(), dir.clone()).transpose() + } + #[inline] pub fn from_angle(theta: Rad) -> Mat2 { let cos_theta = cos(theta.clone()); @@ -115,11 +120,11 @@ impl Mat3 { impl> Mat3 { pub fn look_at(dir: &Vec3, up: &Vec3) -> Mat3 { - let dir = dir.normalize(); - let side = dir.cross(&up.normalize()); - let up = side.cross(&dir).normalize(); + let dir = dir.normalize(); + let side = up.cross(&dir).normalize(); + let up = dir.cross(&side).normalize(); - Mat3::from_cols(up, side, dir) + Mat3::from_cols(side, up, dir).transpose() } /// Create a matrix from a rotation around the `x` axis (pitch). @@ -672,7 +677,7 @@ impl> ToQuat for Mat3 { /// Convert the matrix to a quaternion fn to_quat(&self) -> Quat { - // http://www.cs.ucr.edu/~vbz/resources/Quatut.pdf + // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf let trace = self.trace(); let half: S = cast(0.5).unwrap(); match () { diff --git a/src/cgmath/point.rs b/src/cgmath/point.rs index 193a1ed..6c37d85 100644 --- a/src/cgmath/point.rs +++ b/src/cgmath/point.rs @@ -37,11 +37,6 @@ impl Point2 { pub fn new(x: S, y: S) -> Point2 { Point2 { x: x, y: y } } - - #[inline] - pub fn origin() -> Point2 { - Point2 { x: zero(), y: zero() } - } } impl Point3 { @@ -49,11 +44,6 @@ impl Point3 { pub fn new(x: S, y: S, z: S) -> Point3 { Point3 { x: x, y: y, z: z } } - - #[inline] - pub fn origin() -> Point3 { - Point3 { x: zero(), y: zero(), z: zero() } - } } impl Point3 { @@ -78,6 +68,8 @@ pub trait Point > : Array { + #[inline] fn origin() -> Self{ build(|_i| zero::()) } + #[inline] fn from_vec(v: &V) -> Self { build(|i| v.i(i).clone()) } #[inline] fn to_vec(&self) -> V { build(|i| self.i(i).clone()) } diff --git a/src/cgmath/quaternion.rs b/src/cgmath/quaternion.rs index 8be7640..f86295b 100644 --- a/src/cgmath/quaternion.rs +++ b/src/cgmath/quaternion.rs @@ -47,11 +47,6 @@ Quat { Quat { s: s, v: v } } - #[inline] - pub fn look_at(dir: &Vec3, up: &Vec3) -> Quat { - Mat3::look_at(dir, up).to_quat() - } - /// Create a matrix from a rotation around the `x` axis (pitch). #[inline] pub fn from_angle_x(theta: Rad) -> Quat { diff --git a/src/cgmath/rotation.rs b/src/cgmath/rotation.rs index 9ad86d3..5e9a29f 100644 --- a/src/cgmath/rotation.rs +++ b/src/cgmath/rotation.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The CGMath Developers. For a full listing of the authors, +// Copyright 2014 The CGMath Developers. For a full listing of the authors, // refer to the AUTHORS file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,6 +36,8 @@ pub trait Rotation + ApproxEq { fn identity() -> Self; + fn look_at(dir: &V, up: &V) -> Self; + fn rotate_vec(&self, vec: &V) -> V; #[inline] @@ -120,6 +122,16 @@ impl> Rotation, Point2> for Basis2 { #[inline] fn identity() -> Basis2 { Basis2{ mat: Mat2::identity() } } + + #[inline] + fn look_at(dir: &Vec2, up: &Vec2) -> Basis2 { + Basis2 { mat: Mat2::look_at(dir, up) } + } + + #[inline] + fn look_at(dir: &Vec2, up: &Vec2) -> Basis2 { + Basis2 { mat: Mat2::look_at(dir, up) } + } #[inline] fn rotate_vec(&self, vec: &Vec2) -> Vec2 { self.mat.mul_v(vec) } @@ -165,11 +177,6 @@ pub struct Basis3 { impl> Basis3 { - #[inline] - pub fn look_at(dir: &Vec3, up: &Vec3) -> Basis3 { - Basis3 { mat: Mat3::look_at(dir, up) } - } - /// Create a rotation matrix from a rotation around the `x` axis (pitch). pub fn from_angle_x(theta: Rad) -> Basis3 { Basis3 { mat: Mat3::from_angle_x(theta) } @@ -229,6 +236,11 @@ impl> Rotation, Point3> for Basis3 { #[inline] fn identity() -> Basis3 { Basis3{ mat: Mat3::identity() } } + + #[inline] + fn look_at(dir: &Vec3, up: &Vec3) -> Basis3 { + Basis3 { mat: Mat3::look_at(dir, up) } + } #[inline] fn rotate_vec(&self, vec: &Vec3) -> Vec3 { self.mat.mul_v(vec) } @@ -278,6 +290,11 @@ impl> Rotation, Point3> for Quat { #[inline] fn identity() -> Quat { Quat::identity() } + + #[inline] + fn look_at(dir: &Vec3, up: &Vec3) -> Quat { + Mat3::look_at(dir, up).to_quat() + } #[inline] fn rotate_vec(&self, vec: &Vec3) -> Vec3 { self.mul_v(vec) } diff --git a/src/cgmath/transform.rs b/src/cgmath/transform.rs index eacfaf0..9e759e2 100644 --- a/src/cgmath/transform.rs +++ b/src/cgmath/transform.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The CGMath Developers. For a full listing of the authors, +// Copyright 2014 The CGMath Developers. For a full listing of the authors, // refer to the AUTHORS file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ pub trait Transform > { fn identity() -> Self; + fn look_at(eye: &P, center: &P, up: &V) -> Self; fn transform_vec(&self, vec: &V) -> V; fn transform_point(&self, point: &P) -> P; @@ -90,6 +91,18 @@ Transform for Decomposed { } } + #[inline] + fn look_at(eye: &P, center: &P, up: &V) -> Decomposed { + let origin :P = Point::origin(); + let rot :R = Rotation::look_at( ¢er.sub_p(eye), up ); + let disp :V = rot.rotate_vec( &origin.sub_p(eye) ); + Decomposed { + scale: num::one(), + rot: rot, + disp: disp, + } + } + #[inline] fn transform_vec(&self, vec: &V) -> V { self.rot.rotate_vec( &vec.mul_s( self.scale.clone() )) @@ -162,6 +175,11 @@ Transform, Point3> for AffineMatrix3 { fn identity() -> AffineMatrix3 { AffineMatrix3 { mat: Mat4::identity() } } + + #[inline] + fn look_at(eye: &Point3, center: &Point3, up: &Vec3) -> AffineMatrix3 { + AffineMatrix3 { mat: Mat4::look_at(eye, center, up) } + } #[inline] fn transform_vec(&self, vec: &Vec3) -> Vec3 { diff --git a/src/test/transform.rs b/src/test/transform.rs index 1ca465c..eac50af 100644 --- a/src/test/transform.rs +++ b/src/test/transform.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The CGMath Developers. For a full listing of the authors, +// Copyright 2014 The CGMath Developers. For a full listing of the authors, // refer to the AUTHORS file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +15,7 @@ use cgmath::quaternion::*; use cgmath::transform::*; +use cgmath::point::*; use cgmath::vector::*; use cgmath::approx::ApproxEq; @@ -26,3 +27,14 @@ fn test_invert() { let vt = t.get().transform_vec( &v ); assert!(v.approx_eq( &ti.transform_vec( &vt ) )); } + +#[test] +fn test_look_at() { + let eye = Point3::new(0.0, 0.0, -5.0); + let center = Point3::new(0.0, 0.0, 0.0); + let up = Vec3::new(1.0, 0.0, 0.0); + let t: Decomposed,Quat> = Transform::look_at(&eye, ¢er, &up); + let point = Point3::new(1.0, 0.0, 0.0); + let view_point = Point3::new(0.0, 1.0, 5.0); + assert!( t.transform_point(&point).approx_eq(&view_point) ); +}