Archived

This topic is now archived and is closed to further replies.

Rudan

Matrix to quaternion

Recommended Posts

I''ve been trying to learn how to use quaternions for a while now, and I got a question: When creating a quaternion from a matrix, most of the examples I''ve seen are pretty long. However, I''ve seen this(or similiar) in a few places:
public final void set(Matrix4f m1)
{
w = Math.sqrt(1.0 + m1.m00 + m1.m11 + m1.m22) / 2.0;
double w4 = (4.0 * w);
x = (m1.m12 - m1.m21) / w4 ;
y = (m1.m20 - m1.m02) / w4 ;
z = (m1.m01 - m1.m10) / w4 ;
} 
I wonder if this works too? Probably not, why would not more people use it that''s the case? Thanks...

Share this post


Link to post
Share on other sites
This will work for some (but not all) matrices...

A safer version might be:



const float d = (1.0f + m1.m00 + m1.m11 + m1.m22);

if (d > 0.0f)
{
w = 0.5f * sqrtf(d);

const float temp = 0.25f / w;

x = (m1.m12 - m1.m21) * temp;
y = (m1.m20 - m1.m02) * temp;
z = (m1.m01 - m1.m10) * temp;
}
else
{
// fall back to long code...
}



As a general rule, you should always check that values you pass to square-root functions are >= 0, plus you don''t want a divide by zero.

Share this post


Link to post
Share on other sites
Damn, I was hoping to get away with the short one.
I guess I''ll have to learn the hard way to do it.
Thanks

Share this post


Link to post
Share on other sites
I don''t know if this works (I haven''t seriously tested it, in other words) but this is what I wrote a while back for my engine. The lower case ''s'' is what I use where most people use ''w''. ''v'' is a local vector. Val.v is a 16 element 1D array of floats.

void rQuat::operator = (const rMatrix4x4 &Val) {
float T, S;

T = Val.v[0] + Val.v[5] + Val.v[10] + 1.0f;
if(T > 0.0f) {
S = 0.5f / (float) rInternalSqrt(T);
s = 0.25f / S;
v.v[0] = S * (Val.v[9] - Val.v[6]);
v.v[1] = S * (Val.v[2] - Val.v[8]);
v.v[2] = S * (Val.v[4] - Val.v[1]);
} else {
if(Val.v[0] > Val.v[5]) {
if(Val.v[0] > Val.v[10]) { // Column 1
S = 0.5f / (float)rInternalSqrt(1.0f + Val.v[0] - Val.v[5] - Val.v[10]);
s = S * (Val.v[6] + Val.v[9]);
v.v[0] = S * 0.5f;
v.v[1] = S * (Val.v[1] + Val.v[4]);
v.v[2] = S * (Val.v[2] + Val.v[8]);
} else goto HandleCol3;
} else {
if(Val.v[5] > Val.v[10]) { // Column 2
S = 0.5f / (float)rInternalSqrt(1.0f + Val.v[5] - Val.v[0] - Val.v[10]);
s = S * (Val.v[2] + Val.v[8]);
v.v[0] = S * (Val.v[1] + Val.v[4]);
v.v[1] = S * 0.5f;
v.v[2] = S * (Val.v[2] + Val.v[8]);
} else goto HandleCol3;
}
return;
HandleCol3:
{ // Column 3
S = 0.5f / (float)rInternalSqrt(1.0f + Val.v[10] - Val.v[0] - Val.v[5]);
s = S * (Val.v[1] + Val.v[4]);
v.v[0] = S * (Val.v[2] + Val.v[8]);
v.v[1] = S * (Val.v[6] + Val.v[9]);
v.v[2] = S * 0.5f;
}
}
}


[Resist Windows XP''s Invasive Production Activation Technology!]

Share this post


Link to post
Share on other sites