diff --git a/glm/gtx/quaternion.hpp b/glm/gtx/quaternion.hpp index ad298dae..cce10892 100644 --- a/glm/gtx/quaternion.hpp +++ b/glm/gtx/quaternion.hpp @@ -177,6 +177,34 @@ namespace glm vec<3, T, P> const & orig, vec<3, T, P> const & dest); + /// Build a look at quaternion based on the default handedness. + /// + /// @param direction Desired direction of the camera. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL tquat quatLookAt( + tvec3 const & direction, + tvec3 const & up); + + /// Build a right-handed look at quaternion. + /// + /// @param direction Desired direction of the camera. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL tquat quatLookAtRH( + tvec3 const & direction, + tvec3 const & up); + + /// Build a left-handed look at quaternion. + /// + /// @param eye Position of the camera + /// @param direction Desired direction onto which the +z-axis gets mapped + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL tquat quatLookAtLH( + tvec3 const & direction, + tvec3 const & up); + /// Returns the squared length of x. /// /// @see gtx_quaternion diff --git a/glm/gtx/quaternion.inl b/glm/gtx/quaternion.inl index 7bdcdf60..c69426bb 100644 --- a/glm/gtx/quaternion.inl +++ b/glm/gtx/quaternion.inl @@ -208,5 +208,39 @@ namespace glm rotationAxis.y * invs, rotationAxis.z * invs); } + + template + GLM_FUNC_QUALIFIER tquat quatLookAt(tvec3 const& direction, tvec3 const& up) + { +# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED + return quatLookAtLH(direction, up); +# else + return quatLookAtRH(direction, up); +# endif + } + + template + GLM_FUNC_QUALIFIER tquat quatLookAtRH(tvec3 const& direction, tvec3 const& up) + { + tmat3x3 Result(uninitialize); + + Result[2] = -normalize(direction); + Result[0] = normalize(cross(up, Result[2])); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } + + template + GLM_FUNC_QUALIFIER tquat quatLookAtLH(tvec3 const& direction, tvec3 const& up) + { + tmat3x3 Result(uninitialize); + + Result[2] = normalize(direction); + Result[0] = normalize(cross(up, Result[2])); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } }//namespace glm diff --git a/test/gtx/gtx_quaternion.cpp b/test/gtx/gtx_quaternion.cpp index a6daf715..e27981c4 100644 --- a/test/gtx/gtx_quaternion.cpp +++ b/test/gtx/gtx_quaternion.cpp @@ -90,6 +90,23 @@ int test_log() return Error; } +int test_quat_lookAt() +{ + int Error(0); + + glm::vec3 eye(0.0f); + glm::vec3 center(1.1f, -2.0f, 3.1416f); + glm::vec3 up = glm::vec3(-0.17f, 7.23f, -1.744f); + + glm::quat test_quat = glm::quatLookAt(center - eye, up); + glm::quat test_mat = glm::conjugate(glm::quat_cast(glm::lookAt(eye, center, up))); + + Error += static_cast(glm::abs(glm::length(test_quat) - 1.0f) > glm::epsilon()); + Error += static_cast(glm::min(glm::length(test_quat + (-test_mat)), glm::length(test_quat + test_mat)) > glm::epsilon()); + + return Error; +} + int main() { int Error = 0; @@ -98,6 +115,7 @@ int main() Error += test_rotation(); Error += test_quat_fastMix(); Error += test_quat_shortMix(); + Error += test_quat_lookAt(); return Error; }