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