Кватернионы - ›Углы Эйлера -› Проблема с матрицей вращения (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

person iondune    schedule 21.08.2012    source источник
comment
Если вам нужна собственная функция для экспериментов и вы знаете, что находится за кулисами, я дал ответ здесь.   -  person qrtLs    schedule 24.02.2016
comment
Кроме того: по крайней мере, с версии 0.9.9 glm::eulerAngles(q) возвращает результат в радианах. См. glm/gtc/quaternion.hpp.   -  person wardw    schedule 31.07.2020


Ответы (3)


Вы, наверное, уже догадались ... но

Какая последовательность 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», или рыскание, тангаж, крен, неверно.

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

person dinkelk    schedule 20.10.2012

Порядок умножения важен при работе с углами Эйлера. 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
person Markus Jarderot    schedule 21.08.2012
comment
Похоже, что это будет иметь те же проблемы. Углы Эйлера действительны только в том порядке, в котором они вычисляются. Помещение их в матрицы не отменяет этого факта. - person JCooper; 21.08.2012
comment
@Markus Я считал, что преобразование углов Эйлера в матрицу может быть проблемой, но до этого этапа есть несоответствие. Например, кватернионы (0,5, -0,5, 0,5, 0,5) и (0,707106, 0, 0,707106, 0) оба преобразуются в углы Эйлера (0, 90, 0), несмотря на то, что представляют собой два различных поворота (от + Z до + Y и От + Z до + X соответственно) при преобразовании непосредственно в матрицу. - person iondune; 22.08.2012

Я думаю, что результат уже в радианах, конвертировать не нужно.

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
person lbsweek    schedule 27.05.2020
comment
Да, это тоже заметил, и по крайней мере с версии 0.9.9 указано, что радианы возвращаются в _ 1_. Я предполагаю, что GLM изменил это в какой-то момент с момента первоначального вопроса в 2012 году. (Спорим, это было весело для некоторых). - person wardw; 31.07.2020