diff --git a/quaternion.cpp b/quaternion.cpp index 45af0857..5d18a97e 100644 --- a/quaternion.cpp +++ b/quaternion.cpp @@ -194,6 +194,8 @@ template util::vector3d util::rotate (util::vector3d, util::quaterniond); /////////////////////////////////////////////////////////////////////////////// +// based on the implementation at: +// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/ template quaternion quaternion::look (vector<3,T> fwd, vector<3,T> up) @@ -201,22 +203,23 @@ quaternion::look (vector<3,T> fwd, vector<3,T> up) CHECK (is_normalised (fwd)); CHECK (is_normalised (up)); - constexpr util::vector3 RH_FWD { 0, 0, -1 }; - constexpr util::vector3 RH_UP { 0, 1, 0 }; + constexpr util::vector3 FWD { 0, 0, -1 }; + constexpr util::vector3 UP { 0, 1, 0 }; - // rotate the right-handed fwd to face the given fwd - auto q1 = from_to (RH_FWD, fwd); + // find the rotation from the world fwd to the object fwd + auto q1 = from_to (FWD, fwd); - // can't retain the up direction if fwd is the same as up - if (norm2 (cross (fwd, up)) < 1e-6) - return q1; + // orthogonalise the up vector + auto right = cross (fwd, up); + auto orthup = normalised (cross (right, fwd)); - // find the right-handed up rotated to the given fwd - auto new_up = rotate (RH_UP, q1); + // recompute the up vector in object space + auto newup = rotate (UP, q1); - // rotate first to the new forward, then align the right handed up with - // the given up. - return from_to (new_up, up) * q1; + // find rotation from object up to world up + auto q2 = from_to (newup, orthup); + + return q2 * q1; }