2015-05-31 1 views
1

Я скопировал код для преобразования 3D-матрицы вращения в кватернионы и обратно. Тот же код используется в jMonkey (я просто переписал его в мой класс C++). Однако он не работает должным образом (по крайней мере, не так, как я ожидал.)матрица вращения к кватерниону (и обратно), что не так?

например. Я сделал это испытание:

matrix (a,b,c): 
a : 0.707107 0.000000 0.707107 
b : 0.000000 -1.000000 0.000000 
c : -0.707107 0.000000 0.707107 

>>> ortonormality: 
a.a b.b c.c 1.000000 1.000000 1.000000 
a.b a.c b.c 0.000000 0.000000 0.000000 

>>> matrix -> quat 
quat: 0.000000 0.594604 0.000000 0.594604 norm(quat) 0.707107 

>>> quat -> matrix 
matrix (a,b,c): 
a: 0.000000 0.000000 1.000000 
b: 0.000000 1.000000 0.000000 
c: -1.000000 0.000000 0.000000 

Я думаю, что проблема вmatrix -> quat, потому что я использовал quat -> matrix процедуру раньше, и он работал отлично. Также странно, что кватернион из ортонормированной матрицы не является унитарным.

matrix -> quat процедура

inline void fromMatrix(TYPE m00, TYPE m01, TYPE m02, TYPE m10, TYPE m11, TYPE m12,  TYPE m20, TYPE m21, TYPE m22) { 
    // Use the Graphics Gems code, from 
    // ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z 
    TYPE t = m00 + m11 + m22; 
    // we protect the division by s by ensuring that s>=1 
    if (t >= 0) { // by w 
     TYPE s = sqrt(t + 1); 
     w = 0.5 * s; 
     s = 0.5/s;     
     x = (m21 - m12) * s; 
     y = (m02 - m20) * s; 
     z = (m10 - m01) * s; 
    } else if ((m00 > m11) && (m00 > m22)) { // by x 
     TYPE s = sqrt(1 + m00 - m11 - m22); 
     x = s * 0.5; 
     s = 0.5/s; 
     y = (m10 + m01) * s; 
     z = (m02 + m20) * s; 
     w = (m21 - m12) * s; 
    } else if (m11 > m22) { // by y 
     TYPE s = sqrt(1 + m11 - m00 - m22); 
     y = s * 0.5; 
     s = 0.5/s; 
     x = (m10 + m01) * s; 
     z = (m21 + m12) * s; 
     w = (m02 - m20) * s; 
    } else { // by z 
     TYPE s = sqrt(1 + m22 - m00 - m11); 
     z = s * 0.5; 
     s = 0.5/s; 
     x = (m02 + m20) * s; 
     y = (m21 + m12) * s; 
     w = (m10 - m01) * s; 
    } 
} 

quat -> matrix процедура

inline void toMatrix(MAT& result) const { 
     TYPE r2 = w*w + x*x + y*y + z*z; 
     //TYPE s = (r2 > 0) ? 2d/r2 : 0; 
     TYPE s = 2/r2; 
     // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs 
     // will be used 2-4 times each. 
     TYPE xs = x * s; TYPE ys = y * s; TYPE zs = z * s; 
     TYPE xx = x * xs; TYPE xy = x * ys; TYPE xz = x * zs; 
     TYPE xw = w * xs; TYPE yy = y * ys; TYPE yz = y * zs; 
     TYPE yw = w * ys; TYPE zz = z * zs; TYPE zw = w * zs; 
     // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here 
     result.xx = 1 - (yy + zz); 
     result.xy =  (xy - zw); 
     result.xz =  (xz + yw); 
     result.yx =  (xy + zw); 
     result.yy = 1 - (xx + zz); 
     result.yz =  (yz - xw); 
     result.zx =  (xz - yw); 
     result.zy =  (yz + xw); 
     result.zz = 1 - (xx + yy); 
}; 

жаль TYPE, VEC, MAT, QUAT это часть класса tepmpltes ... должен быть заменен или float, Vec3f, Mat3f, Quat3f.

EDIT:

Я также проверил, если я получаю такое же поведение с jMonkey непосредственно (в случае, если я сделал ошибку в Java на C++ преобразования). И я - с помощью этого кода:

Matrix3f Min = new Matrix3f(0.707107f, 0.000000f, 0.707107f, 0.000000f, -1.000000f, 0.000000f, -0.707107f, 0.000000f, 0.707107f ); 
    Matrix3f Mout = new Matrix3f(); 
    Quaternion q = new Quaternion(); 
    q.fromRotationMatrix(Min); 
    System.out.println(q.getX()+" "+q.getY()+" "+q.getZ()+" "+q.getW()); 
    q.toRotationMatrix(Mout); 
    System.out.println(Mout.get(0,0) +" "+Mout.get(0,1)+" "+Mout.get(0,2)); 
    System.out.println(Mout.get(1,0) +" "+Mout.get(1,1)+" "+Mout.get(1,2)); 
    System.out.println(Mout.get(2,0) +" "+Mout.get(2,1)+" "+Mout.get(2,2)); 

ответ

2

Ваша матрица:

matrix (a,b,c): 
a : 0.707107 0.000000 0.707107 
b : 0.000000 -1.000000 0.000000 
c : -0.707107 0.000000 0.707107 

ортогонален, но это не матрица вращения. Матрица вращения имеет определитель 1; ваша матрица имеет определитель -1 и, следовательно, improper rotation.

I Ваш код, скорее всего, правильный и проблема в ваших данных. Попробуйте с реальной матрицей вращения.

+0

ОК, это проблема, спасибо. Я не знал, что левая/правая система имеет значение для кватернионов :) –

+0

Технически поворот не волнует, если вы используете левую или правую систему координат, если вы согласны. Проблема возникает, когда вы составляете (т. Е. Умножаете) свое вращение с преобразованием системы координат из одной руки в другую (отражение). – rhashimoto

Смежные вопросы