4
\$\begingroup\$

I'm making a camera object for rendering with OpenGL. However, instead of using the typical "LookAt" method I'm trying to use just a Quaternion for orientation and a Vector3 for position. Instead of messing with euler angles to rotate the Camera I use quaternions directly, like this:

glm::vec3 up = glm::normalize(glm::inverse(cam.Orientation) * glm::vec3(0, 1, 0));
glm::vec3 right = glm::vec3(-1, 0, 0);
cam.Orientation = glm::rotate(cam.Orientation, glm::radians(-xoffset), up);
cam.Orientation = glm::rotate(cam.Orientation, glm::radians(-yoffset), right);

xoffset and yoffset are just the amount the mouse has moved since the last frame.

I create my view matrix from the inverse of the two variables. I've already got FPS style camera movement and rotation working. The problem I have now is that I want to prevent the camera from being able to flip over. I.E. moving the mouse up or down enough that the view becomes upside down. Is there a way to clamp the rotation using purely quaternions to prevent this?

\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

I know its old, but maybe somebody else is facing this painful challange:

So a camera represented only by:

glm::quat mRotation;
glm::vec3 mPosition;

needs also keep track the Pitch and Yaw separately, and apply it one by one to the main mRotation quaternion. I haven't found any other way to limit a quaternion otherwise.

So all in all the Camera class must have these members initialized to 0.0f:

glm::quat mRotation;
glm::vec3 mPosition;
float mPitch, mYaw;

During the frame by frame call, where you pass in the delta mouse movement values, the Pitch keeps track the cumulated mouse movement, and thats what you can clamp, then pass it into the quaternion as angel axis, here is how:

void Camera::rotate(const float horizontalMouseMove, const float verticalMouseMove)
{
    mPitch -= verticalMouseMove;
    mYaw -= horizontalMouseMove;

    //TODO: clamp Yaw?
    mRotation = glm::angleAxis(mYaw, axis::positiveY);

    //clamp Pitch
    constexpr float PITCH_LIMIT = 1.4f;//magic number, 1.0f is too flat to my taste
    if (mPitch < -PITCH_LIMIT)
    {
        mPitch = -PITCH_LIMIT;
    }
    else
    if (mPitch > PITCH_LIMIT)
    {
        mPitch = PITCH_LIMIT;
    }

    //quaternion multiplication is not commutative, and we have YAW rotation already applied mRotation
    mRotation = mRotation * glm::angleAxis(mPitch, getRight());
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .