Преобразование глобальных иерархических ротаций в локальные и обратно

У меня есть иерархический скелет, в котором переводы и повороты выражаются в глобальном пространстве. Мне нужно преобразовать скелет в локальные координаты и обратно. У меня нет проблем с переводами, но я не могу заставить работать вращения.

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

Итак, мой код проходит через каждую кость и применяет преобразование до тех пор, пока у кости есть следующий родитель.

От глобального к локальному:

for(; iter != absolutePose.end(); iter++)
{
    if(hierarchy->find(iter->boneID) != hierarchy->end())
    {
        BoneID parentNodeID = hierarchy[iter->boneID];
        relativePose[iter->boneID].position.X = iter->position.X - absolutePose[parentNodeId].position.X;
        relativePose[iter->boneID].position.Y = iter->position.Y - absolutePose[parentNodeId].position.Y;
        relativePose[iter->boneID].position.Z = iter->position.Z - absolutePose[parentNodeId].position.Z;

                    ////Rotation Part/////////
        float pq[4] ={0.0,0.0,0.0,0.0};
        MatrixToQuaternion(absolutePose[parentNodeId].orientation, pq);

        irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
        irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);

        quat = quat.makeInverse();

        quat = quat*parentquat;

        float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
        QuaternionToMatrix(newQuat,relativePose[iter->first].orientation);

    }
    else // top bone
    {
        relativePose[iter->boneID].position.X = iter->position.X;
        relativePose[iter->boneID].position.Y = iter->position.Y;
        relativePose[iter->boneID].position.Z = iter->position.Z;

        relativePose[iter->boneID].orientation = iter->second.orientation;
    }
}

Затем от локального к глобальному:

for(; iter != relativePose.end(); iter++)
    {
        absolutePose[iter->boneID].position.position = iter->position;
        auto nextParent = hierarchy->find(iter->boneID);
        while(nextParent != hierarchy->end())
        {
            absolutePose[iter->boneID].position.X += relativePose[nextParent->boneID].position.X;
            absolutePose[iter->boneID].position.Y += relativePose[nextParent->boneID].position.Y;
            absolutePose[iter->boneID].position.Z += relativePose[nextParent->boneID].position.Z;

            ////Rotation part///
            float q[4] ={0.0,0.0,0.0,0.0};
            MatrixToQuaternion(relativePose[iter->boneID].orientation, q);

            float pq[4] ={0.0,0.0,0.0,0.0};
            MatrixToQuaternion(relativePose[nextParent->boneID].orientation, pq);
            irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
            irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);

            quat = parentquat*quat;

            float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
            QuaternionToMatrix(newQuat,absolutePose[iter->boneID].orientation);
            //////

            nextParent = hierarchy->find(nextParent->boneID);
        }
    }

У меня были проблемы с этим некоторое время, и я также пытался оставаться в матричном режиме и переключаться на углы Эйлера. Может ли кто-нибудь помочь мне понять, что я делаю неправильно?


person David Menard    schedule 10.12.2012    source источник


Ответы (1)


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

Рассмотрим (при условии, что ориентация применяется к векторам-столбцам справа):

q_1, q_2 и q_3 — это глобальные ориентации трех тел в цепочке. Если мы хотим использовать относительную ориентацию r_2 и r_3, тогда вы должны убрать поворот родителя из его потомков. Итак, мы видим, что q_2 = q_1 * r_2 и q_3 = q_1 * r_2 * r_3 = q_2 * r_3.

Найдите относительные значения, и вы получите r_3 = q_2' * q_3, а также r_2 = q_1. ' * q_2 (где q_2' — обратная матрица или кватернион).

Идя в другом направлении, чтобы преобразовать глобальный в локальный, вы должны помнить:

q_3 = q_1 * r_2 * r_3

Все родительские ориентации должны распространяться до конечного потомка. Таким образом, вам нужно либо использовать рекурсию, чтобы захватить все изменения ориентации от дочернего элемента до корня, либо вам нужно начать с родительского элемента, чтобы распространять/аккумулировать все изменения ориентации в каждой ссылке, когда вы проходите вниз через дочерние элементы.

В заключение я предполагаю, что вам также необходимо убедиться, что корневой узел понимает, что его relativePose равно его absolutePose. Иначе у вас будут проблемы.

person JCooper    schedule 10.12.2012
comment
У меня есть матрицы, содержащие абсолютное положение костей. Я хочу преобразовать их в относительные позиции. Ваш ответ, сделать это? Извините, новичок в 3D-программировании. - person majidarif; 17.09.2016