Thread: Gimbal Lock My Hated Foe

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    4

    Talking Gimbal Lock My Hated Foe

    I have been working on my camera in DirectX 9 for a while now. No matter what I try I can not create a 6DOF (space ship) camera. I came upon a thread on this forum by a user named darksaidin. I implemented it into my own code but I still suffer from that damn rolling up and down when I rotate horizontaly. So I figured I would post my camera code here to get a possible solution to my problem. I cut out any part that doesn't deal with rotation specificaly. If anyone has any suggestions please let me know.

    Code:
    //------------------------------------------------------------------------------------------------
    Constructor
    {
                 m_vecRight        = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
                 m_vecUp           = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
                 m_vecLook         = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
                 m_vecPosition          = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
    
                 m_fRotSpeed = 15.0f;                          // Rotation Speed
    }
    
    //------------------------------------------------------------------------------------------------
    Rotate(float pitch, float yaw, float roll, float Distance, MyUnit * in_Unit)
    {
                D3DXVECTOR3 tempRot(pitch, yaw, roll);	       // Create Vector out of user input
    	D3DXVec3Normalize(&tempRot, &tempRot);  // Norm input		
    	tempRot *= m_fRotSpeed * Distance;           //Scale by time and speed
    	
    	if(tempRot.x != 0)                // Pitch Camera
    	{                               
    	    RotateInPlane(m_vecLook, m_vecUp, -D3DX_PI/180 * tempRot.x);	
    	}
    	if( tempRot.y != 0 )	            // Yaw Camera								
    	{
    	    RotateInPlane(m_vecRight, m_vecLook, -D3DX_PI/180 * tempRot.y);
    	}
    	if ( tempRot.z != 0 )             // Roll Camera
    	{
    	      RotateInPlane(m_vecRight, m_vecUp, D3DX_PI/180 * tempRot.z);	
    	}
    	m_bcon_ViewDirty = true;          // View is dirty must be rebuilt
    }
    
    //------------------------------------------------------------------------------------------------
    GetViewMatrix()
    {
        if(m_bcon_ViewDirty)
       {
                    // Clean up the axises     
            D3DXVec3Normalize( &m_vecLook, &m_vecLook );
            D3DXVec3Cross( &m_vecUp, &m_vecLook, &m_vecRight );
            D3DXVec3Normalize( &m_vecUp, &m_vecUp );
            D3DXVec3Cross( &m_vecRight, &m_vecUp, &m_vecLook );
            D3DXVec3Normalize( &m_vecRight, &m_vecRight );
    
            //   --- Build the view matrix using the altered axises  ---
            m_mtxView._11 = m_vecRight.x;  m_mtxView._12 = m_vecUp.x;  m_mtxView._13 = m_vecLook.x;
            m_mtxView._21 = m_vecRight.y;  m_mtxView._22 = m_vecUp.y;  m_mtxView._23 = m_vecLook.y;
            m_mtxView._31 = m_vecRight.z;  m_mtxView._32 = m_vecUp.z;  m_mtxView._33 = m_vecLook.z;
            m_mtxView._41 =- D3DXVec3Dot( &m_vecPos, &m_vecRight );
            m_mtxView._42 =- D3DXVec3Dot( &m_vecPos, &m_vecUp    );
            m_mtxView._43 =- D3DXVec3Dot( &m_vecPos, &m_vecLook  );
    
            m_bcon_ViewDirty = false;	
        }
    	
        return m_mtxView;
    }
    
    //------------------------------------------------------------------------------------------------
    This is the code I got from darksaidin's post
    Code:
    // rotate 2 vectors in the plane they span
    void RotateInPlane(D3DXVECTOR3 &vA, D3DXVECTOR3 &vB, float fAngle) 
    {
    	float	fCos= cos(fAngle);
    	float	fSin= sin(fAngle);
    	D3DXVECTOR3	vTemp;
    
    	// calc temp vector between vA and vB in their plane.
    	// this will be vA later, but we can't yet overwrite it
    	// since we still need it for vB
    	vTemp.x=	 fCos *vA.x +fSin *vB.x;
    	vTemp.y=	 fCos *vA.y +fSin *vB.y;
    	vTemp.z=	 fCos *vA.z +fSin *vB.z;
    
    	// same for vB but -90 degrees
                    // cos(f+90)=-sin(f) to reduce cos/sin usage
    	vB.x=	-fSin *vA.x +fCos *vB.x; 
                   	vB.y=	-fSin *vA.y +fCos *vB.y;
    	vB.z=	-fSin *vA.z +fCos *vB.z;
    
    	// now update vA
    	vA= vTemp;
    }
    Anyone have any comments or suggestions? Is there a problem in my logic or code? I would also appreciate any links to source code for 6DOF cameras. I have tried a number of other ways to do it (using various tutorials)

  2. #2
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Since you're using D3DX, why not use D3DXMatrixRotationYawPitchRoll?

    EDIT: And if you're really wanting to do it yourself you'd probably be better off using matrices anyway.
    Consider this post signed

  3. #3
    Registered User
    Join Date
    Jun 2010
    Posts
    4
    Man what you are seeing here is like the 4th or 5th reimagining. I have tried it with matrices transforming vector axises, using matrices to accumulate seperate rotations for each axis and then combining those matrices, I've tried quaternions, tried using D3DXMatrixLookAtLH. You name it I have tried it. They all seem to suffer from the same thing. When all 3 rotations are applied they warp in some way. Usually when yaw is applied. I don't know if it is something I am doing or what. I have copy and pasted example code from online books and web tutorials and always get similar results. Has anyone here actually implemented a 6DOF camera in DirectX?
    Last edited by Toe_Tag; 06-24-2010 at 11:28 AM.

  4. #4
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Also I'm pretty sure you have to do your rotations relative to the current orientation of the camera for it to work well. So these guys:
    m_vecRight = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
    m_vecUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
    m_vecLook = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
    are going to have to be rotated too.

    EDIT: (Never mind what I just said, you were already doing that)
    I guess I should ask what you mean by this
    that damn rolling up and down
    Last edited by bernt; 06-24-2010 at 11:35 AM.
    Consider this post signed

  5. #5
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    I mean to say that if the rolling is actual roll (rotation in the z-axis) then that is completely normal in a 6DOF rotation, especially with mouselook. When you pitch and then yaw, the yaw is going to go in a rotated plane and not the global, absolute-horizontal plane.
    Like when the Earth rotates on its axis - it's pitched slightly (~24 degrees), so when you have rotated 90 degrees, what used to be the pitch is now roll (so now pitch=0 degrees, roll=24 degrees). And rotating 90 degrees again restores the pitch/roll.
    Consider this post signed

  6. #6
    Registered User
    Join Date
    Jun 2010
    Posts
    4
    Yeah I understand the theory of the problem. But I know that it can also be avoided or negated in some way. That is what I am looking for. I know I have played plenty of games with a freely rotating camera that didnt roll to the side.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    But I know that it can also be avoided or negated in some way.
    I've tried quaternions, tried using D3DXMatrixLookAtLH.
    O_o

    It can be avoided. I've used quaternions to avoided the issue of "gimbal lock".

    If I understand my own code, I used quaternions to "accumulate" the transformations relative to "global" to produce a single transformation matrix to hand off to OpenGL.

    I can no longer follow the decade old source. It may be something completely different from what it seems.

    [Edit]
    In any event, a few searches offered up several parallel source files from tutorials using OpenGL and DirectX where one example exhibited "gimbal lock" and the other doesn't. I suggest you study such examples carefully.
    [/Edit]

    Soma

  8. #8
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    I know I have played plenty of games with a freely rotating camera that didnt roll to the side.
    So a standard FPS camera, then?
    All you need there is yaw and pitch.
    Code:
    vector_up = {0,0,1};
    vector_look = {cos(yaw)*cos(pitch), sin(yaw)*cos(pitch), sin(pitch)};
    or I think changing the order of rotations in your original code (maybe yaw goes first?) has an effect.
    Consider this post signed

  9. #9
    Registered User
    Join Date
    Jun 2010
    Posts
    4
    No, I have a working FPS Camera. I need a 6DOF camera. Changing the order of rotations does not affect the problem.

  10. #10
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Well I guess I really don't know what you're trying to do.

    AFAIK this isn't a gimbal lock problem anyway - you're free to rotate the camera any which way you please. And changing the order of rotations solves gimbal lock.

    I know I have played plenty of games with a freely rotating camera that didnt roll to the side.
    Could you name one of these games? Are you trying to do something like Shattered Horizon?
    Consider this post signed

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    AFAIK this isn't a gimbal lock problem anyway - you're free to rotate the camera any which way you please.
    From what I've understood, this is a "gimbal lock" issue.

    And changing the order of rotations solves gimbal lock.
    O_o

    No. If you are using simple matrix mathematics (Euler angels) to represent the transformations, then you have three options.

    If you are rotating around a single axis, the order can be changed to prevent "gimbal lock".

    If you are rotating around two axes, the order can be changed to prevent "gimbal lock".

    If you are rotating around three axes, the order is irrelevant as the "middle" rotation if aligned 90 degrees from center will result in "gimbal lock".

    Soma
    Last edited by phantomotap; 06-25-2010 at 11:09 AM. Reason: none of your business

  12. #12
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    If you are rotating around three axes, the order is irrelevant as the "middle" rotation if aligned 90 degrees from center will result in "gimbal lock".
    Okay, I'll admit that.
    But if your camera is rotating 90 degrees in a single step then you have bigger things to worry about. Besides, the symptoms that the OP is describing ("I still suffer from that damn rolling up and down when I rotate horizontaly") have nothing to do with gimbal lock.
    Consider this post signed

  13. #13
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    But if your camera is rotating 90 degrees in a single step then you have bigger things to worry about.
    o_O

    1) It doesn't have to be a "single step".

    2) If the transformations are accumulated and applied to a global state what appears to be a series of transformations may be a "single step".



    Besides, the symptoms that the OP is describing ("I still suffer from that damn rolling up and down when I rotate horizontaly") have nothing to do with gimbal lock.
    That sounds exactly like "gimbal lock" to me.



    [Edit]
    The following depends on perspective. It is just an example.

    Yes. The words "additional", "appear", and "perspective" are poor choices to describe what is a purely mathematical problem. I just couldn't think of better words. ;_;
    [/Edit]

    Consider using the rotation order `(Y,Z,X)'. If `Z' is a rotation 90 degrees from center, using Euler angle matrix mathematics, "additional" `Y' or `X' rotations would "appear" only as `Y' rotations.



    You may be right. The problem the OP is seeing may have nothing to do with "gimbal lock". It just sounds like it to me.

    Soma

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Use D3DXMatrixRotationAxis to rotate your up, right, and look vectors. After that construct the view matrix as:

    View matrix:
    Right.x,Up.x,Look.x,0.0f
    Right.y,Up.y,Look.y,0.0f
    Right.z,Up.z,Look.z,0.0f
    -dot(Pos,Right);,-dot(Pos,Up),-dot(Pos,Look),1.0f

    Yaw:
    Code:
    D3DXMATRIX T;
    D3DXMatrixRotationAxis(&T,&Up,units);
    D3DXVec3TransformCoord(&Right,&Right,&T);
    D3DXVec3TransformCoord(&Look,&Look,&T);
    Pitch:
    Code:
    D3DXMATRIX T;
    D3DXMatrixRotationAxis(&T,&Right,units);
    D3DXVec3TransformCoord(&Up,&Up,&T);
    D3DXVec3TransformCoord(&Look,&Look,&T);
    Roll:
    Code:
    D3DXMATRIX T;
    D3DXMatrixRotationAxis(&T,&Look,units);
    D3DXVec3TransformCoord(&Right,&Right,&T);
    D3DXVec3TransformCoord(&Up,&Up,&T);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. lock needed in this scenario?
    By George2 in forum C# Programming
    Replies: 1
    Last Post: 05-25-2008, 07:22 AM
  2. read write lock in C#
    By George2 in forum C# Programming
    Replies: 0
    Last Post: 04-16-2008, 08:49 AM
  3. Atomic Operations
    By Elysia in forum Windows Programming
    Replies: 27
    Last Post: 03-27-2008, 02:38 AM
  4. nested lock?
    By George2 in forum C# Programming
    Replies: 2
    Last Post: 03-23-2008, 08:33 AM
  5. Threading and mutex's
    By megatron09 in forum C++ Programming
    Replies: 14
    Last Post: 09-07-2006, 02:40 PM