Продолжаем разбираться с линейной алгеброй для 3D-приложений вместе с Александром Паничевым — ведущим разработчиком логики в UNIGINE. В прошлом уроке мы поговорили про предназначение математики в трехмерной графике и вспомнили основные операции над векторами. А в этом уроке переходим к более сложным темам: углам Эйлера и кватернионам. Углы Эйлера — это углы описывающие поворот абсолютно твердого тела в трехмерном евклидовом пространстве. Состоят из трех компонент (ψ, θ, φ), каждый из которых — угол вращения вокруг какой-то оси. Леонард Эйлер описывал вращение так, как на картинке ниже: Углы Z-X-Z Intrinsic (классические) Как видите, Эйлер описывал вращение по двум осям тремя компонентами. Сперва поворот по первой оси, затем по второй и в конце снова вращаем по первой оси. В уме он представлял себе некую юлу. На самом деле то, чем мы пользуемся игровых движках сейчас — это расширение, альтернативный вид углов Эйлера, придуманное Питером Тейтом и Джорджем Брайаном для авиации. Они описывают поворот по трем разным осям (более известным, как yaw->pitch->roll) в виде трех компонент. Визуально это выглядит как те самые всем известные вращающиеся вложенные кольца, которые так любят фантасты, если им надо показать двигатель космического корабля или древний артефакт инопланетян. Если рассматривать в общем, то вращения могут быть собственными/подвижными (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). Самолетам сильно крениться нельзя. А камеры игроков обычно вообще имеют нулевой крен. Как итог: ноль проблем с 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 веке была изобретена чудесная формула Кардано для этого: Опа. А что-то не сходится как-то. Нельзя взять корень из -121. Но ведь решение-то есть. Что делать? Рафаэль Бомбелли в 1572 году предложил сделать вид, что корень из отрицательного — это какое-то число. Мы, конечно, знаем, что таких чисел нет, но тем не менее, давайте представим, что оно существует и его, как обычные числа, можно складывать с другими, умножать, возводить в степень и тому подобное. Так и появились мнимые числа. Но… Как это работает? Как вообще можно себе представить квадратный корень из отрицательного числа? Как можно отнять 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! Получается, i2 = -1 имеет право на жизнь. Тогда выходит, что любое число z можно представить в виде пары чисел z = a + bi, где a,b — вещественные числа, а i — мнимая единица. Число a называют вещественной частью числа z, а,b — мнимой. Пару чисел a,b обычно представляют в виде радиус-вектора на комплексной плоскости, который формирует треугольник, где угол между вектором и осью абсцисс называют аргументом, а гипотенузу — расстоянием числа от нуля. Применяя обычную алгебру, получаем интересный эффект: Сложение и вычитание работает аналогично сложению и вычитанию векторов — мы просто смещаем точку на плоскости. Умножая комплексные числа друг на друга (с учетом особенностей мнимой единицы), наша точка начинает вращаться вокруг начала координат и масштабироваться. Представьте, что мы на лодке, движемся с курсом 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. Изначально для тех же кватернионов— как векторная и скалярная часть произведения двух кватернионов, скалярная часть которых равна нулю. «Вектор» и «скаляр» — термины, тоже пришедшие вместе с кватернионами. Анри Пуанкаре писал о кватернионах: «Их появление дало мощный толчок развитию алгебры; исходя от них, наука пошла по пути обобщения понятия числа, придя к концепциям матрицы и линейного оператора, пронизывающим современную математику. Это была революция в арифметике, подобная той, которую сделал Лобачевский в геометрии». Кватернионы изначально изобретались для решения пространственных задач математической физики. Мы используем их для вращения тел в 3D. Для представления вращения. Вместо 9 чисел mat3 можно использовать только 4! Экономия по памяти, быстрее чтение/запись. Создание кватерниона через представление ось-вращение очень быстрое. Вращение кватернионов (их перемножение) более вычислительно стабильно в сравнении с вращением через матрицы. Нет Gimbal Lock’а, как у углов Эйлера. В скелетной анимации для скиннинга. Есть еще такая штука, как Dual quaternion. Позволяет корректно искривлять руки-ноги (вершины) вдоль продольных осей. Анимация. Сделать плавный поворот между двумя кватернионами можно через Spherical interpolation. Через углы Эйлера делать корректную интерполяцию (по наикратчайшему пути) возможно только вокруг одной оси. Нет! (x, y, z, w)— это просто точка на поверхности гиперсферы (3-сферы). Точнее, 3-полусферы. Допустим, мы хотим использовать комплексное число чисто для вращений. У нас есть некий угол φ, надо перевести его в комплексное число, перемножать с другими, а потом получать результат обратно в виде угла. Или, например, мы хотим поворачивать кучу радиус-векторов на угол φ. Быстро. Что нужно сделать, чтобы перемножение двух комплексных чисел давало только поворот, без масштабирования? Умные люди определили, что: «При умножении комплексных чисел их модули перемножаются, а аргументы складываются». Значит, модуль z должен быть равен 1. Графически — быть точкой на поверхности круга. Значит, чтобы вращать точку в 2D (либо складывать углы φ1 + φ2), множитель надо определять как z = cosφ + isinφ! Обратите внимание, что ни вещественная, ни мнимая часть отдельно не формирует ни вектор, ни угол. Они работают в паре. Это проекции, тени вектора на осях. Изменяя одно число, для сохранения угла, надо менять пропорционально и второе. И при этом, у нас есть начало, нулевой угол: 1 + 0i. Тут все чуть сложнее. Представьте себе четыре перпендикулярных друг к другу оси, одна из которых— ось вещественных чисел. 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-приложениях. Оставайтесь на связи и подписывайтесь на наш блог!