Quaternion's and gimbal lock

Started by
3 comments, last by okonomiyaki 18 years, 11 months ago
I was experiencing gimbal lock with using RotateX*RotateY*RotateZ, so i switched to quaternion's and i'm still having the same problem when i'm trying to rotate my mesh. here is my code:

Quaternion rotquaternion = EulerToQuaternion(Geometry.DegreeToRadian(m_YAngle),
				Geometry.DegreeToRadian(m_XAngle),Geometry.DegreeToRadian(m_ZAngle));

device.Transform.World = Matrix.RotationQuaternion(rotquaternion);


m_XAngle, m_YAngle, m_ZAngle are incremented by the delta of the mouse movement. I only increment one of the angles at a time, i choose that angle by having a radio button to select whether to rotate around the X,Y, or Z axis. Here is my code for the EulerToQuaternion method.

private Quaternion EulerToQuaternion(float yaw, float pitch, float roll)
{
	float cr, cp, cy, sr, sp, sy, cpcy, spsy;

	cy = (float)Math.Cos(yaw/2);
	cp = (float)Math.Cos(pitch/2);
	cr = (float)Math.Cos(roll/2);

	sy = (float)Math.Sin(yaw/2);
	sp = (float)Math.Sin(pitch/2);
	sr = (float)Math.Sin(roll/2);

	cpcy = cp * cy;
	spsy = sp * sy;

	float w = cr * cpcy + sr * spsy;
	float x = cr * sp * cy - sr * cp * sy;
	float y = cr * cp * sy + sr * sp * cy;
	float z = sr * cpcy - cr * spsy;

	Quaternion retval = new Quaternion(x,y,z,w);
	return retval;
}


When my mesh is initially displayed i can rotate around any of the axis properly, but if i move around the X axis 270 deg. and the Y axis 270 deg. my X and Z movement until i move my Y axis again are around the same axis. What am I don't wrong? I've been struggling with this for days with a variety of Quaternion and Matrix calculations, and can't seem to get past this gimbal lock.
Advertisement
Even though you're using quaternions as an intermediate representation here, you're still using Euler angles to generate the quaternions. The use of Euler angles is where the gimbal lock is coming from. Quaternions aren't magical; they can't add back the degree of freedom that you removed earlier. Switch from an Euler angle representation to an axis-angle representation.

BTW, this is really more appropriate to the Math & Physics forum. Tell me if you want me to move it there.
As for representing the angles as an axis-angle representation, how do i go about doing that, I've been searching up and down the web, and have yet to find a good example.

here is my code for changing the angles:
private void Viewer_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e){	if(e.Button == MouseButtons.Left)	{		if(!m_fLeftMouseButtonDown)		{			m_fLeftMouseButtonDown = true;			m_iRelativeXPos = e.X;			m_iRelativeYPos = e.Y;		}		else		{			int xmovement = Math.Abs(e.X-m_iRelativeXPos);			int ymovement = Math.Abs(e.Y-m_iRelativeYPos);			if(m_rbXRotation.Checked)			{				if(e.X < m_iRelativeXPos)				{					m_XAngle += xmovement;				}				else if(e.X > m_iRelativeXPos)				{					m_XAngle -= xmovement;				}			}			if(m_rbYRotation.Checked)			{				if(e.Y < m_iRelativeYPos)				{					m_YAngle -= ymovement;				}				else if(e.Y > m_iRelativeYPos)				{					m_YAngle += ymovement;				}			}			if(m_rbZRotation.Checked)			{				if(e.Y < m_iRelativeYPos)				{					m_ZAngle -= ymovement;				}				else if(e.Y > m_iRelativeYPos)				{					m_ZAngle += ymovement;				}			}			if(m_XAngle>359)			{				m_XAngle = m_XAngle-360;			}			else if(m_XAngle<0)			{				m_XAngle = m_XAngle+360;			}			else if(m_YAngle>359)			{				m_YAngle = m_YAngle-360;			}			else if(m_YAngle<0)			{				m_YAngle = m_YAngle+360;			}			else if(m_ZAngle>359)			{				m_ZAngle = m_ZAngle-360;			}			else if(m_ZAngle<0)			{				m_ZAngle = m_ZAngle+360;			}			m_iRelativeXPos = e.X;			m_iRelativeYPos = e.Y;		}	}


m_rb* are the Radio Buttons.

PS: If you want to move it, that's fine.

Quote:Original post by browerjs
m_XAngle, m_YAngle, m_ZAngle are incremented by the delta of the mouse movement. I only increment one of the angles at a time, i choose that angle by having a radio button to select whether to rotate around the X,Y, or Z axis.

Like already pointed out, the problem is essentially you're still storing cumulative result of 'delta' rotations in Euler angles.

A possible way to fix it would be to discard your m_Angle variables altogether, and to store object orientation in single quaternion instead. Then, to alter this orientation build a temporary quaternion in accordance with delta of mouse movement, and multiply (or post-multiply depending on what type of rotation you want) the orientation quaternion of your object by it. You can then use this orientation quaternion to build the final matrix for your object.
Look at the thread that I started a couple days ago. It's a little scattered, but you can find what you need in there. Link

This topic is closed to new replies.

Advertisement