Разбираем углы Эйлера и кватернионы.
![](https://habrastorage.org/getpro/habr/upload_files/c62/5c3/2c5/c625c32c5e2680c95b48baa71328dd7c.png)
Продолжаем разбираться с линейной алгеброй для 3D-приложений вместе с Александром Паничевым — ведущим разработчиком логики в UNIGINE. В прошлом уроке мы поговорили про предназначение математики в трехмерной графике и вспомнили основные операции над векторами. А в этом уроке переходим к более сложным темам: углам Эйлера и кватернионам.
Углы Эйлера
Углы Эйлера — это углы описывающие поворот абсолютно твердого тела в трехмерном евклидовом пространстве. Состоят из трех компонент (ψ, θ, φ), каждый из которых — угол вращения вокруг какой-то оси.
Леонард Эйлер описывал вращение так, как на картинке ниже:
![](https://habrastorage.org/getpro/habr/upload_files/8a9/659/c38/8a9659c38d18ef27bf3dc97d407484c0.png)
Углы Z-X-Z Intrinsic (классические)
Углы Тейта-Брайана
Как видите, Эйлер описывал вращение по двум осям тремя компонентами. Сперва поворот по первой оси, затем по второй и в конце снова вращаем по первой оси. В уме он представлял себе некую юлу.
На самом деле то, чем мы пользуемся игровых движках сейчас — это расширение, альтернативный вид углов Эйлера, придуманное Питером Тейтом и Джорджем Брайаном для авиации. Они описывают поворот по трем разным осям (более известным, как yaw->pitch->roll) в виде трех компонент. Визуально это выглядит как те самые всем известные вращающиеся вложенные кольца, которые так любят фантасты, если им надо показать двигатель космического корабля или древний артефакт инопланетян.
![](https://habrastorage.org/getpro/habr/upload_files/204/6b8/d02/2046b8d0279b8e9501f5a73dda465565.png)
Если рассматривать в общем, то вращения могут быть собственными/подвижными (Intrinsic) или внешними/статичными (Extrinsic).
Более того, они еще делятся на две группы:
Правильные углы Эйлера: z-x-z, x-y-x, y-z-y, z-y-z, x-z-x, y-x-y
Углы Тейта— Брайана (или yaw,pitch,roll): x-y-z, y-z-x, z-x-y, x-z-y, z-y-x, y-x-z
Так что существует 12 вариантов представления.
Как уже было сказано, в игровых движках используется
Yaw -> Pitch -> Roll. Говоря формальным языком— это Z-X-Y Intrinsic.
Это наиболее удобный вариант для большинства задач (не только для самолетов):
Z — рыскание (yaw). Удобно для компаса/карты, всегда можно понять, в какую сторону идет/летит/ползет что-то. Свободно от gimbal lock’а.
X — тангаж (pitch). Самолет обычно строго вверх или вниз не летит. Углы закидывания камеры игрока в играх тоже обычно ограничены градусами между -89 и +89. А, значит, gimbal lock’а тоже нет.
Y — крен (roll). Самолетам сильно крениться нельзя. А камеры игроков обычно вообще имеют нулевой крен.
![](https://habrastorage.org/getpro/habr/upload_files/2e4/e47/3e7/2e4e473e76ccf07d3c560e8113a5df4e.png)
![](https://habrastorage.org/getpro/habr/upload_files/df9/38c/be4/df938cbe4298c949a4aed50d1e9860f3.png)
Как итог: ноль проблем с gimbal lock’ом в типичных задачах!
Производительность:
Сложность перевода из углов Тейта-Брайана в матрицу: 3 sincos, 15 умножений, 4 сложения.
Сложность перевода из матрицы в углы Тейта-Брайана: 2 atan2, 1 asin.
Кватернион
Кватернион — это система гиперкомплексных чисел, образующая векторное пространство размерностью четыре над полем вещественных чисел.
Ничего не понятно?
Еще раз: Кватернион — это система гиперкомплексных чисел, образующая векторное пространство размерностью четыре над полем вещественных чисел.
Разберем по порядку:
1. Гиперкомплексные числа — элементы алгебраических структур, строящихся в результате обобщения понятия о числе после комплексных чисел. Можно сказать, что это конечномерные алгебры над полем вещественных чисел (то есть числа, над которыми есть пара операций по типу сложения и умножения).
1.1. Комплексные числа — числа вида z = a + bi,
где a,b — вещественные числа,
i — мнимая единица (то есть число, у которого i2 = -1)
2. Векторное пространство размерностью четыре над полем вещественных чисел — это Vec4.
А как вообще появились мнимые единицы?
Когда-то давно была задача решения кубического уравнения: x3 + px + q = 0
Если чутка подшаманить, то выходит следующее: x3 = -px - q или x3 = kx + b (слева — кубическая парабола, справа — прямая).
Графически решение сводится к поиску пересечения графика кубической параболы и прямой. Визуально ясно, что любая прямая пересекает кубическую параболу в 1, 2 или 3 точках. То бишь, решение есть всегда.
И в 16 веке была изобретена чудесная формула Кардано для этого:
![](https://habrastorage.org/getpro/habr/upload_files/c02/089/d70/c02089d709519f92278a8e5d26c24441.png)
Опа. А что-то не сходится как-то. Нельзя взять корень из -121. Но ведь решение-то есть. Что делать?
Рафаэль Бомбелли в 1572 году предложил сделать вид, что корень из отрицательного — это какое-то число. Мы, конечно, знаем, что таких чисел нет, но тем не менее, давайте представим, что оно существует и его, как обычные числа, можно складывать с другими, умножать, возводить в степень и тому подобное. Так и появились мнимые числа.
Но… Как это работает? Как вообще можно себе представить квадратный корень из отрицательного числа?
А «отрицательное число» — это вообще что?
![](https://habrastorage.org/getpro/habr/upload_files/486/9d0/e2e/4869d0e2e6a63a73694edec6cc575f36.png)
Как можно отнять 4 коровы от 3? Как можно иметь меньше, чем ничего? В 18 веке до сих пор считалось, что отрицательные числа— это чушь и от них надо избавляться.
Хоть это и теоретическое число, оно обладает полезными свойствами. Через них можно описывать всякие связи (задолженность, например: -20 долг, 50 доход. Итог: -20 + 50 = 30 руб в кармане).
Знаки плюса и минуса автоматически фиксируют направление — вам не нужно целое предложение, чтобы описать изменения после каждой транзакции. С мнимыми числами та же история. Они «нормальны» настолько же, как и все другие. Если «существуют» -1, 1/3 и 0, то давайте представим, что существует и некое число i, где i2 = -1.
Иными словами, умножая i на себя же, мы получаем -1: i*i = -1. Странные новые идеи могут быть чрезвычайно полезными.
Визуальное понимание отрицательных и мнимых чисел
Что означает уравнение x2 = 9?
1 * x2 = 9 или 1 * x * x = 9
Что можно подставить в x? 3 и -3. То бишь, «3 раза по 3 или 3 раза по -3 и переворачиваем результат».
А теперь подумаем про x2 = -1:
1 * x * x = -1
Что можно подставить сюда? Сюда не подставить ни положительное, ни отрицательное число… А что, если… Вращать? Бред, но что если представить х как «поворот 90 градусов», тогда применив х дважды, мы совершим поворот на 180 градусов на координатной оси, и 1 обернется в -1!
![](https://habrastorage.org/getpro/habr/upload_files/d44/c7d/528/d44c7d5288ba59df05ac9c7f13075a42.png)
![](https://habrastorage.org/getpro/habr/upload_files/c2b/2a6/70c/c2b2a670cefcf5d4e1bd3918d8110a75.png)
Понимание комплексных чисел
Получается, i2 = -1 имеет право на жизнь. Тогда выходит, что любое число z можно представить в виде пары чисел z = a + bi, где a,b — вещественные числа, а i — мнимая единица. Число a называют вещественной частью числа z, а,b — мнимой.
Пару чисел a,b обычно представляют в виде радиус-вектора на комплексной плоскости, который формирует треугольник, где угол между вектором и осью абсцисс называют аргументом, а гипотенузу — расстоянием числа от нуля.
Применяя обычную алгебру, получаем интересный эффект:
Сложение и вычитание работает аналогично сложению и вычитанию векторов — мы просто смещаем точку на плоскости.
Умножая комплексные числа друг на друга (с учетом особенностей мнимой единицы), наша точка начинает вращаться вокруг начала координат и масштабироваться.
![](https://habrastorage.org/getpro/habr/upload_files/014/441/1c1/0144411c1ec367ca285e1619ce0a8420.png)
Представьте, что мы на лодке, движемся с курсом 3 единицы на Восток каждые 4 единицы на Север. Хотим изменить свой курс на 45 градусов против часовой стрелки. Каким будет новый курс?
z1 = 3 + 4i
z2 = 1 + i
Перемножаем: z1*z2 = (3 + 4i)(1 + i) = 3 + 3i + 4i + 4i2 = 3 + 7i + 4(-1) = -1 + 7i
Наш новый ориентир: 1 единица на Запад и 7 единиц на Север. И это без всяких синусов и косинусов! Буквально за пару секунд!
Можно сказать, что комплексные числа объединяют алгебру, геометрию и тригонометрию в единое целое.
Так что же такое в итоге Кватернион?
Итак, кватернион — это вот такое выражение:
q = xi + yj + zk + w,
где x,y,z,w — вещественные, а i,j,k — мнимые числа, которые обладают следующими свойствами:
i2 = j2 = k2 = ijk = -1
и, соответственно:
ij=k jk=i ki=j
ji=-k kj=-i ik=-j
Если присмотреться, то это очень сильно похоже на cross product:
x×y=z y×z=x z×x=y
y×x=−z z×y=−x x×z=−y
И не спроста: кватернионы придумал Уильям Гамильтон в 1843 году. Он же 3 года спустя придумал dot и cross product. Изначально для тех же кватернионов— как векторная и скалярная часть произведения двух кватернионов, скалярная часть которых равна нулю. «Вектор» и «скаляр» — термины, тоже пришедшие вместе с кватернионами.
![](https://habrastorage.org/getpro/habr/upload_files/039/8ac/02a/0398ac02ad5447b7462d32cd1564cf48.png)
Анри Пуанкаре писал о кватернионах: «Их появление дало мощный толчок развитию алгебры; исходя от них, наука пошла по пути обобщения понятия числа, придя к концепциям матрицы и линейного оператора, пронизывающим современную математику. Это была революция в арифметике, подобная той, которую сделал Лобачевский в геометрии».
Кватернионы изначально изобретались для решения пространственных задач математической физики. Мы используем их для вращения тел в 3D.
Где и для чего используем кватернион?
Для представления вращения. Вместо 9 чисел mat3 можно использовать только 4! Экономия по памяти, быстрее чтение/запись.
Создание кватерниона через представление ось-вращение очень быстрое.
Вращение кватернионов (их перемножение) более вычислительно стабильно в сравнении с вращением через матрицы.
Нет Gimbal Lock’а, как у углов Эйлера.
![](https://habrastorage.org/getpro/habr/upload_files/6a5/a46/efe/6a5a46efeb1baf6dfdc58d16d94ed1cb.png)
В скелетной анимации для скиннинга. Есть еще такая штука, как Dual quaternion. Позволяет корректно искривлять руки-ноги (вершины) вдоль продольных осей.
![](https://habrastorage.org/getpro/habr/upload_files/3e5/479/af5/3e5479af57d4ffd214f26e27ae89ea9c.png)
![](https://habrastorage.org/getpro/habr/upload_files/894/38b/34f/89438b34f502ba5f3a52d27cc493700b.png)
Анимация. Сделать плавный поворот между двумя кватернионами можно через Spherical interpolation. Через углы Эйлера делать корректную интерполяцию (по наикратчайшему пути) возможно только вокруг одной оси.
![](https://habrastorage.org/getpro/habr/upload_files/b01/f7d/031/b01f7d031b2921b14e60922c631096bb.png)
Получается, xyz — это ось, а w — это угол?
Нет! (x, y, z, w)— это просто точка на поверхности гиперсферы (3-сферы). Точнее, 3-полусферы.
Начнем с 2D
Допустим, мы хотим использовать комплексное число чисто для вращений. У нас есть некий угол φ, надо перевести его в комплексное число, перемножать с другими, а потом получать результат обратно в виде угла. Или, например, мы хотим поворачивать кучу радиус-векторов на угол φ. Быстро.
Что нужно сделать, чтобы перемножение двух комплексных чисел давало только поворот, без масштабирования? Умные люди определили, что: «При умножении комплексных чисел их модули перемножаются, а аргументы складываются».
Значит, модуль z должен быть равен 1. Графически — быть точкой на поверхности круга. Значит, чтобы вращать точку в 2D (либо складывать углы φ1 + φ2), множитель надо определять как z = cosφ + isinφ!
Обратите внимание, что ни вещественная, ни мнимая часть отдельно не формирует ни вектор, ни угол. Они работают в паре. Это проекции, тени вектора на осях. Изменяя одно число, для сохранения угла, надо менять пропорционально и второе.
И при этом, у нас есть начало, нулевой угол: 1 + 0i.
Переходим в 3D
Тут все чуть сложнее. Представьте себе четыре перпендикулярных друг к другу оси, одна из которых— ось вещественных чисел. xyzw — это точка на поверхности гиперсферы с постоянным расстоянием до центра в 1, а угол вращения — проекция xyz из мнимых осей на ось вещественных чисел.
Так что кватернион можно собрать таким образом (через axis-angle):
q = cos(φ/2) + u sin(φ/2), где u — единичный вектор из (x,y,z)
Если модуль (x,y,z,w) не равен 1, то вместе с вращением мы начнем еще и масштабировать точки/вектора, двигая их по спирали. Так что НИКОГДА не меняйте w компоненту отдельно от xyz!
Во-первых, масштабируете, а во-вторых, угол вращения будет зависеть от текущих значений (x,y,z).
Почему φ/2? Потому что вращение произвольного вектора v делается через qvq-1. Там это связано с тем, что v — (x,y,z), а q — (x,y,z,w). После qv повернутый v перестает быть чисто «мнимым», а имеет скалярную часть. Необходимо домножить на q-1, чтобы вернуть повернутый v в «мнимую» часть.
* * *
Вот и подошел к концу второй урок из запланированных трех. В третьем, завершающем, уроке разберем объемную тему матриц в 3D-приложениях. Оставайтесь на связи и подписывайтесь на наш блог!