glMatrix. Кватернионы


два часа теории перед
практическими занятиями


Клиначев Николай Васильевич

[Home] [←] [PgUp]  [Esc] [Space]  [PgDn] [→] [End]

Способы кодирования ориентации

  1. Углы Эйлера: прецессии, нутации, и собственного вращения (α, β, γ)
  2. Углы Брайнта-Крылова: крен, тангаж, рысканье (φ, θ, ψ)
  3. Кватернион – 4 числа (x, y, z, w) от -1 до +1
  4. Матрица поворота (3x3, из векторов направлений): right, up, forward

Углы Эйлера – α, β, γ

Хорошо, что ось вращения Земли наклонена. А то было бы как с кораблями – если мачта в зените, угол нутации обнуляется, нелинейные "Кинематические уравнения Эйлера" вырождаются (происходит деление на ноль, на sin от угла нутации). И ни кто не знает, что происходит.

Углы Брайнта-Крылова – φ, θ, ψ

Хорошо, что корабли, у которых мачта лежит на воде, ни кому не нужны. А то было бы как с истребителями – сделал "кобру", дифферент / тангаж равен 90, нелинейные "Кинематические уравнения Брайнта-Крылова" вырождаются. И опять ни кто не знает, что происходит.

Кватернион – x, y, z, w

Кручу, верчу – лечу куда хочу. "Кинематические уравнения Родрига-Гамильтона" линейны, не вырождаются. :-)

Кодирование ориентации кватернионом – x, y, z, w

Углы – это 360°. Кватернион – 720°.

Углы кодируют ориентацию в пределах одного оборота. Кватернион – в пределах двух. У систем ориентации исчезает запретный сектор для позиционирования. В котором из-за, шумов датчиков, возможны периодические развороты аппарата на 360°.

Кватернион ориентации всегда нормирован

1  ===  (x * x + y * y + z * z + w * w) ^ 0.5

Нормализацию могут нарушить лишь ошибки интегрирования "Кинематических уравнений". Если вы их используете, то нормализуйте кватернион на выходе СУ – quat.normalize.

Для "реверс-движений" (для смены знака кватерниона) не используйте функцию quat.invert. Используйте функцию quat.conjugate

Кватернион и Аффинная матрица

Задание для ориентации определяют кватернионом. Коэффициенты кватерниона пересчитывают в коэффициенты аффинной матрицы. Аффинную матрицу подключают к видеокарте для вывода фрагмента 3D-сцены.

Термины и обозначения

  • Q – ориентация (кватернион)
  • P – позиция (x, y, z)
  • V – вектор (P2 - P1)
  • L – дистанция |V|
  • N – направление (V / L)
  • N – номаль (перпендикуляр)

Префиксы для величин

  • g – задание для величины
  • y – фактическая величина
  • d – приращение величины
  • i – величина со знаком минус
  • z – регистр задержки

эти соглашения из ТАУ

Как определить кватернион?

var gQ = quat.create();         // [0, 0, 0, 1]
quat.fromEuler(gQ, 90, 0, 0);   // из углов Эйлера

Как повернуть кватернион?

// Фрагмент функции обработки нажатия клавиш
// [↑] [↓] [←] [→] [1] [2]
switch (event.keyCode) {
    case 38 : quat.rotateX(gQ, gQ, -0.04); break;
    case 40 : quat.rotateX(gQ, gQ, +0.04); break;
    case 37 : quat.rotateY(gQ, gQ, -0.04); break;
    case 39 : quat.rotateY(gQ, gQ, +0.04); break;
    case 49 : quat.rotateZ(gQ, gQ, +0.04); break;
    case 50 : quat.rotateZ(gQ, gQ, -0.04); break;
    default : return true;
}
return false;

[0, 0, 0, 1] – Какой кватернион не может повернуть вектор?

// Повернуть вектор или изменить направление
// кватернионом может функция vec3.transformQuat
vec3.transformQuat([], [0, 0, -1], [0, 0, 0, 1]);
vec3.transformQuat([], [0, 0, +1], [0, 0, 0, 1]);
vec3.transformQuat([], [0, -1, 0], [0, 0, 0, 1]);
vec3.transformQuat([], [0, +1, 0], [0, 0, 0, 1]);
vec3.transformQuat([], [-1, 0, 0], [0, 0, 0, 1]);
vec3.transformQuat([], [+1, 0, 0], [0, 0, 0, 1]);
// Возвращаемое значение – копия второго аргумента

// Кватернион можно преобразовать в матрицу
// и использовать функцию vec3.transformMat3
var rotMat = mat3.fromQuat([], [0, 0, 0, 1]);
vec3.transformMat3([], [1, 2, 3], rotMat);
//   результат:        [1, 2, 3]

Понятие о Реверс-движении

Легко ли повернуть букву F обратно?

F newX     a  c  e     X
newY  =  b  d  f  *  Y
new1     0  0  1     1

Надо решить СЛАУ с тремя неизвестными
[x, y, z, 1] (найти инверсную афф. матрицу)

Но мы знаем, что буква "F" была повернута на 30 градусов по часовой стрелке.

... по или против, против или по ...

А теперь нужно решать СЛАУ?

F newX     a  c  e     X
newY  =  b  d  f  *  Y
new1     0  0  1     1

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

Как вычислить направление света?

// Камера перемещается в неподвижной сцене
// cmQ – кватернион ориентации камеры
// gVL – направление на ламинарный свет (для сцены)
// yVL – направление на ламинарный свет (в камере)
// yVL вычисляют "Реверс-движением". Если камера
// поворачивается по часовой, то свет – против

// Вычислим кватернион, iQcm, для реверс-движения
quat.conjugate(iQcm, cmQ);        // iQcm = "-"cmQ
// Повернем gVL, получим направление света в ..
vec3.transformQuat(yVL, gVL, iQcm);  // оке камеры

// Примечание. |gVL| = 1, |cmQ| = 1  =>  |yVL| = 1

Понятие о виртуальном мире, который "шагает под вами"

Как сфотографировать подснежник?


Нужно взять смартфон (камеру 3D-сцены), отнести её в лес, и сделать снимок.


... идти, нести, нести, идти, ...

Что мы видим?

Движение камеры вокруг сцены или реверс-движение сцены перед неподвижной камерой?

Погрешность расчётов на видеокарте

Предположим, погрешность равна одному разряду десятичной мантиссы из 5 знакомест.

±00001

Если камера находится в позиции [0, 0, 0], то погрешность вычислений геометрии ±0.00001 метра. Если монстры убежали на 99999 метров, то погрешности в их изображениях ±1 метр.

Резюме

В компьюрерных стрелялках, весь мир шагает и крутиться под вами. А камера 3D-сцены ведет неподвижный образ жизни в позиции [0, 0, 0] и видит в направлении [0, 0, -1].

Как определить Матрицу камеры?

// В WebGL камера находиться в позиции [0, 0, 0]
// и видит в направлении [0, 0, -1]. Её движение
// к позиции cmP и ориентация cmQ эмулируются.
// Используем "Метод прямых движений с инверсией"

mat4.fromRotationTranslation(cmMatrix, cmQ, cmP);
mat4.invert(cmMatrix, cmMatrix); // Матрица камеры

// ... Альтернативный "Метод обратных движений"
//     не требует вычисления инверсной матрицы ...

// ... Используют так же функцию  mat4.lookAt  ...

Понятие об "аффинном измерении" (субпространстве), в котором сложение движений отражается в умножение матриц и кватернионов


Примечание. Это почти как с логарифмической линейкой, но только с линейкой умножение превращается в сложение.

Мы уже умеем поворачивать букву F

F X1     a  c  e     X0
Y1  =  b  d  f  *  Y0
 1     0  0  1      1

А еще повернуть можете ?

Да! [P1] = [A1] * [P0] и [P2] = [A2] * [P1]

F X2     a  c  e     X1
Y2  =  b  d  f  *  Y1
 1     0  0  1      1

А можно было афф. матрицы перемножить
[P2] = ([A2] * [A1]) * [P0] ?

Проверим на практическом занятии ...


А можно ли предположить, что первый поворот буквы F случился из-за движения камеры?

... и всех других элементов 3D-сцены ...


Поэтому матрицы сцены для всех элементов инициируют матрицей камеры.

Как определить Матрицу сцены?
(для отрисовки элемента)

// Рисуем станцию "Салют-7"
//   в позиции, yP7, с ориентацией yQ7.
// cmMatrix – аффинная "Матрица камеры"
// mvMatrix – аффинная "Матрица сцены"
// dwMatrix – матрица для текущих операций
//
// Перешли в сцене к станции "Салют-7"
mat4.translate(mvMatrix, cmMatrix, yP7);
// Кватернион ориентации "Салюта-7" в матрицу
mat4.fromQuat(dwMatrix, yQ7);
// Повернули сцену для отрисовки "Салюта-7"
mat4.multiply(mvMatrix, mvMatrix, dwMatrix);
// Выбрали масштаб для отрисовки по осям x, y и z
mat4.scale(mvMatrix, mvMatrix, [4.0, 4.0, 6.0]);

Сумма ориентаций

// gQ – кватернион целевой ориентации (телескопа)
// yQ – кватернион фактической ориентации
// dQ – кватернион дополнительного поворота

quat.multiply(gQ, yQ, dQ);      // gQ = yQ "+" dQ

Повороты суммируют, умножая кватернионы (а деления для кватернионов нет)

Разность ориентаций

// gQ – кватернион целевой ориентации (телескопа)
// yQ – кватернион фактической ориентации
// dQ – кватернион поворота до цели

// Вычислим ошибку ориентации dQ = gQ "-" yQ

// "Реверс движение" – iQ – к начальной ориентации
quat.conjugate(iQ, yQ);         // iQ = "-" yQ
// Переход dQ от yQ к цели через "Реверс движение"
quat.multiply(dQ, iQ, gQ);      // dQ = iQ "+" gQ
// Проверка (движение от фактической к целевой)
quat.multiply(_Q, yQ, dQ);      // _Q = yQ "+" dQ
quat.equals(_Q, gQ) === true;   // === gQ Убедились

Дистанция и поворот → Вектор

// dQ – кватернион до цели
// dL – дистанция до цели
// dP – вектор до цели
// yP – позиция наблюдателя
// yC – позиция цели (искомое)

// Повернём дистанцию [0, 0, -dL] кватернионом
vec3.transformQuat(dP, [0, 0, -dL], dQ);
// yC = yP + dP
vec3.add(yC, yP, dP);           // Нашли позицию Ц

// И, обратно, вектор (кватернионом) в дистанцию
quat.conjugate(dQ, dQ);         // Реверс-движение
vec3.transformQuat(dP, dP, dQ); // dP == [0, 0, -dL]

Вектор → Дистанция и поворот

// dP – вектор до цели – vec3.subtract(dP, yC, yP)
var dP = vec3.fromValues(30, 50, -70);
var dL = vec3.length(dP);   // Дистанция   до цели
var dQ = quat.create();     // Кватернион  до цели
var _P = vec3.create();
vec3.normalize(_P, dP);     // Направление до цели
quat.rotationTo(dQ, [0.0, 0.0, -1.0], _P);

// Проверка. Поворот и дистанция → Вектор
vec3.transformQuat(_P, [0, 0, -dL], dQ);
vec3.equals(_P, dP) === true;   // === dP Убедились

Вектор → Дистанция и поворот

// dP – вектор до цели – vec3.subtract(dP, yC, yP)
var dP = vec3.fromValues(30, 50, -70);
var dL = vec3.length(dP);   // Дистанция до цели
var dQ = quat.create();     // Кватернион до цели
var uV = vec3.fromValues(0, 1, 0);  // Нормаль ↑
var rV = vec3.fromValues(0, 0, 0);  // Нормаль →
vec3.normalize(dP, dP);         // Направление
vec3.cross(rV, dP, uV);         // Перпендикуляр
vec3.normalize(rV, rV);         // Нормаль вправо
vec3.cross(uV, rV, dP);         // Нормаль вверх
quat.setAxes(dQ, dP, rV, uV);   // Матрица поворота
quat.conjugate(dQ, dQ);         // Реверс-движение
// Проверка. Дистанция и поворот → Вектор
vec3.transformQuat([], [0, 0, -dL], dQ); // == dP

Икосаэдр – основа для планет, астероидов, звёздного небосвода

Икосаэдр и Звёздный небосвод

Большая нагрузка на видеокарту

Звёздные зонтики небосвода и вершины икосаэдра

Секторы можно переключать под камеру

Переключение секторов звёздного небосвода в вершинах икосаэдра

4 секунды и включается система ориентации КА

Инструменты

Литература

Что делать, как жить?


Делать ракету!
Выполняем комплект л.р. и курсовую аэрокосмического факультета.


29.12.2018