Вращающийся вектор3 кватернионом

25

Я пытаюсь повернуть вектор3 на заданный кватернион.

Я знаю что это правда

v=qvq1

Я знаю, что является инверсией, которая просто , но как мне отобразить умножение вектора на кватернион, чтобы вернуть вектор?q1qmagnitude(q)

Я обнаружил, что вы можете рассматривать как матрицу и конвертировать и в матрицы, а затем конвертировать из матрицы в вектор, но это кажется слишком сложным, чтобы получить вектор. Есть ли более чистая реализация, которую я мог бы использовать?vqqv

gardian06
источник

Ответы:

36

Как показали Натан Рид и теодрон, рецепт вращения вектора v кватернионом единичной длины q :

1) Создайте чистый кватернион p из v . Это просто означает добавление четвертой координаты 0:

p=(vx,vy,vz,0)p=(v,0)

2) Предварительно умножьте его на q и затем умножьте на сопряженное q * :

p=q×p×q

3) Это приведет к еще одному чистому кватерниону, который можно превратить в вектор:

v=(px,py,pz)

Этот вектор v является v повернута на q .


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

Мы также можем описать q как комбинацию трехмерного вектора u и скаляра s :

q=(ux,uy,uz,s)q=(u,s)

По правилам умножения кватернионов , а так как сопряженность кватерниона единичной длины просто обратна, мы получаем:

p=qpq=(u,s)(v,0)(u,s)=(sv+u×v,uv)(u,s)=((uv)(u)+s(sv+u× v)+(sv+u×v)×(u),)=((uv)u+s2v+s(u×v)+sv×(u)+(u×v)×(u),)

Скалярная часть (эллипсы) приводит к нулю, как подробно описано здесь . Что интересно, векторная часть, AKA наш повернутый вектор v ' . Это можно упростить, используя некоторые основные векторные тождества :

v=(uv)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(uv)u+s2v+2s(u×v)+(uv)u(uu)v=2(uv)u+(s2uu)v+2s(u×v)

Это теперь намного более оптимально ; две точки, перекрестный продукт и несколько дополнительных функций: около половины операций. Что даст что-то подобное в исходном коде (при условии некоторой универсальной библиотеки векторной математики)

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}
Лоран Кувиду
источник
Снимаю шляпу перед лучшим письменным ответом. И, учитывая, что большинство любителей производительности, как правило, используют встроенные функции для выполнения векторных операций, вы получаете значительное ускорение (даже для простого умножения кватернионов, особенно на архитектурах Intel).
Теодрон
Окончательный результат выглядит аналогично формуле вращения Родригеса - в любом случае он имеет одинаковые базисные векторы; Я должен был бы покопаться в некоторых триггерных идентичностях, чтобы увидеть, совпадают ли коэффициенты.
Натан Рид
@NathanReed Похоже, это еще один способ прийти к тому же результату. Я также хотел бы знать, соответствует ли это. Спасибо что подметил это!
Лоран Кувиду
1
Я проверял реализацию GLM этого, и это, кажется, реализовано немного по-другому, а именно следующим образом: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fэто похожая оптимизация? Это выглядит несколько похоже, но не то же самое - оно использует только перекрестные продукты, а не точечные. Оригинальный исходный код можно найти в файле type_quat.inl официального репозитория GLM в в operator*котором принимает кватернион и вектор ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi
7

Прежде всего, q ^ (- 1) не равно -q / величина (q); это q * / (величина (q)) ^ 2 (q * является сопряженным; оно отрицает все компоненты, кроме действительного). Конечно, вы можете исключить деление на величину, если все ваши кватернионы уже нормализованы, как это обычно бывает в системе вращения.

Что касается умножения на вектор, вы просто расширяете вектор до кватерниона, устанавливая реальный компонент квата в ноль, а его компоненты ijk равны xyz вектора. Затем вы делаете умножения кватернионов, чтобы получить v ', а затем снова извлекаете компоненты ijk. (Действительная часть v 'всегда должна выходить за ноль, плюс или минус некоторая ошибка с плавающей точкой.)

Натан Рид
источник
5

Первое наблюдение: обратное qнет -q/magnitude(q), это совершенно неправильно. Вращения с кватернионами подразумевают, что эти эквиваленты 4D комплексных чисел имеют унитарную норму, следовательно, лежат на единичной сфере S3 в этом 4D пространстве. Тот факт, что кват является унитарным, означает, что его норма равна, norm(q)^2=q*conjugate(q)=1и это означает, что обратное значение квата является его сопряженным.

Если единичный кватернион записывается как q=(w,x,y,z)= (cos (t), sin (t) v ), то его сопряженность равна conjugate(q)=(w,-x,-y,-z)= (cos (t), - sin (t) v ), где t - половина угла поворота, а v ось вращения (как единичный вектор, конечно).

Когда тот чувак Гамильтона решил поиграть с эквивалентами комплексных чисел в более высоких измерениях, он также наткнулся на некоторые хорошие свойства. Например, если вы используете полностью чистый кватернион q=(0,x,y,z)(без скалярной части w !), Вы можете считать это дерьмо вектором (на самом деле это кват на то, что люди могут назвать экватором сферы S3, которая является сферой S2! ! - умопомрачительные вещи, если учесть, насколько технически слабые люди в 19 веке кажутся нам ковбоями EyePhone в наше время). Таким образом, Гамильтон взял этот вектор в форме квата v=(0,x,y,z)и провел серию экспериментов с учетом геометрических свойств кватов. Короче говоря:

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

где

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

Замечание: q * (0, v) * con (q) должен быть другим кватом вида (0, v '). Я не буду проходить через все это, по-видимому, сложное объяснение того, почему это происходит, но если вы поворачиваете чистый воображаемый кватернион (или вектор в нашем случае!) С помощью этого метода, вы должны получить объект подобного типа: чистый воображаемый кват. и вы принимаете его мнимую роль в качестве результата. Вот вам и чудесный мир вращений с кватернионами в ореховой скорлупе.

ПРИМЕЧАНИЕ : для тех, кто присоединяется к этой чрезмерно употребленной фразе: четверки хороши, потому что они избегают их блокировки карданного подвеса ... должны сначала открыть свое воображение !! Кваты - это просто «изящный» математический аппарат, и его можно полностью избежать, используя другие подходы, один из которых я считаю совершенно геометрически эквивалентным подходу угла оси.

КОД : библиотека C ++, которая мне нравится , довольно проста, но в ней есть все операции с матрицами, векторами и кватами, которые могут понадобиться экспериментатору по трехмерной графике, не тратя больше 15 минут на ее изучение. Вы можете протестировать то, что я написал здесь, используя это через 15 минут, если вы не новичок в C ++. Удачи!

teodron
источник
+1 за вашу заметку. Бьюсь об заклад, большинство людей не смогли бы добиться реальной блокировки карданного подвеса, если бы они попытались. Это стало ключевой фразой для любого неожиданного поведения при выполнении поворотов.
Стив Х
Большинство людей не могут построить надлежащий механизм карданного подвеса и думают, что, если они соединят вместе 3 матрицы вращения, они автоматически получат представление «Углы Эйлера». Карданная штучка - всего лишь один из самых простых вращательных механизмов типа «рука робота». суставы, которые могут испытывать избыточность при попытке выполнить обратную кинематику (у этого есть больше степеней свободы, чем это фактически необходимо, чтобы произвести желаемую ориентацию). О, хорошо, это другая тема, но я подумал, что это хорошо, чтобы держаться подальше от шумихи, которую эта "легендарная" проблема вызвала среди программистов CG ..
teodron
Nitpickery: хотя осевой угол эквивалентен в том смысле, что оба представления могут представлять все повороты в SO (3) однозначно (хорошо, по модулю обычного двойного покрытия) и, конечно, между ними есть почти тривиальное преобразование, кватернионы действительно имеют преимущество в том, что его гораздо проще составлять, чем во всех других нематричных представлениях.
Стивен Стадницки
У них есть преимущество в том, что их легче составлять благодаря их хорошему поведению на любом объектно-ориентированном языке программирования, особенно при использовании перегрузки операторов. Я не уверен, но, возможно, даже их сферические интерполяционные свойства сохраняются для оси-угла (кроме SQUAD, может быть, ?!).
Теодрон
2

Вот альтернативный способ преобразования вектора кватернионом. Так MS делает это в рамках xna. http://pastebin.com/fAFp6NnN

Стив Н
источник
-1

Я попытался решить это вручную и придумал следующее уравнение / метод:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

Я был бы признателен, если бы кто-то посмотрел на производную от mt, которую я использовал http://pastebin.com/8QHQqGbv. Я бы предложил скопировать в текстовый редактор, поддерживающий боковую прокрутку.

в моей записи я использовал q ^ (- 1) для обозначения сопряженных, а не обратных, и разных идентификаторов, но я надеюсь, что он является следуемым. Я думаю, что большинство прав, особенно в тех случаях, когда при доказательстве исчезнет реальная часть вектора.

gardian06
источник