Кватернионы → Углы Эйлера → Проблемы с матрицей вращения (GLM)

Я пишу программу, которая загружает файл, содержащий описание сцены, а затем отображает его с помощью OpenGL. Я использую GLM для всех своих математических операций. Вращения в файле сцены хранятся в формате кватернионов. Мои системы управления сценой принимают вращения для объектов в виде углов Эйлера, и эти углы позже преобразуются в матрицу вращения при рисовании.

Таким образом, процесс загрузки приводит к поворотам кватернионов, преобразует их в углы Эйлера для хранения в моем классе объектов, а затем преобразует эти углы Эйлера в матрицы вращения для рисования. Я использую функции glm:: eulerAngles и glm:: eulerAngleYXZ (соответственно) для выполнения этих двух операций.

Однако я получаю неправильные результаты. Например, если я правильно понимаю, что кватернион {0,500 -0,500 0,500 0,500} (что W X Y Z) должен описывать поворот с помощью стрелки от оси + Z до оси + Y. Однако, когда я запускаю программу, я получаю стрелку, указывающую вдоль оси + X.

Я бы предположил, что есть некоторые недостатки в моем понимании кватернионов, но я могу получить ожидаемые результаты, пропуская форму угла посредника эйлеров. Преобразуя кватернион непосредственно в матрицу вращения с помощью glm:: toMat4, я получаю поворот, который указывает мою + Z стрелку в сторону + Y.

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

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f; // eulerAngleYXZ takes radians but eulerAngles returns degrees
glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
// transform1 rotates a +Z arrow so that it points at +X

glm::quat q(.5, -.5, .5, .5);
glm::mat4 transform2 = glm::toMat4(q);
// transform2 rotates a +Z arrow so that it points at +Y

Ответ 1

Вероятно, вы уже поняли это... но

Какую последовательность eulerAngle выполняет функция:

glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;

вернуться? Если он не возвращает явно последовательность "YXZ", вы не сможете использовать следующую функцию правильно:

glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);

Ваша переменная 'euler' должна быть того же типа последовательности, что и указанная вами функция, чтобы преобразовать ее в матрицу вращения.

После просмотра здесь выглядит так: функция "glm:: eulerAngles" возвращает "XYZ" как шаг, рыскание и рулон. Таким образом, считая, что они являются "YXZ", или "рысканье", шаг, рулон неверен.

Как уже говорилось, с углами Эйлера и матрицами вращения порядок имеет значение!

Ответ 2

Порядок умножения важен при работе с углами Эйлера. YXZ и XYZ производят очень разные вращения.

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

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;

glm::mat4 transformX = glm::eulerAngleX(euler.x);
glm::mat4 transformY = glm::eulerAngleY(euler.y);
glm::mat4 transformZ = glm::eulerAngleZ(euler.z);

glm::mat4 transform1 =
    transformX * transformY * transformZ; // or some other order