Как получить осевой угол из матрицы вращения?

Мне нужно получить некоторые данные из матрицы вращения openGL. Мне нужно получить эквивалентные углы Эйлера (уже сделал это), эквивалентный кватернион (сделал это, но просто скопировав его из Интернета) и эквивалентный угол оси.

Я не знаю, может ли матрица вращения быть выражена как одно вращение на определенный угол вокруг определенного вектора. Это эквивалентно? Если они есть, как я могу получить одно от другого?

Кроме того, я хотел бы лучше понять значение кватерниона и внутренности матрицы вращения. Куда мне пойти, чтобы узнать об этом?

2 ответа

Решение

Да, любая матрица вращения / единица кватерниона эквивалентна вращению вокруг одной оси. Если мы называем эту ось n и угол theta тогда кватернион для этого вращения:

[n * sin(theta / 2) cos(theta / 2)]

Чтобы восстановить это использование acos на w элемент кватерниона, чтобы получить theta / 2, После того, как у вас есть theta ты можешь разделить x,y а также z компонент с sin(theta / 2) реконструировать ось.

Вот функция, которая преобразует матрицу 3x3 в ось, угол (используя кватирование, так что, возможно, есть более эффективный способ обойти этот шаг).

void axis_angle_from_mat3(float r_axis[3], float *r_angle, float mat[3][3])
{
    float q[4];

    /* -------------------------------------------------------------------- */
    /* matrix to quaternion */
    double tr, s;
    float tmat[3][3];

    /* work on a copy */
    memcpy(tmat, mat, sizeof(tmat));

    /* normalize the matrix */
    int i;
    for (i = 0; i < 3; i++) {
        float d = (tmat[i][0] * tmat[i][0] + tmat[i][1] * tmat[i][1] + tmat[i][2] * tmat[i][2]);

        if (d > 1.0e-35f) {
            d = sqrtf(d);
            tmat[i][0] /= d;
            tmat[i][1] /= d;
            tmat[i][2] /= d;
        }
        else {
            tmat[i][0] = 0.0f;
            tmat[i][1] = 0.0f;
            tmat[i][2] = 0.0f;
            d = 0.0f;
        }
    }


    tr = 0.25 * (double)(1.0f + tmat[0][0] + tmat[1][1] + tmat[2][2]);

    if (tr > (double)1e-4f) {
        s = sqrt(tr);
        q[0] = (float)s;
        s = 1.0 / (4.0 * s);
        q[1] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
        q[2] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
        q[3] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
    }
    else {
        if (tmat[0][0] > tmat[1][1] && tmat[0][0] > tmat[2][2]) {
            s = 2.0f * sqrtf(1.0f + tmat[0][0] - tmat[1][1] - tmat[2][2]);
            q[1] = (float)(0.25 * s);

            s = 1.0 / s;
            q[0] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
            q[2] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
            q[3] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
        }
        else if (tmat[1][1] > tmat[2][2]) {
            s = 2.0f * sqrtf(1.0f + tmat[1][1] - tmat[0][0] - tmat[2][2]);
            q[2] = (float)(0.25 * s);

            s = 1.0 / s;
            q[0] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
            q[1] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
            q[3] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
        }
        else {
            s = 2.0f * sqrtf(1.0f + tmat[2][2] - tmat[0][0] - tmat[1][1]);
            q[3] = (float)(0.25 * s);

            s = 1.0 / s;
            q[0] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
            q[1] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
            q[2] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
        }
    }


    /* normalize the quat */
    float len;
    len = sqrtf(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
    if (len != 0.0f) {
        q[0] /= len;
        q[1] /= len;
        q[2] /= len;
        q[3] /= len;
    }
    else {
        q[1] = 1.0f;
        q[0] = q[2] = q[3] = 0.0f;
    }


    /* -------------------------------------------------------------------- */
    /* quaternion to axis angle */

    float ha, si;

    ha = acosf(q[0]);
    si = sinf(ha);

    *r_angle = ha * 2;

    if (fabsf(si) < FLT_EPSILON)
        si = 1.0f;

    r_axis[0] = q[1] / si;
    r_axis[1] = q[2] / si;
    r_axis[2] = q[3] / si;
}
Другие вопросы по тегам