Обертовий вектор3 кватерніоном


25

Я намагаюся повернути вектор3 заданим кватерніоном.

Я знаю, що це правда

v=qvq1

Я знаю, що є оберненою, яка просто , але як я зіставити множення вектора на кватерніон, щоб повернути вектор?q1qmagnitude(q)

Я виявив, що ви можете ставитися до як до матриці та перетворювати і в матриці, а потім перетворювати з матриці у вектор, але це здається трохи вгорі, щоб отримати вектор. Чи є більш чиста реалізація, яку я міг би використати?vqqv

Відповіді:


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Чи схожа це оптимізація? Це виглядає дещо схоже, але не те саме - він використовує лише перехресні продукти, не крапкові продукти. Оригінальний вихідний код можна знайти в офіційному файлі сховища GLM type_quat.inl, в 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 - на ксиз вектора. Потім ви робите множення кватерніона, щоб отримати 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 столітті здаються нам очі ковбоями в даний час). Тож Гамільтон прийняв цей вектор у своєму квазі вигляді: 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) * conj (q) має бути ще одним кватом форми (0, v '). Я не буду проходити через все це, очевидно складне пояснення, чому це відбувається, але якщо ви обертаєте чистий уявний кватерніон (або вектор у нашому випадку!) Цим методом, ви повинні отримати подібний об’єкт: чистий уявний кват. і ви берете його уявну роль як результат. Там у вас є, дивовижний світ обертів з кватерніонами в горіховій (ти) оболонці.

ПРИМІТКА : до кого вскочить ця надмірно використана фраза: квати хороші тим, що вони уникають їхнього замкового каркасу. Спершу слід розблокувати свою уяву !! Квати - це просто «елегантний» математичний апарат, і його можна взагалі уникнути, використовуючи інші підходи; той, який я вважаю абсолютно геометрично еквівалентним, є кутовим підходом до осі.

КОД : Бібліотека C ++, яка мені здається, є досить спрощеною, але має всі матричні, векторні та кватні операції, які потребує експерименталіст з 3D-графіки, не витрачаючи більше 15 хвилин, щоб вивчити це. Ви можете перевірити те, що я написав тут, використовуючи це за 15 хвилин, якщо ви не новачок на C ++. Удачі!


+1 для вашої замітки. Гадаю, що більшість людей не змогли досягти справжнього фіксатора, якщо вони спробували. Це стало загальною фразою для будь-якої несподіваної поведінки під час обертання.
Стів H

Більшість людей не можуть створити належний механізм повороту і думають, що якщо вони з'єднають між собою 3 матриці обертання, вони автоматично закінчуються представленням "кутів Ейлера". суглоби, які можуть зазнати надмірності при спробі виконання зворотної кінематики (у неї більше ступенів свободи, ніж потрібно насправді для отримання бажаної орієнтації). Ну добре, це вже інша тема, але я подумав, що приємно триматися подалі від шуму, яку ця "легендарна" проблема породила серед програмістів CG ..
teodron

Nitpickery: хоча вісь кута рівнозначний тому, що обидва представлення можуть однозначно представляти всі обертання в SO (3) (добре, по модулю звичайна подвійна кришка), і, звичайно, між ними відбувається майже тривіальне перетворення назад і назад, кватерніони мають перевага полягає в тому, що скласти набагато простіше, ніж усі інші нематричні подання.
Стівен Стадницький

Вони мають перевагу в тому, що вони легше створювати композиції завдяки їх приємній поведінці на будь-якій об'єктно-орієнтованій мові програмування, особливо при використанні операторів перевантаження. Я не впевнений, але, можливо, навіть їх сферичні інтерполяційні властивості зберігають для осі-кута (крім хіба що SQUAD ?!).
теодрон


-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) для позначення кон'югатів, а не зворотних та різних ідентифікаторів, але я сподіваюся, що це можна зрозуміти. Я думаю, що більшість прав, особливо там, де докази реальної частини вектора зникнуть.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.