# Thread: Gimbal Lock My Hated Foe

1. ## 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. 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.

3. 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?

4. 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

5. 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.

6. 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. 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.

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. 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.

9. No, I have a working FPS Camera. I need a 6DOF camera. Changing the order of rotations does not affect the problem.

10. 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?

11. 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

12. 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".
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.

13. 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.

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. 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);```