Translating from a quaternion?

OK hello everyone again.

You may or may not know that I have been struggling with a quaternion rotation system in my 3D OpenGL game written in C.

I managed to work it out (with the help of a few helpful developers) but I have now another problem: how to translate.

I was told to ‘find the z vector from the matrix’ and translate along that but that doesn’t work.

How do I work out a set of coordinates to translate to when I have a rotation matrix and quaternion?

P.S.


        shipRotation.z = pitch   * DEG_TO_RAD ;
	shipRotation.y = heading  * DEG_TO_RAD ;
	shipRotation.x = roll * DEG_TO_RAD;
	

	
	q1 =  eulerToQuat(shipRotation);
	
	
	
	q2 = quatMult(q1,q2);
        shipMatrix = quatToMatrix(q2);
	
	glMultMatrixf(  shipMatrix.m );


The components m[3,0], m[3,1] and m[3,2] are the traslation x, y and z. Simply set them before using the matrix in glMultMatrixf

Hmmm. I don’t think I explained my problem. I don’t have a specific x,y and z values, but an airspeed variable. I want my ship to travel along the Z axis (locally, like an aeroplane).

I could use things like sin(pitch) but I’m not sure about these and quaternions.
Here’s my current code:

	translation.x +=  shipMatrix.m[8];
	translation.y +=  shipMatrix.m[9];
	translation.z +=  shipMatrix.m[10];
	
	xp = translation.x * airspeed ;
	yp = translation.y * airspeed ;
	zp = translation.z * airspeed ;
	
	
	glTranslatef(-xp ,-yp,zp);

I was told in my other thread to:

translate along the Z vector of the matrix, that is matrix[8] matrix[9] and matrix[10].

But my code acts strangely.

So, you need the “forward” vector that a Mat3x3 has.


struct Mat3{
	vec3 GetForwardVector(){
		return vec3(a20,a21,a22);
	}
	
	union {
		struct {
			float a00, a10, a20;
			float a01, a11, a21;
			float a02, a12, a22;
		};
		
		float mat_array[9];
	};
};


You have this:


	
struct MyObject{
	Quaternion Q;
	vec3 position;
	
	float speed;
	...
	
	void update();
};

void MyObject::update(){
	Mat3 rotation = Q.toMatrix3();
	vec3 forwardVector = rotation.GetForwardVector();
	position += speed*forwardVector;
}

Sorry to seem stupid but I only know C and I’m not really sure what the code does. My matrix is stored in the struct like this:


typedef struct 
	{
		float m[16];
	}matrix;

But if I change my code to this:

	shipRotation.z = pitch   * DEG_TO_RAD ;
	shipRotation.y = heading  * DEG_TO_RAD ;
	shipRotation.x = roll * DEG_TO_RAD;
	

	
	q1 =  eulerToQuat(shipRotation);
	
	
	
	q2 = quatMult(q1,q2);
	
	translation.x +=  shipMatrix.m[12];
	translation.y +=  shipMatrix.m[13];
	translation.z +=  shipMatrix.m[14];
	
	xp += translation.x * airspeed ;
	yp += translation.y * airspeed ;
	zp += translation.z * airspeed ;
	
	
	glTranslatef(xp ,yp,zp);
	

Nothing happens. I can still rotate fine but no translation.

This code:


	translation.x +=  shipMatrix.m[12];
	translation.y +=  shipMatrix.m[13];
	translation.z +=  shipMatrix.m[14];

shouldn’t be?..


	translation.x =  shipMatrix.m[12];
	translation.y =  shipMatrix.m[13];
	translation.z =  shipMatrix.m[14];

I tried that but still nothing happens.

Anyone?

I already wrote what I think you should code; I use very similar code successfully.

Well it doesn’t seem to work for me. Here’s my exact code:


			
	shipRotation.z = pitch   * DEG_TO_RAD ;
	shipRotation.y = heading  * DEG_TO_RAD ;
	shipRotation.x = roll * DEG_TO_RAD;
	

	
	q1 =  eulerToQuat(shipRotation);
	
	
	
	q2 = quatMult(q1,q2);
	

	
	

//glTranslatef(0.0f,0.0f,airspeed );
	
	//q1 = eulerToQuat(shipRotation);	
	//quatMultiply(q1, q2, q2);
	
	//q2.w = 1.0;
	shipMatrix = quatToMatrix(q2);
	
	
	


	
	
	glLoadMatrixf(  shipMatrix.m );
	
	
	translation.z =  shipMatrix.m[8];
	translation.y =  shipMatrix.m[9];
	translation.x =  shipMatrix.m[10];
	
	xp +=  airspeed * translation.z;
	yp += airspeed * translation.y;
	zp +=   airspeed * translation.x;
	
	
	glTranslatef(xp ,yp,zp);

        drawWorld();


And all of the quaternion functions:

quaternion eulerToQuat(vec3D euler) 
{
	quaternion quat;
	float sinAngle;
	float angle;
	
	vec3D axis;
	
	float c1 = cos((euler.y* DEG_TO_RAD) / 2);
	float c2 = cos((euler.x* DEG_TO_RAD) / 2);
	float c3 = cos((euler.z* DEG_TO_RAD) / 2);
	float s1 = sin((euler.y* DEG_TO_RAD) / 2);
	float s2 = sin((euler.x* DEG_TO_RAD) / 2);
	float s3 = sin((euler.z* DEG_TO_RAD) / 2);
	
			quat.w = (c1 * c2 *  c3 - s1 *  s2 *  s3);
			quat.x = (s1 *  s2 *  c3 +c1 *  c2 *  s3);
			quat.y = (s1  * c2  * c3 + c1 *  s2 *  s3);
			quat.z = (c1 *  s2 *  c3 - s1 *  c2 *  s3);
	
	return quat;
}

quaternion axisAngleToQuat(vec3D axis, float angle) 
{
	quaternion quat;
	float sinAngle;
	
	angle *= 0.5f;
	axis = normVec3D(axis);
	sinAngle = sin(angle);
	quat.x = (axis.x * sinAngle);
	quat.y = (axis.y * sinAngle);
	quat.z = (axis.z * sinAngle);
	quat.w = cos(angle);
	
	return quat;


}


quaternion conjugateQuat(quaternion quat)
{
	quaternion ans;
	
	ans.x = -quat.x;
	ans.y = -quat.y;
	ans.z = -quat.z;
	
	return ans;
}


quaternion quatMult(quaternion  quat1, quaternion quat2) 
{
	vec3D vector1, vector2, cross;
	quaternion quat3;
	float angle;
	
	vector1.x = quat1.x;
	vector1.y = quat1.y;
	vector1.z = quat1.z;
	vector2.x = quat2.x;
	vector2.y = quat2.y;
	vector2.z = quat2.z;
	angle = (quat1.w * quat2.w) - dotprodVec3D(vector1, vector2);
	
	cross = crossprodVec3D(vector1, vector2);
	vector1.x *= quat2.w;
	vector1.y *= quat2.w;
	vector1.z *= quat2.w;
	vector2.x *= quat1.w;
	vector2.y *= quat1.w;
	vector2.z *= quat1.w;
	
	quat3.x = vector1.x + vector2.x + cross.x;
	quat3.y = vector1.y + vector2.y + cross.y;
	quat3.z = vector1.z + vector2.z + cross.z;
	quat3.w = angle;
	
	return quat3;
}


matrix quatToMatrix(quaternion quat) {
	matrix qmatrix;	
	
	qmatrix.m[0]  = (1.0f - (2.0f * ((quat.y * quat.y) + (quat.z * quat.z))));
	qmatrix.m[1]  =         (2.0f * ((quat.x * quat.y) + (quat.z * quat.w)));
	qmatrix.m[2]  =         (2.0f * ((quat.x * quat.z) - (quat.y * quat.w)));
	qmatrix.m[3]  = 0.0f;
	qmatrix.m[4]  =         (2.0f * ((quat.x * quat.y) - (quat.z * quat.w)));
	qmatrix.m[5]  = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.z * quat.z))));
	qmatrix.m[6]  =         (2.0f * ((quat.y * quat.z) + (quat.x * quat.w)));
	qmatrix.m[7]  = 0.0f;
	qmatrix.m[8]  =         (2.0f * ((quat.x * quat.z) + (quat.y * quat.w)));
	qmatrix.m[9]  =         (2.0f * ((quat.y * quat.z) - (quat.x * quat.w)));
	qmatrix.m[10] = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.y * quat.y))));
	qmatrix.m[11] = 0.0f;
	qmatrix.m[12] = 0.0f;
	qmatrix.m[13] = 0.0f;
	qmatrix.m[14] = 0.0f;
	qmatrix.m[15] = 1.0f;
	
	return qmatrix;
}

AHA! I think the problem is that your matrices are row major whereas opengl matrices are column major. So I should be using 8,9,10 (My matrices are 4x4) but still something is wrong.

However if we look at NeHe’s code:

	GLfloat Matrix[16];

	glRotatef(m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
	glRotatef(m_PitchDegrees, 1.0f, 0.0f, 0.0f);

	glGetFloatv(GL_MODELVIEW_MATRIX, Matrix);

	m_DirectionVector.i = Matrix[8];
	m_DirectionVector.k = Matrix[10];

	glLoadIdentity();

	glRotatef(m_PitchDegrees, 1.0f, 0.0f, 0.0f);

	glGetFloatv(GL_MODELVIEW_MATRIX, Matrix);
	m_DirectionVector.j = Matrix[9];

	glRotatef(m_HeadingDegrees, 0.0f, 1.0f, 0.0f);

	// Scale the direction by our speed.
	m_DirectionVector *= m_ForwardVelocity;

	// Increment our position by the vector
	m_Position.x += m_DirectionVector.i;
	m_Position.y += m_DirectionVector.j;
	m_Position.z += m_DirectionVector.k;

	// Translate to our new position.
	glTranslatef(-m_Position.x, -m_Position.y, m_Position.z);

He seems to get the 9 element of the matrix before he changes the matrix…