Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Quaternion-based camera still has gimbal lock.

  1. #1
    Newbie Newbie
    Join Date
    Dec 2012
    Posts
    3

    Question Quaternion-based camera still has gimbal lock.

    Hello, I'm not quite sure if this is question has already been asked before but I couldn't find anything after searching Google for hours.

    Basically, I'm trying to move my camera class away from vector rotations, due to the inevitable gimbal lock issue, and towards quaternion-based orientations. So far though, I've tried several different implementations using quaternions (even switched to matrices with no luck) but no matter what I try, I keep getting the same results that I had with rotating vectors. Can someone look over my code and help me figure this out? I feel as though the gimbal lock is rooted somewhere in between my euler angle conversion and the fact that I base my rotations on world axes.

    Code :
    //-----------------------------------------------------------------------------
    //	Camera Object - Movement & Orientation
    //-----------------------------------------------------------------------------
     
    void camera::look( const glm::vec3& inTarget ) {
    	glm::vec3 diffTarget	( pos - inTarget );
    	glm::quat rotations		( 0.f, diffTarget );
    	glm::vec3 angles		( glm::angle( rotations ) );
    	pitch = angles.x;
    	yaw = angles.y;
    	roll = angles.z;
    }
     
    void camera::move( float dx, float dy, float dz ) {
    	pos.x += dx;
    	pos.y += dy;
    	pos.z += dz;
    }
     
    void camera::rotate( float dPitch, float dYaw, float dRoll ) {
    	pitch = dPitch;
    	yaw = dYaw;
    	roll = dRoll;
    }
     
    //-----------------------------------------------------------------------------
    // Camera - Updating
    //-----------------------------------------------------------------------------
    void camera::update() {
    	//update the rotations
    	glm::quat rotateX( std::cos( pitch ), std::sin( pitch ), 0.f, 0.f );
    	glm::quat rotateY( std::cos( yaw ), 0.f, std::sin( yaw ), 0.f );
    	glm::quat rotateZ( std::cos( roll ), 0.f, 0.f, std::sin( roll ) );
     
    	glm::quat endRot = rotateZ * rotateY * rotateX;
     
    	switch( camType ) {
    		default:
    		case CAM_TYPE_FPS:
    			target.x = endRot.x;
    			target.y = endRot.y;
    			target.z = endRot.z;
    			break;
     
    		case CAM_TYPE_SPECTATOR:
    			eye = endRot;
    		break;
    	}
     
    	mvp
    		= projMat
    		* glm::lookAt( pos, target, up )
    		* glm::mat4_cast( eye );
    }

    I also tried removing the yaw, pitch, and roll variables from my camera class since that seemed more natural, although my brain just isn't really wired for quaternions.

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Apr 2010
    Location
    Germany
    Posts
    1,128
    Mathematically, gimbal lock using quaternions is impossible. If you still get similar problems, you're doing it wrong.

    EDIT: BTW, where do you actually rotate? You rotate in R^3 using a quaternion using: P' = q*P*q^-1

    Code :
    	glm::quat rotateX( std::cos( pitch ), std::sin( pitch ), 0.f, 0.f ); 	
    glm::quat rotateY( std::cos( yaw ), 0.f, std::sin( yaw ), 0.f ); 	
    glm::quat rotateZ( std::cos( roll ), 0.f, 0.f, std::sin( roll ) );   	
    glm::quat endRot = rotateZ * rotateY * rotateX;

    where q == endRot. I can't see any rotations in your code.

    Code :
    case CAM_TYPE_FPS:
        target.x = endRot.x;
        target.y = endRot.y;
        target.z = endRot.z;
        break;
     
    case CAM_TYPE_SPECTATOR:
        eye = endRot;

    This is not a rotation. This is complete nonsense. You set the components of the concatenated quaternion as the focal point passed to glmLookAt. Think about this for a minute ...
    Last edited by thokra; 12-14-2012 at 03:08 AM.

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,193
    Quote Originally Posted by thokra View Post
    Mathematically, gimbal lock using quaternions is impossible
    This is actually common misconception. Quaternions in-and-of-themselves don't solve gimbal lock. You can produce gimbal lock with quaternions (see below). However, if you use them right, you can get rid of gimbal lock.

    Gimbal lock arises from representating a rotation transform as multiple component rotations about different axes (e.g. heading, pitch, roll; or rotate about X, then Y, then Z; etc.) -- aka Euler angles. This scenario allows you to rotate one axis onto another, resulting in a loss of a degree of freedom and the dreaded gimble lock.

    What you need to do is represent your 3D rotations with "1" and only one quaternion. Not "3". Then use that for interpolation and compositing.

    For more info, see Quaternions and their Applications to Rotation in 3D Space (see the "Gimbal Lock with Quaternions" section).

    Then once you get real comfortable with quaternions and need to interpolate rotation and translation together, check out Dual Quaternions.
    Last edited by Dark Photon; 12-14-2012 at 07:08 AM.

  4. #4
    Senior Member OpenGL Pro
    Join Date
    Apr 2010
    Location
    Germany
    Posts
    1,128
    Quote Originally Posted by Dark Photon
    This is actually common misconception. Quaternions in-and-of-themselves don't solve gimble lock. If you use them right, you can get rid of gimble lock however.
    Yes, you're absolutely correct. I should have been more precise.

  5. #5
    Newbie Newbie
    Join Date
    Dec 2012
    Posts
    3
    Quote Originally Posted by thokra View Post
    Mathematically, gimbal lock using quaternions is impossible. If you still get similar problems, you're doing it wrong.

    EDIT: BTW, where do you actually rotate? You rotate in R^3 using a quaternion using: P' = q*P*q^-1

    Code :
    	glm::quat rotateX( std::cos( pitch ), std::sin( pitch ), 0.f, 0.f ); 	
    glm::quat rotateY( std::cos( yaw ), 0.f, std::sin( yaw ), 0.f ); 	
    glm::quat rotateZ( std::cos( roll ), 0.f, 0.f, std::sin( roll ) );   	
    glm::quat endRot = rotateZ * rotateY * rotateX;

    where q == endRot. I can't see any rotations in your code.

    Code :
    case CAM_TYPE_FPS:
        target.x = endRot.x;
        target.y = endRot.y;
        target.z = endRot.z;
        break;
     
    case CAM_TYPE_SPECTATOR:
        eye = endRot;

    This is not a rotation. This is complete nonsense. You set the components of the concatenated quaternion as the focal point passed to glmLookAt. Think about this for a minute ...
    I was following this tutorial which seemed to explain rotations in plain english (see the section on Euler to Quaternion). It actually works but still gives gimbal lock.

    Quote Originally Posted by Dark Photon View Post
    Gimbal lock arises from representating a rotation transform as multiple component rotations about different axes (e.g. heading, pitch, roll; or rotate about X, then Y, then Z; etc.) -- aka Euler angles. This scenario allows you to rotate one axis onto another, resulting in a loss of a degree of freedom and the dreaded gimble lock.

    What you need to do is represent your 3D rotations with "1" and only one quaternion. Not "3". Then use that for interpolation and compositing.
    This part really confuses me. If I am rotating using only one quaternion, then how do I manage a rotation around all 3 axes? I know I can have if "point" in a single direction, but I have to rotate it to get there first.

  6. #6
    Newbie Newbie
    Join Date
    Dec 2012
    Posts
    3
    @thokra, the rotations actually occur at the top of the "update" function. I was following this tutorial that I found while searching for help. I'm almost positive that the problem is caused by my use of yaw, pitch, and roll, but if I want to rotate my camera, how could I possibly do it without those angles?
    @Dark Photon, thanks for the article. I read through it but I'm still trying to comprehend everything.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •