Hello~
I ve been stuck for a while on this problem, which is probably trivial to most of you, and I can’t quite understand if I am doing something wrong or not. As the topic says, I need to make a routine to convert a rotation matrix into a quaternion and back. I understood this operation is totally reversible and it is possible to recreate the original matrix from the quaternion, provided it was an orthonormal matrix, besides some approximation error. Now… this is the output I get if I try to run some conversions:
Matr1:
-0.947701, 0.11744351, 0.29676592
-0.07347012, 0.8245853, -0.56094676
0.31058836, 0.5534132, 0.7728316
q:
0.82485795, -0.55718, 0.006911218, 0.09545682
Matr2:
0.98168045, -0.16517824, -0.094971724
0.14977506, 0.36087695, 0.9205082
-0.11777481, -0.91786927, 0.37900543
q2:
0.824858, -0.55718, 0.006911215, 0.09545682
matr3:
0.98168045, -0.16517824, -0.09497173
0.14977507, 0.36087692, 0.9205082
-0.11777481, -0.9178693, 0.37900537
That output was generated running this code:
Matrix3f matr1=new Matrix3f(-0.947701f, -0.07347012f, 0.31058836f,
0.11744351f, 0.8245853f, 0.5534132f,
0.29676595f, -0.56094676f, 0.7728316f );
matr1.orthonormalize();
matr1.traceMe("Matr1");
Quaternion q=matr1.getRotationMatrix4f().toQuaternion();
q.traceMe("q");
Matrix3f matr2=q.toMatrix3f();
matr2.traceMe("Matr2");
Quaternion q2=matr2.toQuaternion();q2.traceMe("q2");
Matrix3f matr3=q2.toMatrix3f(); matr3.traceMe("matr3");
And the function I used are the following:
public Matrix3f orthonormalize(){
Vector3f u1=new Vector3f(m[0], m[1], m[2]);
Vector3f u2=new Vector3f(m[3], m[4], m[5]);
Vector3f u3=new Vector3f(m[6], m[7], m[8]);
Vector3f w1 = u1.normalize();
Vector3f w2 = (u2.subtract(w1.proj(u2))).normalize();
Vector3f w3 = (u3.subtract(w1.proj(u3)).subtract(w2.proj(u3))).normalize();
m[0]=w1.x;
m[1]=w1.y;
m[2]=w1.z;
m[3]=w2.x;
m[4]=w2.y;
m[5]=w2.z;
m[6]=w3.x;
m[7]=w3.y;
m[8]=w3.z;
return this;
}
and…
public Quaternion toQuaternion(){
normalize();
double tr, s;
float[][] mat=new float[3][3];
float[] q=new float[4];
int i=0;
for(int x=0; x<3; x++){
for(int y=0; y<3; y++){
mat[x][y]=m[i++];
}
}
tr= 0.25*(1.0+mat[0][0]+mat[1][1]+mat[2][2]);
if(tr>0) {
s= Math.sqrt( tr);
q[0]= (float)s;
s*= 4.0;
q[1]= (float)((mat[1][2]-mat[2][1])/s);
q[2]= (float)((mat[2][0]-mat[0][2])/s);
q[3]= (float)((mat[0][1]-mat[1][0])/s);
} else {
q[0]= 0.0f;
s= -0.5*(mat[1][1]+mat[2][2]);
if(s>0) {
s= Math.sqrt(s);
q[1]= (float)s;
q[2]= (float)(mat[0][1]/(2*s));
q[3]= (float)(mat[0][2]/(2*s));
} else {
q[1]= 0.0f;
s= 0.5*(1.0-mat[2][2]);
if(s>FLT_EPSILON) {
s= Math.sqrt(s);
q[2]= (float)s;
q[3]= (float)(mat[1][2]/(2*s));
} else {
q[2]= 0.0f;
q[3]= 1.0f;
}
}
}
return new Quaternion(q[1], q[2], q[3], q[0]).normalize();
}
and finally…
public Matrix3f toMatrix3f(){
/* float x2 = x * x;
float y2 = y * y;
float z2 = z * z;
float xy = x * y;
float xz = x * z;
float yz = y * z;
float wx = w * x;
float wy = w * y;
float wz = w * z;
float[] values=new float[9];
values[0]=1.0f - 2.0f * (y2 + z2);
values[1]=2.0f * (xy + wz);
values[2]=2.0f * (xz - wy);
values[3]=2.0f * (xy - wz);
values[4]=1.0f - 2.0f * (x2 + z2);
values[5]=2.0f * (yz + wx);
values[6]=2.0f * (xz + wy);
values[7]=2.0f * (yz - wx);
values[8]=1.0f - 2.0f * (x2 + y2); */
double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
float[] values=new float[9];
q0= M_SQRT2 * w;
q1= M_SQRT2 * x;
q2= M_SQRT2 * y;
q3= M_SQRT2 * z;
qda= q0*q1;
qdb= q0*q2;
qdc= q0*q3;
qaa= q1*q1;
qab= q1*q2;
qac= q1*q3;
qbb= q2*q2;
qbc= q2*q3;
qcc= q3*q3;
Matrix3f tmp= new Matrix3f(
(float)(1.0-qbb-qcc),
(float)(qdc+qab),
(float)(-qdb+qac),
(float)(-qdc+qab),
(float)(1.0-qaa-qcc),
(float)(qda+qbc),
(float)(qdb+qac),
(float)(-qda+qbc),
(float)(1.0-qaa-qbb));
return tmp.orthonormalize();
}
The test case output shows the first quaternion derived matrix is different from the original one, but it yeilds the same quaternion, and the system is stable for further loops. So I ve been wondering if these 2 matrices would by chance give the same rotation, and I ve tested this in my graphics engine, but of course, they do not. I don’t see what I did wrong, after having tried to implement and re-implement this a couple times, using different sources, books, tutorials, websites etc, the one I posted is a translation of blender3d’s conversion functions.
Thanks to whoever reads this ~