О поворотах в играх по-простому
Всем привет! Меня зовут Григорий Дядиченко, я CTO & Founder White Label Games. Уже больше десяти лет занимаюсь разработкой на Unity, и за это время повороты успели побыть для меня и магией, и проклятием, и наконец просто инструментом — но через очень специфическую дорогу.
Сталкивались ли вы с ситуацией, когда персонаж в вашей игре на повороте начинает странно дёргаться? Или, скажем, плавная интерполяция между двумя ориентациями вдруг проходит «через всю комнату»? А может, вы открыли учебник по компьютерной графике, увидели формулу q · v · q⁻¹ со словами «и тут, конечно же, всё интуитивно понятно» — и захлопнули книжку?
Все эти симптомы — про одно и то же. Про повороты в трёхмерном пространстве и про то, как их хранить в памяти, чтобы не плакать. Конечно же, главный герой здесь — кватернионы. Но рассматривать их в вакууме, как делают в большинстве статей, мне кажется неправильным. Поэтому разберём всё семейство: углы Эйлера, матрицы, ось-угол, кватернионы. С плюсами и минусами, без выбора любимчика заранее.
И главное — поймём, откуда у кватернионов четыре числа. Не «возьмите как факт», а действительно поймём, через геометрию двух отражений. Заодно разберём, почему формула q · v · q⁻¹ — сэндвич, а не одно умножение, и почему поворот на 360° в кватернионном мире не равен исходному состоянию.
Часть 1. Разминка: 2D, где всё ещё просто
Чтож, прежде чем разбирать кватернионы, давайте разогреемся. Поворот в 2D — это, по сути, одно число: угол. И это та редкая страница в статье, где «одно число» — действительно одно число, а не четыре с условиями нормировки.
Но даже здесь, в плоскости, у поворота уже два «лица». Можно описывать его матрицей. Можно — умножением на комплексное число. Два разных языка, один и тот же танец. Разберём.
Один угол — один поворот
Представьте, что вы крутите стрелку компаса. Положение стрелки полностью описывается одним числом — углом от севера. Никаких «трёх компонент с условиями ортогональности», никаких «четырёх чисел с нормировкой». Просто угол. По сути, это и есть поворот в 2D.
В программе вы храните одно число — θ — и можете его прибавлять, вычитать, интерполировать. Поворот на 30°, потом ещё на 60° — это просто 30 + 60 = 90. Никакой магии.
Способ первый: матрица 2×2
Когда нужно реально применить поворот к точке, появляется первая формула. Куда уехала точка (1, 0) после поворота на угол θ? В (cos θ, sin θ) — это видно из определения косинуса и синуса. А точка (0, 1)? В (−sin θ, cos θ) — повёрнутая на 90° вперёд. Эти два повёрнутых вектора и есть столбцы матрицы поворота:
Применяете её к точке (x, y) — получаете повёрнутую (x cos θ − y sin θ, x sin θ + y cos θ). Готово.
Способ второй: комплексное число
Теперь странный фокус. Берём комплексное число z = x + iy — записываем нашу точку как одно «число». И умножаем его на другое комплексное число — e^{iθ}. Получаем точно ту же повёрнутую точку.
Почему так — отдельная история, формула Эйлера. Сейчас важнее, что работает: умножение на комплексное число с модулем 1 геометрически означает поворот. А складывание углов превращается в перемножение чисел: e^{iα} · e^{iβ} = e^{i(α+β)}.
Один результат, разные пути
Две механики одного поворота
Покрутите слайдер. Точка слева ездит по кругу, точка справа — тоже. В обеих формулах внизу одинаковые числа — cos θ и sin θ, только в матрице они стоят по углам, а в комплексном числе — рядом, как Re и Im.
Это и есть главный сюжет Части 1: матрица и комплексное число — два языка про один и тот же поворот. Один многословный, другой компактный, оба правильные.
Запоминаем: «поворот в 2D — это число, которое умеет умножаться». В 3D эта роль перейдёт к кватернионам, и окажется, что параллель не случайная.
Часть 2. Три измерения, или где всё ломается
Итак, в 2D было хорошо. Один угол — один поворот. Складываем углы — складывается поворот. Никаких подвохов.
В 3D всё это перестаёт работать. И не из-за «недостатка усилий», а из-за того, что в трёхмерном пространстве у поворотов другая внутренняя структура. Сейчас покажу, что именно ломается.
Порядок имеет значение
Возьмите кубик в руки. Положите его на стол так, чтобы вы видели верхнюю грань. Теперь:
- Поверните на 90° вокруг оси X (грань, которая смотрела на вас, теперь смотрит вверх).
- Затем поверните на 90° вокруг оси Y (грань, которая смотрела вверх, теперь смотрит вправо).
Запомните результат. А теперь возьмите такой же кубик и сделайте те же два поворота, но в обратном порядке: сначала Y, потом X. Получится другая ориентация.
Порядок имеет значение
В 2D такого не было. Поворот на 30°, потом на 60° — всегда даёт 90°, без разницы, что было первым. В математике это свойство называется коммутативностью: a + b = b + a. Сложение чисел коммутативно, умножение — тоже. А вот 3D-повороты — нет. И это не «исправляется хорошим подходом» — это фундаментально.
Три ручки не работают
Кажется логичным, что у поворота в 3D «три ручки»: yaw, pitch, roll — три угла поворота вокруг трёх осей. Берёшь три числа, крутишь — получаешь любую ориентацию. Удобно же.
Так и сделали — это называется углы Эйлера. Они работают. Но в них есть одна неприятность, которую сейчас невозможно увидеть, а в Части 3 разберём подробно: при определённых ориентациях две из трёх «ручек» начинают двигать кубик одинаково. Третья степень свободы исчезает. Это называется gimbal lock — и ситуация, когда персонаж дёргается на повороте, скорее всего, именно про это.
По сути, проблема такая: трёхмерное пространство ориентаций (математики называют его SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность.) — это не куб с тремя осями. Это нечто покрученее. И попытка покрыть его тремя числами без вырождений — это как попытка нарисовать карту земного шара на одном плоском листе без разрывов и искажений. Не выйдет.
Поэтому существует зоопарк
Раз одного «правильного» способа нет, в практике сложилось несколько. Углы Эйлера — простые, но с гимбал-локом. Матрицы — универсальные, но громоздкие. Ось-угол — наглядные, но плохо интерполируются. Кватернионы — компактные и мощные, но нужна нетривиальная геометрия, чтобы понять, откуда они.
В Части 3 пройдёмся по каждому. С честными плюсами и минусами. Без объявления победителя — кватернионы получат своё место в Части 4, но до этого нужно увидеть, с чем мы их сравниваем.
Часть 3. Зоопарк: четыре способа повернуть кубик
Чтож, давайте знакомиться с зоопарком. Четыре представления ориентации. Каждое со своей механикой, своими плюсами и своими «но». Проходим по очереди, в конце сводная таблица.
3.1. Углы Эйлера: три слайдера и вечная драма
Идея: три последовательных поворота вокруг трёх осей. Yaw — рыскание, поворот вокруг вертикальной оси. Pitch — тангаж, наклон вверх-вниз. Roll — крен, поворот вокруг направления взгляда. Знакомо всем, кто хоть раз настраивал камеру в Unity или Unreal.
Хорош для: ввода от человека (понятные «ручки»), отображения в редакторе, сериализации в файл. Когда вам нужно показать художнику «поверни на 30 градусов влево», углы Эйлера — самый понятный способ.
Плох для: интерполяции (если не повезёт с углами — будет дёргаться), композиции (придётся переводить в матрицу), и главное — гимбал-лок.
Три слайдера и сломанное управление
Покрутите слайдеры. На большинстве комбинаций всё хорошо. Но при pitch ≈ ±90° yaw и roll начинают крутить кубик вокруг одной и той же оси — степень свободы исчезла. Это и есть гимбал-лок — название из авиационных гироскопов, где три кольца карданного подвеса в определённых ориентациях схлопываются в одну плоскость.
Гимбал-лок не «исправляется добавлением четвёртой оси» (хотя в реальных гироскопах так и делают). Он неустраним внутри представления тремя углами. Это просто следствие того, что три числа не покрывают SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность. гладко.
3.2. Матрицы 3×3: девять чисел и куда уехала ось
Идея: поворот как линейное преобразование. В 2D у нас была матрица 2×2:
В 3D — матрица 3×3, девять чисел в табличке. Но не любых: они должны удовлетворять условиям ортогональности (столбцы попарно перпендикулярны и единичной длины, определитель = +1). Поворот вокруг каждой из трёх координатных осей выглядит так:
Заметьте: 2D-матрица — это в точности «угол» 3×3-матрицы R_z, с осью Z как осью вращения. То есть 2D-поворот — это просто 3D-поворот вокруг Z. Все остальные 3D-повороты — комбинации R_x, R_y, R_z через перемножение (порядок важен — это та же некоммутативность из Части 2).
Лайфхак для интуиции: столбцы матрицы — это куда поехали базисные векторы X, Y, Z после поворота. Первый столбец — куда уехала ось X. Второй — куда Y. Третий — куда Z. Это гораздо нагляднее, чем смотреть на матрицу как на «таблицу чисел».
Матрица как тройка базисных векторов
Хорош для: применения к вершинам (v' = M · v — стандартная операция в шейдерах), композиции (M₁ · M₂ — поворот сначала на M₂, потом на M₁), универсальности (4×4 матрица заодно делает ещё и сдвиг — вся графика на этом).
Плох для: хранения (девять чисел вместо трёх — расточительно), интерполяции (как промежуточно поворачивать матрицы? отдельная боль), и численного дрейфа: после серии умножений матрица перестаёт быть точно ортогональной, нужна периодическая ре-ортогонализация.
3.3. Ось и угол: теорема Эйлера
Идея: теорема Эйлера говорит, что любой 3D-поворот, каким бы хитрым он ни был, эквивалентен повороту вокруг одной оси на один угол. Это, может быть, самое красивое утверждение во всей этой истории.
Хранится так: единичный вектор оси n = (nx, ny, nz) плюс угол θ. Итого четыре числа, но с одной связью (‖n‖ = 1), то есть три степени свободы. Никакого вырождения по углам, никакого гимбал-лока.
Стрелка и угол
Хорош для: интуиции и отладки. Когда вы видите такое представление, вы понимаете поворот геометрически — где ось, насколько крутим. Полезно для дебага.
Плох для: интерполяции (как линейно интерполировать ось, чтобы получился осмысленный «промежуточный поворот»? тоже не очевидно), композиции (нужны хитрые формулы Родрига), и вырождения при θ = 0 (ось не определена — куда поворачивать, если поворот нулевой?).
3.4. Кватернионы: четыре загадочных числа
Идея: ну, сейчас я вам её толком и не расскажу. Это будет в Части 4.
Просто посмотрите. Четыре числа (w, x, y, z). Условие нормировки w² + x² + y² + z² = 1. Применяется к точке по формуле сэндвича q · v · q⁻¹. Откуда всё это берётся, пока неясно.
Четыре загадочных числа
Хорош для: интерполяции (есть SLERP — гладкая интерполяция по дуге), композиции (просто перемножение), компактного хранения (четыре числа), численной устойчивости (легко нормализовать), отсутствия гимбал-лока. По сути, всё.
Плох для: интуиции. Никто не понимает, что такое i² = j² = k² = ijk = −1, пока не нарисует две плоскости-зеркала.
Вот это «всё на свете умеют, но никто не понимает» и есть та причина, по которой кватернионы в большинстве статей объясняют как магию. Часть 4 это исправляет.
Сводная таблица
| Эйлер | Матрица | Ось-угол | Кватернион | |
|---|---|---|---|---|
| Чисел | 3 | 9 | 4 | 4 |
| Интуитивен | да | средне | да | нет |
| Интерполируется | плохо | плохо | плохо | отлично |
| Композируется | через матрицу | да | через кватернион | да |
| Гимбал-лок | есть | нет | нет | нет |
| Хранение | дёшево | дорого | средне | дёшево |
| Численный дрейф | нет | есть | мало | мало |
Вы смотрите на это и видите, как кватернионы выигрывают почти по всем строчкам, кроме интуитивности. Что и составляет загадку: «как такая мощная вещь может быть настолько непонятной?»
Собственно, в Части 4 разбираемся. Без магии.
Часть 4. Кватернионы по-настоящему
Вот мы и пришли. Часть, ради которой всё затевалось. Сейчас разберём, что такое кватернион геометрически, откуда у него четыре числа, что значат i, j, k, почему сэндвич, и зачем 720° равно нулю.
Если хотя бы один из этих вопросов вызывает дискомфорт — нормально. К концу части их не останется.
4.1. Поворот = два отражения
Это утверждение — главный гвоздь всей этой истории. Запомните его, остальное вырастает из него.
Любой поворот в 3D можно получить как композицию двух отражений в плоскостях. Угол между плоскостями — половина угла поворота. Ось поворота — линия пересечения плоскостей.
Возьмите два зеркала и поставьте их под углом α/2. Положите между ними объект и мысленно сделайте: отразите его в первом зеркале, потом во втором. Объект окажется повёрнутым на угол α вокруг оси, проходящей по линии пересечения зеркал.
Два зеркала
Частные случаи:
- Параллельные зеркала (угол между ними
0°) → нет поворота. - Перпендикулярные зеркала (угол
90°) → поворот на180°. - Зеркала под углом
45°→ поворот на90°.
Это не просто красивое наблюдение. Это причина, по которой кватернионы устроены так, как устроены. Кватернион — это компактная запись пары зеркал. Скалярная часть w отвечает за угол между зеркалами. Векторная часть (x, y, z) — за направление линии пересечения зеркал (она же ось поворота). Половинный угол, который везде в формулах кватерниона возникает «откуда-то», — это просто угол между зеркалами, потому что два зеркала под α/2 дают поворот на α.
Половинный угол не магия. Это бухгалтерия двух отражений.
4.2. Почему именно четыре числа
Самый ответственный подраздел. Идём слоями — каждый следующий проясняет предыдущий.
Слой 1. Наивный счёт. У поворота в 3D три степени свободы: два числа на направление оси (углы широты и долготы) и одно на сам угол. Итого три. Кажется, трёх должно хватать.
Слой 2. Топологическая проблема. Пространство ориентаций (SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность.) нельзя гладко покрыть тремя числами без вырождений. Никаким способом. Это не «нужно ещё подумать», это математически доказано.
Аналогия (намеренно спустимся на одну размерность вниз — на обычную 2-сферу): попробуйте покрыть земной шар координатной сеткой долгота/широта. На полюсах долгота вырождается — там «все направления одновременно», на полюсе долгота не определена. Любая попытка ввести две координаты на сферу оставит особые точки.
Тут полезно вспомнить Часть 1. Там мы выяснили, что 2D-поворот элегантнее всего описывается одним комплексным числом e^{iθ} — вместо двух координат (cos θ, sin θ). Любопытная параллель: 2-сферу тоже можно описать одним комплексным числом через стереографическую проекцию (это так называемая сфера Римана — сферу проецируют на плоскость комплексных чисел из одной точки, и каждой точке сферы кроме полюса проекции соответствует одно z = x + iy). И там, и там одно «специальное число, которое умеет умножаться» обходит проблему вырождения, с которой не справляются пары координат.
На SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность. происходит то же самое, только размерность ещё выше. Гимбал-лок углов Эйлера — проявление этой топологической особенности. И правильным «специальным числом» для трёхмерных поворотов становится уже не комплексное (двух действительных компонент мало), а кватернион — прямое продолжение той же мысли, только с четырьмя компонентами вместо двух.
Кстати, даже обычную 2-сферу (продолжим аналогию) для гладкого описания обычно параметризуют тремя числами с одной связью: точка на ней — это (x, y, z) с условием x² + y² + z² = 1. Три числа, одна связь, две реальных степени свободы — ровно сколько и должно быть у точки на 2-сфере. SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность. устроен сложнее, на размерность выше — и для него гладкое описание потребует уже четырёх чисел с одной связью. Этим как раз и окажется кватернион. Но сначала — промежуточная попытка.
Слой 3. Ось-угол как промежуточная попытка. Окей, давайте попробуем: три числа на ось (nx, ny, nz) плюс угол θ. Четыре числа с одной связью ‖n‖ = 1. Три степени свободы — уже хорошо. Но: при θ = 0 ось не определена (куда поворачивать, если не поворачиваем?). И интерполяция по такой паре — не очевидна. Не идеально.
Слой 4. Половинный угол. А что если взять не n и θ, а закодировать их хитрее? Скажем:
То есть w = cos(θ/2) — скаляр, а (x, y, z) = sin(θ/2) · n — вектор. Четыре числа. Условие w² + x² + y² + z² = 1 — единичная сфера в 4D, которую математики называют S³.
И вот тут происходит чудо. Половинный угол берётся не с потолка — он следует из тех самых двух отражений из 4.1: два зеркала под θ/2 дают поворот на θ. А кватернион — компактная запись пары зеркал. Поэтому половинка везде.
Заодно дважды-покрытие: q и −q дают один и тот же поворот. Это побочный эффект половинного угла (cos(θ/2 + π) = −cos(θ/2), sin(θ/2 + π) = −sin(θ/2)). И это не баг, а фича — именно дважды-покрытие позволяет сделать пространство кватернионов гладким (без особых точек), в отличие от ось-угла.
Глобус ориентаций (стереографическая проекция S³)
Итого: четыре числа с одной связью → три степени свободы → дважды-покрывает SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность. → нет вырождений → есть гладкая интерполяция. Победа.
4.3. i, j, k без мистики
Историю кватернионов обычно начинают с Гамильтона и его правил i² = j² = k² = ijk = −1. Это правда красиво, но без геометрии — непонятно, почему именно так.
С геометрией двух отражений всё встаёт на свои места.
i, j, k — это не «мнимые единицы трёх сортов». Это три ортогональные плоскости отражения. i — отражение от плоскости YZ. j — от плоскости XZ. k — от плоскости XY.
Что значит i² = −1? Применили отражение i дважды. Что получилось? Композиция двух отражений в одной и той же плоскости — это разворот на 360°. И в кватернионной алгебре 360° поворота — это −1 (потому что половинный угол: cos(360°/2) = cos(180°) = −1). Вот и i² = −1.
Что значит i · j? Композиция отражения в YZ и отражения в XZ. Эти плоскости перпендикулярны и пересекаются по оси Z. Композиция двух отражений в перпендикулярных плоскостях — поворот на 180° вокруг линии пересечения. То есть i · j = k (поворот на 180° вокруг Z, что в кватернионной записи и есть k).
И так далее. Все правила Гамильтона выводятся из геометрии композиции отражений. Никакой магии.
Кватернион из двух зеркал
Отдельно — что значат скалярная и векторная части. У кватерниона q = (w, x, y, z) четыре компоненты:
w = cos(θ/2)— косинус половинного угла между зеркалами.(x, y, z) = sin(θ/2) · n— синус половинного угла, помноженный на единичный вектор вдоль линии пересечения зеркал (он же ось поворота).
При θ = 0 (зеркала параллельны, нет поворота) → w = 1, (x, y, z) = (0, 0, 0) → единичный кватернион. При θ = 360° (полный оборот) → w = −1, (x, y, z) = (0, 0, 0) → минус-единичный. И вот это самое −1 — как раз то самое дважды-покрытие.
4.4. Формула q·v·q⁻¹ как сэндвич
Окей, кватернион определён. Как с его помощью повернуть точку?
Можно было бы наивно думать: q · v — поворачиваем вектор. Но эта операция работает не так. Если просто умножить q · v (где v — чистый вектор, то есть кватернион с w = 0), получится:
- Поворот на удвоенный угол (потому что в кватернионе сидит половинный угол, и одно умножение даёт лишь половину «целого» поворота).
- И ещё длина исказится.
Ни то, ни другое не годится.
Сэндвич — q · v · q⁻¹ — это композиция двух операций: умножение слева на q, умножение справа на q⁻¹. Они вместе компенсируют искажение длины и удваивают эффект поворота — в результате получается ровно тот поворот на θ, который мы хотели.
Геометрически: q · v — это «применили половину поворота». · q⁻¹ — «применили ещё половину поворота, но с другой стороны, чтобы скомпенсировать длину». Два полуповорота в сумме дают полный поворот. Вот и сэндвич.
Анатомия сэндвича
Если вы программист и вас бесит «почему нельзя одним умножением» — теперь понятно, почему. Потому что кватернион хранит половинный угол. И чтобы получить «целый» эффект, нужно дважды.
4.5. Plate trick — главный аттракцион
И теперь самая красивая часть. Помните, мы говорили: q и −q — один и тот же поворот? То есть в SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность. есть «короткий путь» к ориентации и «длинный путь» через всю S³, и оба приходят туда же. Эта двойственность имеет физическое следствие.
Поворот на 360° ≠ исходное состояние. Поворот на 720° = исходное.
Это звучит безумно. Но это правда. И есть классический фокус, который это демонстрирует физически — он называется Dirac belt trick (фокус с ремнём Дирака).
Как проделать дома (нужен ремень, длинный шарф или собачий поводок):
- Возьмите ремень длиной хотя бы метр. Один конец прикрепите к чему-то неподвижному — зажмите дверью, привяжите к ручке шкафа, или попросите кого-то держать. Второй конец держите в правой руке, ремень натянут горизонтально.
- Держите свой конец плашмя (например, представьте, что в руке пряжка с надписью «вверх», и эта надпись должна оставаться сверху всё время).
- Первый оборот (0° → 360°): поверните ваш конец вокруг вертикальной оси на полный оборот, не наклоняя пряжку. Ремень между руками теперь закручен на один виток.
- Попытайтесь распутать: не вращая свой конец и не отрывая дальний, попытайтесь убрать виток. Можете обходить ремень с любой стороны, поднимать его над головой, опускать к ногам — виток никуда не денется. Один виток упрямо остаётся.
- Второй оборот (360° → 720°, в ту же сторону): продолжите крутить пряжку, ещё один полный оборот в ту же сторону. На ремне теперь два витка, выглядит ещё плотнее закрученным.
- А теперь распутайте: не вращая свой конец, проведите свой кулак через петлю. Конкретно: подведите вашу руку (со всё ещё горизонтальной пряжкой) под ремень, потом перенесите её над ремнём — то есть сделайте кулаком траекторию, которая проходит через витую часть. Один такой проход снимает сразу два витка, и ремень распрямляется. Пряжка осталась в той же ориентации, в которой была после двух оборотов.
Между 360° и 720° ваш конец крутился только вперёд, никаких разворотов назад. И в первом случае распутать было нельзя, а во втором — можно.
Почему 360° распутать нельзя, а 720° — можно? Каждое «провести конец ремня сквозь петлю» меняет число витков сразу на ±2 (пряжка прошла над и под ремнём — это два изменения сразу). Значит, чётность числа витков сохраняется при любых таких операциях. Один виток — нечётное число; ноль — чётное; перевести одно в другое никакими «проходами через петлю» нельзя. Два витка — уже чётное число, ноль достижим. Это и есть 4π против 2π на языке топологии: пути длиной 4π стягиваются в точку, пути длиной 2π — нет.
В демо ниже у нас не один ремень, а три ленты — топология та же. Кнопка «распутать ленты» доступна только на 720°, где число витков чётное. Анимация теперь делает это честно: каждая лента по очереди отрывается от своей точки крепления, проходит над кубиком и возвращается обратно, и за этот проход с неё снимаются сразу два витка. Это та самая операция «провести конец через петлю» из ремня. Кубик при этом не вращается — он стоит на месте всё распутывание.
Чашка на ладони — plate trick
Это не подвох и не оптическая иллюзия. Это физическое проявление того, что в S³ путь от identity до identity длиной 360° (туда же, но через −q) — топологически нетривиален, а путь длиной 720° (через q обратно к identity) — тривиален.
В физике эта же штука называется спинорной геометрией. Электрон ведёт себя как объект на ремне: его «полный оборот» — это 4π, а не 2π. И это не случайность — это та же топология SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность., что у нас в кватернионах. Если хочется глубже, копайте в сторону спиноров и групп Ли. Не для слабонервных.
4.6. SLERP и практика
Чтож, теории достаточно. Поговорим о применении.
Самая популярная операция с кватернионами — интерполяция между двумя ориентациями. Скажем, у вас камера в точке A смотрит туда-то, в точке B — сюда-то, и нужно за полсекунды плавно переехать. Три способа:
LERP — линейная интерполяция компонент. Тупо q(t) = (1−t) · q₁ + t · q₂. Дёшево. Но результат не нормирован, и идёт не по дуге, а по хорде сферы. Плюс, если q₁ · q₂ < 0 (то есть на S³ они «по разные стороны») — пойдёт длинным путём через всю сферу.
NLERP — LERP плюс нормализация. То же самое, но в конце делим на ‖q‖. Норма теперь правильная, но скорость по дуге неравномерная — ускоряется в середине.
SLERP — Spherical Linear intERPolation. Идёт по дуге большого круга на S³ с равномерной угловой скоростью. Формула:
где Ω — угол между q₁ и q₂ на S³.
Три способа интерполяции
На практике почти везде используется NLERP. SLERP идеален математически, но дороже (там тригонометрия), и для большинства геймдев-сценариев NLERP визуально неотличим. SLERP оставляйте для случаев, где вам действительно важна равномерная угловая скорость.
Типичные баги:
- Не нормировали кватернион после серии умножений — медленно дрейфует от единичного, ориентации становятся скошенными. Лечится периодической нормализацией.
- Не выбрали короткий путь. Если
q₁ · q₂ < 0, нужно заменитьq₂на−q₂перед интерполяцией. Иначе ваша камера сделает оборот через всю сцену вместо короткой дуги. - Перепутали порядок умножения. Кватернионы некоммутативны.
q₁ · q₂— это сначалаq₂, потомq₁. Многих это сбивает.
Эпилог. Куда расти
Если вы дочитали досюда — поздравляю, вы теперь знаете о поворотах в 3D больше, чем 95% людей, которые ими пользуются. Серьёзно. Большинство геймдев-разработчиков работает с кватернионами как с волшебным ящиком: «крутит, не дёргается, и слава богу». А вы теперь понимаете, что внутри две плоскости-зеркала, половинный угол и дважды-покрытие SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность.. Это уже другой уровень разговора с самим инструментом.
Куда копать дальше, если зацепило:
-
Двойные кватернионы (dual quaternions) — обобщение, которое за один объект объединяет и поворот, и сдвиг. В геймдеве используются для скиннинга мешей: классический weighted-кватернионный скиннинг даёт артефакты при сильных деформациях, dual quaternion skinning их убирает. Если делаете персонажей с гибкими руками — это ваше.
-
Геометрическая алгебра (она же Clifford algebra, и её прикладной кусок — роторы). Это обобщение «поворот через зеркала» на любую размерность пространства. Многие считают, что с этого надо начинать преподавать повороты, а кватернионы — частный случай для 3D. То, что мы делали с двумя зеркалами в Части 4, — частный случай одного оператора в GA. Очень красиво, но требует другого подхода к мышлению.
-
Спиноры — то же место, что и plate trick, но в физике. Если квантовая механика говорит, что у электрона спин-1/2 и его волновая функция меняет знак при повороте на 360°, а на 720° возвращается, — это ровно та же топология, что у нас в кватернионах. SU(2) и SO(3) — пространство всех 3D-поворотов. Имеет три степени свободы, но устроено топологически нетривиально (не как куб с тремя осями) — отсюда и гимбал-лок углов Эйлера, и необходимость кватернионов, чтобы покрыть его гладко. «SO» = «special orthogonal», «3» = размерность., та же история. Если интересно, копайте в сторону групп Ли и накрытий.
-
SLERP в продакшне. Если будете писать своё — гляньте, как сделано в Unity (
Quaternion.Slerp) или Unreal (FQuat::Slerp): проверенные реализации с учётом всех численных подводных камней. Классическая статья, в которой SLERP и был сформулирован, — Кен Шумейкер, 1985 год, гуглится по «Shoemake quaternion curves».
И на этом всё. Надеюсь, статья была полезна — особенно если до неё кватернионы казались магией. Магии в графике, как и почти везде, на самом деле нет: есть только геометрия с хорошим костюмом.
[больше интересного в телеграм][другие статьи и квизы на dev-math.ru]