GLM: Эйлеровы углы к кватерниону

12

Я надеюсь, что вы знакомы с математикой GL ( GLM ), потому что у меня есть проблема, я не могу сломать:

У меня есть набор углов Эйлера, и мне нужно выполнить плавную интерполяцию между ними. Лучший способ - преобразовать их в кватернионы и применить алгоритм SLERP.

У меня вопрос, как инициализировать glm :: quaternion с помощью углов Эйлера, пожалуйста?

Я читаю документацию GLM снова и снова, но не могу найти уместного Quaternion constructor signature, что бы взять три угла Эйлера. Самым близким, который я нашел, является функция angleAxis () , принимающая значение угла и ось для этого угла. Обратите внимание, что я ищу способ, как разобрать RotX, RotY, RotZ.


К вашему сведению, это подпись функции metNioned angleAxis () :

detail::tquat< valType > angleAxis (valType const &angle, valType const &x, valType const &y, valType const &z)
Bunkai.Satori
источник

Ответы:

13

Я не знаком с GLM, но в отсутствие функции прямого преобразования углов Эйлера в кватернионы вы можете использовать для нее функции «вращения вокруг оси» (например, «angleAxis»).

Вот как (псевдокод):

Quaternion QuatAroundX = Quaternion( Vector3(1.0,0.0,0.0), EulerAngle.x );
Quaternion QuatAroundY = Quaternion( Vector3(0.0,1.0,0.0), EulerAngle.y );
Quaternion QuatAroundZ = Quaternion( Vector3(0.0,0.0,1.0), EulerAngle.z );
Quaternion finalOrientation = QuatAroundX * QuatAroundY * QuatAroundZ;

(Или вам может потребоваться переключить эти кватернионные умножения вокруг, в зависимости от порядка, в котором должны применяться ваши углы поворота Эйлера)

С другой стороны, просматривая документацию GLM, вы можете конвертировать углы Эйлера -> matrix3 -> quaternion следующим образом:

toQuat( orient3( EulerAngles ) )
Тревор Пауэлл
источник
хороший ответ, потому что он не так однозначен в отношении порядка применения.
Ричард Фабиан
@Trevor: +1, привет, Тревор, спасибо за хороший ответ. Это выглядит как наиболее практичное решение здесь. Я могу легко переключаться между порядком умножения вращения. Возможно, именно количество комбинаций является причиной, по которой преобразование углов Эйлера в кватерионы недоступно в GLM.
Bunkai.Satori
Хотя все ответы хорошие и ценные, на мой взгляд, это самый практичный ответ . Я хотел бы отметить его как принятый ответ .
Bunkai.Satori
@Trevor: В Quaternion finalOrientation = QuatAroundX * QuatAroundY * QuatAroundZ; какой тип умножения вы имели в виду? Я удивлен, что GLM не перегружает operator *умножение кватернионов, поэтому, возможно, мне придется выполнять умножение вручную .
Bunkai.Satori
3
@Bunkai концепция умножения кватернионов похожа на умножение матриц, она не является ни точечным, ни перекрестным произведением. Если вы хотите понять использование кватернионов, а затем привыкнуть к матрицам и понять углы осей, их основная концепция очень похожа на кватернионы, математика немного более продвинута, но как только вы поняли углы осей, то кватернионы не далеко больше.
Майк Земдер
16
glm::quat myquaternion = glm::quat(glm::vec3(angle.x, angle.y, angle.z));

Где angleнаходится glm::vec3вмещающий шаг, рыскание, крен соответственно.

PS. Если есть сомнения, просто зайдите в заголовки и посмотрите. Определение можно найти в glm / gtc / quaternion.hpp:

explicit tquat(tvec3<T> const & eulerAngles) {
        tvec3<T> c = glm::cos(eulerAngle * value_type(0.5));
    tvec3<T> s = glm::sin(eulerAngle * value_type(0.5));

    this->w = c.x * c.y * c.z + s.x * s.y * s.z;
    this->x = s.x * c.y * c.z - c.x * s.y * s.z;
    this->y = c.x * s.y * c.z + s.x * c.y * s.z;
    this->z = c.x * c.y * s.z - s.x * s.y * c.z;    
}

Для чего quatиспользуется тип float tquat?

deceleratedcaviar
источник
Это довольно двусмысленно, в каком порядке они будут применяться? Эйлера - это упорядоченные вращения, и конструктор кватернионов здесь, похоже, не заботится об этом.
Ричард Фабиан
Определение функции точно такое же, как у вас; Я отправил это в своем ответе, если это имело значение.
замедленная
не порядок аргументов, порядок применения ротации. Мой ответ содержит порядок XYZ, взятый из статьи в Википедии, однако мы используем порядок приложений ZYX в моей старой компании, а YZX - в моей текущей. угол x по-прежнему является первым значением в списке векторов / аргументов во всех случаях, но фактическое результирующее преобразование не совпадает.
Ричард Фабиан
Я исправил свой ответ на вращение Quat, чтобы вы могли видеть, как вы можете легко изменить порядок. По умолчанию он принимает XYZ, но вы можете легко это изменить.
замедленная
2
-1 за не упоминание порядка вращения, что очень важно для вопроса
Maik Semder
7

Решение в википедии: http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles

используя это:

sx = sin(x/2); sy = sin(y/2); sz = sin(z/2);
cx = cos(x/2); cy = cos(y/2); cz = cos(z/2);

q( cx*cy*cz + sx*sy*sz,
   sx*cy*cz - cx*sy*sz,
   cx*sy*cz + sx*cy*sz,
   cx*cy*sz - sx*sy*cz ) // for XYZ application order

q( cx*cy*cz - sx*sy*sz,
   sx*cy*cz + cx*sy*sz,
   cx*sy*cz - sx*cy*sz,
   cx*cy*sz + sx*sy*cz ) // for ZYX application order

Конструкторы для кватерниона, заданные Эйлером (где применение вращения XYZ или ZYX). Однако это только две из шести возможных комбинаций углов Эйлера. Вам действительно нужно выяснить, в каком порядке построены углы Эйлера при преобразовании в матрицу преобразования. Только тогда можно определить решение.

В старой компании, в которой я работал, у нас был Z вперед (как у большинства видеокарт), поэтому заказ приложений был ZYX, а в моей нынешней компании ось Y направлена ​​вперед, а Z вверх, поэтому наш заказ приложений - YZX. Этот порядок - порядок, в котором вы умножаете свои кватернионы вместе, чтобы сгенерировать ваше окончательное преобразование, и порядок вращений имеет значение, если умножения не являются коммутативными.

Ричард Фабиан
источник
1
+1, привет и спасибо за отличный ответ. Поскольку я использую OpenGL , значение Z выходит за пределы экрана. В моем приложении я выполняю порядок умножения ZYX . Изначально я думал, что в GLM эта функциональность доступна, но я вижу, они еще не реализовали ее, поэтому , как вы рекомендуете , одной из альтернатив является создание преобразования вручную .
Bunkai.Satori
Это лучший ответ здесь.
плазмацел
1
vec3 myEuler (fAngle[0],fAngle[1],fAngle[2]);
glm::quat myQuat (myEuler);

Угол должен быть в радианах!

Carlos
источник
2
Это была шутка? Или вы просто не читали другие ответы (особенно Даниеля)?
Крис говорит восстановить Монику