Glm Quaternion lookat function
c++, glm-math, opengl, quaternions
Solution
Since version 0.9.9.0 there is a function in `<glm/gtc/quaternion.hpp>` doing mostly what you want:
template<typename T, qualifier Q>
tquat<T, Q> quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up);
It was added by this pull request and has been merged into master July 24, 2017.
But:
- direction has to be a normalized vector!
- direction can't be parallel to up!
So you may want to write a safer wrapper around the function:
glm::quat safeQuatLookAt(
glm::vec3 const& lookFrom,
glm::vec3 const& lookTo,
glm::vec3 const& up,
glm::vec3 const& alternativeUp)
{
glm::vec3 direction = lookTo - lookFrom;
float directionLength = glm::length(direction);
// Check if the direction is valid; Also deals with NaN
if(!(directionLength > 0.0001))
return glm::quat(1, 0, 0, 0); // Just return identity
// Normalize direction
direction /= directionLength;
// Is the normal up (nearly) parallel to direction?
if(glm::abs(glm::dot(direction, up)) > .9999f) {
// Use alternative up
return glm::quatLookAt(direction, alternativeUp);
}
else {
return glm::quatLookAt(direction, up);
}
}
Problem
I am trying to write a lookat function that uses glm::quat to represent rotations, based of off this answer. I am running into trouble getting a correct angle however. This is my lookat function: ``` void Camera::LookAt(float x, float y, float z) { glm::vec3 lookVector = glm::vec3(x, y, z); assert(lookVector != position); glm::vec3 direction = glm::normalize(lookVector-position); float dot = glm::dot(glm::vec3(0, 0, -1), direction); if (fabs(dot - (-1.0f)) < 0.000001f) rotation = glm::quat(RadiansToDegrees(M_PI), 0.0f, 1.0f, 0.0f); if (fabs(dot - (1.0f)) < 0.000001f) rotation = glm::quat(); float angle = RadiansToDegrees(acosf(dot)); glm::vec3 cross = (glm::cross(glm::vec3(0, 0, -1), direction)); rotation = glm::normalize(glm::angleAxis(angle, cross)); std::cout << glm::eulerAngles(rotation).x << " " << glm::eulerAngles(rotation).y << " " << glm::eulerAngles(rotation).z << "\n"; } ``` When I call LookAt(0.0f, 0.0f, 0.0f) when my camera is at (0.0f, 0.0f, -10.0f), this outputs a correct rotation of 0,0,0. However if I translate my camera to (0.0f, -0.01f, -10.0f) or more I get a rotation of about 124,0,0. This goes down if I continue to translate y by -0.01f. If I do not normalize the quaternion I do not get this problem. The rotation is still 124 about the x axis, but the appearance is fine. If however I normalize the quaternion later it once again appears to rotate to about 124. I can not normalize `cross`, because doing so throws an assert. What would cause me to get euler angles of 124 about x from my lookat function, and how can I fix it?