PDA

View Full Version : a to convert a matrix to a quaternion

jmanuelexe
06-06-2012, 04:45 PM
Hi everyone

I am new to the forum and just learning and in top of that I am not a native english speaker so please bear with me.

I am working with some animation and want to make a mesh move and rotate according to a bezier path I have manage to make it move but the way I came with to make it rotate is to make a lookat matrix look from the current to the next position in the bezier curve, I'm not very good at math so, I don't know how to make a lookat quaternion so I use lookat matrix and convert it to a quaternion. All my rotation need to be in quaternion because all the interpolation is already done that way my scene graph, I tested my lookat matrix and is fine but the conversion to quaternion is wrong the function I am using is the one I have been seen around the web every where

void CQuaternion::FromMatrix(CMatrix& m)
{
float trace = 1 + m.m11 + m.m22 + m.m33;
float s = 0;

if (trace > 0.0000001)
{
s = (float)sqrt(trace) * 2;
x = (m.m23 - m.m32) / s;
y = (m.m31 - m.m13) / s;
z = (m.m12 - m.m21) / s;
w = 0.25f * s;
}
else
{
if (m.m11 > m.m22 && m.m11 > m.m33)
{
// Column 0:
s = (float)sqrt(1.0 + m.m11 - m.m22 - m.m33) * 2;
x = 0.25f * s;
y = (m.m12 + m.m21) / s;
z = (m.m31 + m.m13) / s;
w = (m.m23 - m.m32) / s;
}
else if (m.m22 > m.m33)
{
// Column 1:
s = (float)sqrt(1.0 + m.m22 - m.m11 - m.m33) * 2;
x = (m.m12 + m.m21) / s;
y = 0.25f * s;
z = (m.m23 + m.m32) / s;
w = (m.m31 - m.m13) / s;
}
else
{
// Column 2:
s = (float)sqrt(1.0 + m.m33 - m.m11 - m.m22) * 2;
x = (m.m31 + m.m13) / s;
y = (m.m23 + m.m32) / s;
z = 0.25f * s;
w = (m.m12 - m.m21) / s;
}
}
}
and this is my lookat matrix method just to be more clear

void CMatrix::LookAt(CVector3 Pos, CVector3 Target, CVector3 y)
{
CVector3 x, z;

z = Target - Pos;
z.Normalize();

if(!z.x && z.y == 1.0f && !z.z)
{
Rotate(-1.5707963267948966f, 0.0f, 0.0f);
// Translate( Pos.x, Pos.y, Pos.z);
return;
}else
if(!z.x && z.y == -1.0f && !z.z)
{
Identity();
Rotate(1.5707963267948f, 0.0f, 0.0f);
// Translate( Pos.x, Pos.y, Pos.z);
return;
}

x.CrossProduct(z, y);
//x.Normalize();

y.CrossProduct(x, z);
y.Normalize();

m11 = x.x;
m12 = x.y;
m13 = x.z;

m21 = y.x;
m22 = y.y;
m23 = y.z;

m31 = z.x;
m32 = z.y;
m33 = z.z;

/*don't need position
m14 = m24 = m34 = 0;
m41 = Pos[0];
m42 = Pos[1];
m43 = Pos[2];*/
m44 = 1.0f;
}

tonyo_au
06-07-2012, 12:43 AM
You Matrix - Quaternion is quite different to mine. Are you sure the matrix is from OpenGL and not DirectX. You may need to find the original maths; mine is based on Allan and Mark Watt's "Advanced Animation and Rendering Techniques".

Dark Photon
06-07-2012, 06:36 AM
Looking at your MatrixToQuat code, looks nearly equivalent to what I'm using (regrouping terms, of course). Two differences. One is my if/elif conditions for the nested if (i.e. those in the trace <= 0 case) are >= instead of > (a minor point). And second is that for greater numerical stability, it's better for the first if if you check for (trace-1) > 0, not trace > 0. This corresponds to a w^2 > 1/4 case as opposed to the w^2 > 0. Additionally, this gets rid of the need for that 0.0000001 you're using to test against.

Note that the above routine presumes "row-major operator-on-the-right " math order (e.g. y=x*M), which generates the same results as OpenGL's "column-major operator-on-the-left" math order (y=M*x).

Haven't sifted your LookAt code. Cut it out of the picture and do some MatrixToQuat followed by QuatToMatrix -- make sure you get the same thing back out. That's a pretty good test.

jmanuelexe
06-07-2012, 07:34 AM
it was basically what you mansion darkphoton I just realize my FromMatrix was row major while the lookat matrix was column major the funny thing was that I thought about it and decided to swap the column before using my FromMatrix method and the result were wrong too until I realize that by negating the z vector of my lookat matrix plus swapping from row to column major on the FromMatrix works fine.