Main Menu

Quaternion Math

Started by overdunn, October 25, 2012, 03:41:57

Previous topic - Next topic

overdunn

Hi, I have a sprite class and I'm using a custom quaternion class to determine it's rotation, but the angle is wrong and the sprite is stretched. Let me first say that my code works fine using matrix transformations (that is, storing X, Y, and Z rotation angles and applying the appropriate glRotatefs()). I want to improve my rotation code by using quaternions. All I have done is comment out the lines using matrix rotations and replace them with a single glMultMatrix() with my quaternion generated matrix. My math for generating a matrix from my quaternion is very simple:
   
public void rotateY(float angle) {
	w = (float)Math.cos(angle*SDGlobal.DEG_TO_RAD/2);
	x = 0;
	y = 1; // only rotate around the y
	z = 0;
    }

    public static FloatBuffer matrixFromQuaternion(SDQuaternion q) {
	FloatBuffer matrix = BufferUtils.createFloatBuffer(16);
	float x2 = q.x*q.x, y2 = q.y*q.y, z2 = q.z*q.z;
	matrix.put( new float [] { (1-2*z2-2*y2), (2*q.x*q.y+2*q.w*q.z), (2*q.x*q.z-2*q.w*q.y), 0,
		(2*q.x*q.y-2*q.w*q.z), (1-2*z2-2*x2),  (2*q.y*q.z+2*q.w*q.x), 0,
		(2*q.x*q.z+2*q.w*q.y), (2*q.y*q.z-2*q.w*q.x), (1-2*y2-2*x2), 0,
		0, 0, 0, 1 } );
	matrix.flip();
	return matrix;
    }


All I'm trying to do for now is rotate a sprite 90 degrees, the same way I do with matrixes. In my render() function for my sprite:
...
glTranslatef(pos().x, pos().y, pos().z);
glMultMatrix( SDQuaternion.matrixFromQuaternion(_rotationQ) );
glBegin(GL_TRIANGLE_STRIP);
{
    for (int i = 0; i < _vertex.length; i++) {
	glTexCoord2f(_texCoords[i].x, _texCoords[i].y);
	glVertex3f(_vertex[i].x, _vertex[i].y, _vertex[i].z);
    }
}
glEnd();
...


I call my rotate function once in the constructor (which again, works fine if I replace glMultMatrix with glRotatef):
_rotateQ.setYRotation(90);


Any ideas what I'm doing wrong with my math/matrix conversion?

Thanks!

overdunn

Okay, calling my normalize function after the rotation seems to have removed the stretching, but I my angle is still not 90. It's like 75sh...here's my normalize code:
    
    public static double magnitude(SDQuaternion q) {
	return Math.sqrt(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z);
    }
    
    public static void normalize(SDQuaternion q) {
	float m = (float)magnitude(q);
	if (m == 0) {
	    SDLog.err("divide by 0");
	    return;
	}
	q.w /= m;
	q.x /= m;
	q.y /= m;
	q.z /= m;
    }
   

overdunn

Aaaaand...I solved it!

I tracked it down shortly after I noticed normalize made a difference. For anyone wondering how/what went wrong:

I wanted to rotate about the y-axis, so I set it 1. This makes sense for a 3D axis, but a quarternion actually represents 4D space. Therefore, all components must add to 1. Setting y=1 and then normalizing tipped me off that something needed to change about my axis setting. The correct Y-axis was:

q.y= Math.sin( DEG_TO_RAD*angle/2 );


Hope this helps somebody else