PDA

View Full Version : Translating from a quaternion?

mikeynovemberoscar
01-29-2010, 12:47 PM
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 );

Yomboprime
01-31-2010, 03:51 PM
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

mikeynovemberoscar
02-02-2010, 01:57 PM
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.

Ilian Dinev
02-03-2010, 06:23 PM
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;
}

mikeynovemberoscar
02-04-2010, 09:29 AM
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.

Yomboprime
02-05-2010, 11:48 PM
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];

mikeynovemberoscar
02-06-2010, 03:23 AM
I tried that but still nothing happens.

mikeynovemberoscar
02-09-2010, 11:52 AM
Anyone?

Ilian Dinev
02-09-2010, 01:30 PM
I already wrote what I think you should code; I use very similar code successfully.

mikeynovemberoscar
02-12-2010, 12:24 PM
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;
}

mikeynovemberoscar
02-17-2010, 03:53 AM
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...