Sign in to follow this  
EonStrife

Quaternion and Axis Angle

Recommended Posts

Hi guys, I'm little confused with the Quaternion and Axis Angle. In GameTutorials.com's MD3 animation tutorial, they use Quaternion. I reuse the quaternion class from them, that's I make my own glRotate function(which is axis angle), then convert it to quaternion, then to matrix and applied it :
void CQuaternion::CreateMatrix(float *pMatrix)
{
        //This is GameTutorials.com's
	if(!pMatrix) return;
	pMatrix[ 0] = 1.0f - 2.0f * ( y * y + z * z );
	pMatrix[ 1] = 2.0f * ( x * y - w * z );
	pMatrix[ 2] = 2.0f * ( x * z + w * y );
	pMatrix[ 3] = 0.0f;
	pMatrix[ 4] = 2.0f * ( x * y + w * z );
	pMatrix[ 5] = 1.0f - 2.0f * ( x * x + z * z );
	pMatrix[ 6] = 2.0f * ( y * z - w * x );
	pMatrix[ 7] = 0.0f;
	pMatrix[ 8] = 2.0f * ( x * z - w * y );
	pMatrix[ 9] = 2.0f * ( y * z + w * x );
	pMatrix[10] = 1.0f - 2.0f * ( x * x + y * y );
	pMatrix[11] = 0.0f;
	pMatrix[12] = 0;
	pMatrix[13] = 0;
	pMatrix[14] = 0;
	pMatrix[15] = 1.0f;
}

void CQuaternion::MyRotate(float angle, float sb_x, float sb_y, float sb_z)
{
        //This is my own glRotatef
	float l, rad, m_now[16]={0};
	rad = angle* PI / 180;
	w = cos(rad/2);
	x = sb_x * sin(rad/2);
	y = sb_y * sin(rad/2);
	z = sb_z * sin(rad/2);
	l=sqrt(w * w + x * x + y * y + z * z);
	w/=l; x/=l; y/=l; z/=l;
	CreateMatrix(m_now);
	glMultMatrixf(m_now);
}

The problem is, when I switch between using OpenGL's glRotate and my own glRotate the object rotates to opposite direction !
int DrawGLScene(GLvoid)
{
	CQuaternion k;
	rtri=45;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
        glTranslatef(0.0f ,0.f, -6.0f);
	
	if(flag==true)
	{
		glTranslatef(1.5f,0.0f,0.0f);
                glRotatef(rtri,0.0f,0.0f,1.0f);
        }
	else
	{
		glTranslatef(1.5f,0.0f,0.0f);
                k.MyRotate(rtri, 0.0f, 0.0f, 1.0f);
	}

	glBegin(GL_TRIANGLES);
        glColor3f(1.0f,0.0f,0.0f);
        glVertex3f( 0.0f, 1.0f, 0.0f);
        glColor3f(0.0f,1.0f,0.0f);
        glVertex3f(-1.0f,-1.0f, 0.0f);
        glColor3f(0.0f,0.0f,1.0f);
        glVertex3f( 1.0f,-1.0f, 0.0f);
        glEnd();
        return TRUE;
}


BTW, I got Matrix and Quaternion FAQ from somewhere in the net before. It has formula to convert axis angle -> quaternion -> matrix(Q56 then Q54). What funny is, suppose I rotate 45 degree in Z axis, the matrix result for (axis angle -> quaternion -> matrix) is transpose of Z-axis rotation matrix(Q30). Thanks. [Edited by - EonStrife on July 9, 2005 7:08:55 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by EonStrife
What funny is, suppose I rotate 45 degree in Z axis, the matrix result for (axis angle -> quaternion -> matrix) is transpose of Z-axis rotation matrix(Q30).


Because the math itself is funny ;) Did you know, that inversion of an orthonormal matrix is the same as its transposition? Rotation matrix is orthonormal.

Your result simply says that your angle is somewhat negated. That could happen, when you are calculating it with arcus cosine. Cosine is symmetric along Y axis, so the angle returned by acos is always > 0, cause there's nothing that the function could do to distinguish between angle and -angle. You probably want to have -angle.
That, of course, is not a general rule. It depends on what your routine of calculating angle is. Where does it come from? (I assumed you made dot and acos, but it could be otherwise).

Another possibility is that you are using OpenGL right-handed coordinates, and the original third-party snippet assumed it will work in left-handed. Sine would have been negated, resulting in reversed rotation.

This is my rotation code, for comparison:

// rotation matrix
INL xmat rotation (cxquat & q) {
xmat m = identityMat();

((float*)&m)[0] = 1.0f - (q.y*q.y + q.z*q.z)*2.0f; // 0,0
((float*)&m)[4] = (q.x*q.y - q.w*q.z)*2.0f; // 0,1
((float*)&m)[8] = (q.x*q.z + q.w*q.y)*2.0f; // 0,2

((float*)&m)[1] = (q.x*q.y + q.w*q.z)*2.0f; // 1,0
((float*)&m)[5] = 1.0f - (q.x*q.x + q.z*q.z)*2.0f; // 1,1
((float*)&m)[9] = (q.y*q.z - q.w*q.x)*2.0f; // 1,2

((float*)&m)[2] = (q.x*q.z - q.w*q.y)*2.0f; // 2,0
((float*)&m)[6] = (q.y*q.z + q.w*q.x)*2.0f; // 2,1
((float*)&m)[10] = 1.0f - (q.x*q.x + q.y*q.y)*2.0f;// 2,2

return m;
}



Cheers.
/def

EDIT:
Quote:

w = cos(rad/2);
x = sb_x * sin(rad/2);
y = sb_y * sin(rad/2);
z = sb_z * sin(rad/2);
l=sqrt(w * w + x * x + y * y + z * z);
w/=l; x/=l; y/=l; z/=l;

This would be already unit lenght, if I'm calculating right(if sb_xyz is unit-lenght), so there's no point in re-normalizing.

Share this post


Link to post
Share on other sites
I think deffer is right. Notice that in his quaternion-to-matrix code, the pluses and minuses in the non-diagonal terms are reversed from yours. Try switching those and see if that doesn't fix the problem, as your current matrix will (I think) produce left-handed rotations in a right-handed coordinate system (the opposite of OpenGL).

Also, I assume you're normalizing in the quat function to allow for non-unit-length rotation axes. I'm not positive about this, but I think if you're going to do this, you need to normalize the axis before constructing the quaternion, rather than normalizing the quaternion after it's already constructed.

Share this post


Link to post
Share on other sites
Hmm...I suppose the problem is with the Quaternion to Matrix.

However, I got that conversion method from GameTutorial.com's MD3 animation tutorial(http://www.gametutorials.com/gtstore/pc-79-1-md3-animation.aspx), and using that conversion(which is suppose to produce left-handed matrix although OpenGL is righthanded) the MD3 object(it uses Lara Croft) moves correctly !

And, no, I don't use arc cosine, I followed Q30, Q54, and Q56 from Matrix and Quaternion FAQ and there's no Arc Cosine.
Thanks :)

Share this post


Link to post
Share on other sites
Hold out the thumb, forefinger, and middle finger of your right hand such that your thumb points right, your forefinger points right, and your middle finger points straight back at you. Think of your thumb as X, your forefinger as Y, and your middle finger as Z. This is a right-handed coordinate system.

Now, put your left hand out too, with your thumb and forefinger pointing in the same directions as those on your right hand (not mirrored). Your middle finger will end up pointing away from you. This is a left-handed coordinate system.

Share this post


Link to post
Share on other sites
I always had problems remembering the difference between a right and left handed coordinate system, until I read "Real time 3D terrain engines using C++ and DirectX 9"

The way it was explained in that book was as follows. In a right handed coordinate system, anything heading along the positive z axis is headed right for you, anything heading along the positive z axis in a left handed system has gone past, or left you.

Share this post


Link to post
Share on other sites
Quote:
Original post by Oxyacetylene
The way it was explained in that book was as follows. In a right handed coordinate system, anything heading along the positive z axis is headed right for you, anything heading along the positive z axis in a left handed system has gone past, or left you.

The problem is, that's not necessarily the case. Right/left-handedness refers to the relative ordering of the axes, not the absolute directions. A coordinate system with positive X to the left, positive Y up, and positive Z away from you, would still be a right-handed coordinate system.

Share this post


Link to post
Share on other sites
Well, thanks for the reply guys. I know what's left/right handed coordinate system.
The problem is, why does that left-handed Q-to-M conversion work well in OpenGL in that MD3 tutorial ?

Notes that some part of the animation algorithm from that tutorial :
-Get rotation matrix for current frame
-Get rotation matrix for next frame
-Change both matrices to Quaternion(Actually, the Matrix-to-Quaternion algorithm they use is also left-handed too)
-Interpolate the quaternion
-Change the interpolated quaternion to matrix and multiply to Modelview matrix.

Oh wait, the left handed Q-to-M conversion works because M-to-Q conversion also left-handed ?

Share this post


Link to post
Share on other sites
BTW, I have more question, this is about Quaternion and Axis Angle.Anyway, everybody said that interpolation with Quaternion is smoother than Axis Angle and Euler Representation, but they didn't say why ? Can anybody explain this to me ?
Thanks.

Share this post


Link to post
Share on other sites
Quote:
BTW, I have more question, this is about Quaternion and Axis Angle.Anyway, everybody said that interpolation with Quaternion is smoother than Axis Angle and Euler Representation, but they didn't say why ? Can anybody explain this to me ?
The 'real' answer is pretty deep mathematically, and certainly not something I'm qualified to explain. Practically speaking, however, two desirable characteristics of an interpolation method are often a) angular velocity is constant over the interpolation, and b) the interpolation takes the shortest path. With Euler angles or axis-angle pairs, it is difficult to meet both these criteria. With both matrices and quaternions there is a clear solution. The matrix form, however, is fairly expensive compared to the equivalent quaternion 'power' form. Furthermore, it can be shown that the quaternion power form is equivalent to the standard slerp algorithm for interpolating an N-dimensional vector over the unit sphere. We end up with an algorithm that is quite efficient, as far as interpolation goes.

If constant velocity is not important, there are alternatives, but quaternion nlerp() still fairs quite well, as it is simply the normalized average of the input quaternions and fairly quick to compute.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this