Glm Quaternion lookat function

别来无恙 提交于 2021-02-18 03:38:05

问题


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?


回答1:


Since version 0.9.9.0 there is a function in <glm/gtx/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:

  1. direction has to be a normalized vector!
  2. 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);
    }
}



回答2:


I have fixed the problem with the following code:

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::angleAxis(RadiansToDegrees(M_PI), glm::vec3(0, 1, 0));
        return;
    }
    else if (fabs(dot - (1.0f)) < 0.000001f) {
        rotation = glm::quat();
        return;
    }

    float angle = -RadiansToDegrees(acosf(dot));

    glm::vec3 cross = glm::normalize(glm::cross(glm::vec3(0, 0, 1), direction));
    rotation = glm::normalize(glm::angleAxis(angle, cross));
}

I do not however understand the necessity of the negative on angle. It fixed the last of my problems, and an explanation of the math of why would be helpful.



来源:https://stackoverflow.com/questions/18172388/glm-quaternion-lookat-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!