Próbuję wydobyć oś obrotu i kąt obrotu z macierzy obrotu 3x3. Obecnie korzystam z tej metody, ale nie jestem pewien, czy jestem na dobrej drodze. Mam problemy w innym miejscu w moim programie i myślę, że może to być przyczyną, ale nie jestem w stanie sam tego zweryfikować.

Pracuję z frameworkiem XNA, jeśli to pomaga. Przyjrzałem się użyciu Matrix.Decompose(), który zwraca skalę (vec3) tłumaczenie (vec3) i obrót (quaternion), ale nie jestem pewien, czy mogę wyodrębnić dane, których potrzebuję z tych wartości.

public static void MatrixRotationAxisAngle(Matrix m, ref float theta, ref Vector3 rot_axis) {
        float trace = m.M11 + m.M22 + m.M33;
        float cos_theta = 0.5f * (trace - 1.0f);
        if (cos_theta > 0.999999875f) {
            //allow some epsilon value
            theta = 0.0f;
            rot_axis = new Vector3(1.0f, 0.0f, 0.0f);
        } else if (cos_theta > -0.999999875f) {

            theta = (float)Math.Acos(cos_theta);
            rot_axis.X = (m.Up.Z - m.Forward.Y);
            rot_axis.Y = (m.Forward.X - m.Right.Z);
            rot_axis.Z = (m.Right.Y - m.Up.X);
            rot_axis.Normalize();

        } else { //angle within PI limits
            theta = (float)Math.PI;
            //find index of largest diag term in matrix
            int index = 0;

            if (m.M11 > m.M22 && m.M11 > m.M33) {
                index = 0;
            }
            if (m.M22 > m.M11 && m.M22 > m.M33) {
                index = 1;
            }
            if (m.M33 > m.M11 && m.M33 > m.M22) {
                index = 2;
            }

            switch (index) {
                case 0:
                    float ix = 1.0f / rot_axis.X;
                    rot_axis.X = (float)Math.Sqrt(m.M11 + 1.0f);
                    rot_axis.Y = m.M12 * ix;
                    rot_axis.X = m.M13 * ix;
                    break;
                case 1:
                    float iy = 1.0f / rot_axis.Y;
                    rot_axis.Y = (float)Math.Sqrt(m.M22 + 1.0f);
                    rot_axis.X = m.M21 * iy;
                    rot_axis.Z = m.M23 * iy;
                    break;
                case 2:
                    float iz = 1.0f / rot_axis.Y;
                    rot_axis.Z = (float)Math.Sqrt(m.M33 + 1.0f);
                    rot_axis.X = m.M31 * iz;
                    rot_axis.Y = m.M32 * iz;
                    break;
            }
            rot_axis.Normalize();
        }
    }
0
Matt Weichselbaum 8 luty 2012, 20:48

2 odpowiedzi

Najlepsza odpowiedź

Proponuję zajrzeć do pseudokodu z tego matematycznego wyjaśnienia (pdf), rozdział 2.1 (w zależności od Twojej matrycy). Z powodzeniem użyłem kodu w jednym z moich projektów i w moim przypadku zwrócił on prawidłowe wyniki.

0
Lennart 8 luty 2012, 20:56

Zobacz macierz w http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations .

Jak widać znalezienie theta jest dość łatwe. Użyj tego w innych równaniach, aby znaleźć inne kąty.

0
ElKamina 8 luty 2012, 20:57