2

I read in many sources about using quaternion to avoid gimbal lock but I can't apply this practically in my code, so I have a camera class I want to rotate it with mouse so I have Euler angles Pitch and Yaw, I have a camQuat qauaternion to store the rotation quaternion each frame, so I have the initCamera method which initialize the camera:

void Camera::initCamera(glm::vec3& pos, glm::vec3& center, GLfloat yaw, GLfloat pitch) {
    view = glm::translate(view, center - pos);
    camQuat = glm::quat(glm::vec3(glm::radians(pitch), glm::radians(yaw), 0.0));
    camQuat = glm::normalize(camQuat);
    glm::mat4 rot = glm::mat4_cast(camQuat);
    view = view * rot;
    view = glm::translate(view, pos - center);
}

then each frame I update the camera by this method

void Camera::rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c) {
    xoffset *= this->mouseSensitivity;
    yoffset *= this->mouseSensitivity;
    view = glm::translate(view, c);
    glm::quat q(glm::vec3(glm::radians(yoffset), glm::radians(xoffset), 0.0f));
    q = glm::normalize(q);
    glm::quat temp(q);
    q = q * camQuat * glm::conjugate(q);
    camQuat = temp;
    glm::mat4 rot = glm::mat4_cast(q);
    view = view * rot;
    view = glm::translate(view, -c);
}

this makes the rotation but with gimbal look, what is the bug in my code or what is the right way to use quaternion to prevent the gimbal look?

Edit: the first image is the normal camera FPS the rotation should be around the x and y axis only (No Rolling), once I rotate around any axis (as I read until the angle becomes 90) the gimbal lock appear and the camera begins to roll around z like the second image. enter image description here

Normal camera gimbal lock

Solution: due to DMGregory link below this code works fine:

void Camera::rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c, GLboolean constrainpitch) {
    xoffset *= this->mouseSensitivity;
    yoffset *= this->mouseSensitivity;
    glm::quat Qx(glm::angleAxis(glm::radians(yoffset), glm::vec3(1.0f, 0.0f, 0.0f)));
    glm::quat Qy(glm::angleAxis(glm::radians(xoffset), glm::vec3(0.0f, 1.0f, 0.0f)));
    glm::mat4 rotX = glm::mat4_cast(Qx);
    glm::mat4 rotY = glm::mat4_cast(Qy);
    view = glm::translate(view, c);
    view = rotX * view;
    view = view * rotY;
    view = glm::translate(view, -c);
}

I get the quaternion for both x and y then post multiply the QX by the view matrix then pre multiply the QY by the view matrix, the idea is rotating pitch globally and yaw locally to avoid unwanted creeping roll.

Vaillancourt
  • 16,325
  • 17
  • 55
  • 61
Mohamed
  • 141
  • 5
  • Can you describe the gimbal lock symptoms you're observing? A typical scenario is that when you look straight up/down, attempting to turn left/right (eg sweeping my gaze from my right toe to right hand to right shoulder without lifting my head) instead spins the view, like you were standing on a turntable. I'm not fluent in GL, but it doesn't look like your code would have this symptom. There's another common rotation issue where a twist or roll "creeps in" without the sharp spin singularity of gimbal lock. Is it possible you're seeing that? – DMGregory Jul 10 '17 at 11:08
  • Check my answer here: How to avoid gimbal lock , its more less a duplicate of your question. – Maik Semder Jul 10 '17 at 11:21
  • I don't know if it fixes your issue but please avoid changing your camera by offset quaternions if you use yaw and pitch values. Instead of computing offset quats and adding them to current orientation - add offsets to yaw/pitch values and run 'initCamera' code every frame. – kolenda Jul 10 '17 at 11:27
  • @DMGregory I added the description of what happen – Mohamed Jul 10 '17 at 11:32
  • @MaikSemder I already read your answer before asking and as u answer I store the quaternion and post multiply it by the new quaternion calculated from Euler angles but still have that behavior. – Mohamed Jul 10 '17 at 11:34
  • The symptom you've shown doesn't look like gimbal lock to me. It would be very unusual to have a gimbal lock pole when looking outward at the horizon. Instead, it looks like the creeping roll phenomenon I linked above. Can you take a look at the animations at that link and let us know if they're similar to what you're observing? – DMGregory Jul 10 '17 at 11:37
  • How do you calculate xoffset and yoffset? – Maik Semder Jul 10 '17 at 11:50
  • also the new camera quaternion should be the old one * with the delta, something like camQuat = camQuat * qThisFrame without the conjugate – Maik Semder Jul 10 '17 at 11:51
  • you can also test your function with those param: rotate(0, 0, vec3(0,0,0)) nothing should change if you call it like this, does that work? – Maik Semder Jul 10 '17 at 11:54
  • @DMGregory, yes the same problem exactly, so as your answer I should make yaw rotation around the global Y, but I rotate the camera around an object and I make this by translating to it, rotate and translate back to position so i'm confused how could I do this? – Mohamed Jul 10 '17 at 12:17
  • @DMGregory finally I did it, just flip the multiplication order of the quaternion around x by the transformation matrix, Thank you your answer was very helpful, could you posit it as answer? – Mohamed Jul 10 '17 at 14:15
  • If the other answer solved your problem, then I think this question is a duplicate of the linked question. What would you say to closing this question as a duplicate, and you can add an additional answer to that linked question explaining how you applied the "pitch local, yaw global" fix in your specific OpenGL situation? When we centralise the knowledge of how to fix these problems, it makes it easier for other users to find it, or for us to link users to canonical solutions. – DMGregory Jul 10 '17 at 14:21
  • sure, I will immediatly – Mohamed Jul 10 '17 at 14:24

0 Answers0