Mam dwa wektory u i v. Czy istnieje sposób na znalezienie kwaternionu reprezentującego obrót od u do v?
math
vector
quaternions
sdfqwerqaz1
źródło
źródło
crossproduct
nie będzie prawidłowy w tych przypadkach, więc najpierw musisz sprawdzićdot(v1, v2) > 0.999999
idot(v1, v2) < -0.999999
, odpowiednio, i albo zwrócić quat identyfikacyjny dla równoległych wektorów, albo zwrócić obrót o 180 stopni (wokół dowolnej osi) dla przeciwnych wektorów.sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
upraszczav1.Length * v2.Length
. Nie mogłem znaleźć żadnej odmiany tego, aby uzyskać rozsądne wyniki.Rozwiązanie wektorowe w połowie drogi
Wymyśliłem rozwiązanie, które moim zdaniem Imbrondir próbował zaprezentować (aczkolwiek z drobnym błędem, który prawdopodobnie był powodem, dla którego sinisterchipmunk miał problem z weryfikacją).
Zakładając, że możemy skonstruować kwaternion reprezentujący obrót wokół osi w następujący sposób:
I że kropka i iloczyn poprzeczny dwóch znormalizowanych wektorów to:
Widząc, że obrót od u do v można osiągnąć obracając o theta (kąt między wektorami) wokół prostopadłego wektora, wygląda na to, że możemy bezpośrednio skonstruować kwaternion reprezentujący taki obrót z wyników kropki i iloczynów poprzecznych ; jednakże w obecnej postaci theta = kąt / 2 , co oznacza, że spowodowałoby to dwukrotność pożądanego obrotu.
Jednym z rozwiązań jest obliczenie wektora w połowie drogi między u i v i użycie kropki i iloczynu poprzecznego u oraz wektora połowy drogi do skonstruowania kwaternionu reprezentującego obrót o dwukrotności kąta między u a wektorem w połowie drogi , co prowadzi nas aż do v !
Istnieje specjalny przypadek, w którym u == -v i unikatowy wektor połówkowy staje się niemożliwy do obliczenia. Jest to oczekiwane, biorąc pod uwagę nieskończenie wiele obrotów „najkrótszego łuku”, które mogą prowadzić nas od u do v , i musimy po prostu obrócić o 180 stopni wokół dowolnego wektora prostopadłego do u (lub v ), co jest naszym rozwiązaniem w przypadku szczególnym. Odbywa się to poprzez znormalizowany iloczynu U z dowolnym innym wektorem nie równolegle do u .
Następuje pseudokod (oczywiście w rzeczywistości szczególny przypadek musiałby uwzględniać niedokładności zmiennoprzecinkowe - prawdopodobnie poprzez sprawdzanie iloczynów skalarnych względem jakiegoś progu, a nie wartości bezwzględnej).
Zauważ również, że nie ma specjalnego przypadku, gdy u == v (tworzony jest kwaternion tożsamości - sprawdź i przekonaj się sam).
orthogonal
Zwraca dowolny wektor prostopadły do danego wektora. Ta implementacja używa iloczynu krzyżowego z najbardziej ortogonalnym wektorem bazowym.Rozwiązanie Half-Way Quaternion
W rzeczywistości jest to rozwiązanie przedstawione w przyjętej odpowiedzi i wydaje się być nieznacznie szybsze niż rozwiązanie wektorowe w połowie drogi (~ 20% szybciej według moich pomiarów, choć nie wierz mi na słowo). Dodam to tutaj na wypadek, gdyby inni tacy jak ja byli zainteresowani wyjaśnieniem.
Zasadniczo, zamiast obliczać kwaternion przy użyciu wektora połówkowego, można obliczyć kwaternion, która daje dwukrotność wymaganego obrotu (jak opisano w drugim rozwiązaniu) i znaleźć kwaternion w połowie odległości między tym a zerem stopni.
Jak wyjaśniłem wcześniej, kwaternion dla podwójnej wymaganej rotacji wynosi:
A kwaternion dla rotacji zerowej to:
Obliczanie kwaternionów w połowie drogi polega po prostu na sumowaniu kwaternionów i normalizacji wyniku, podobnie jak w przypadku wektorów. Jednak, podobnie jak w przypadku wektorów, kwaterniony muszą mieć tę samą wielkość, w przeciwnym razie wynik będzie pochylony w kierunku kwaternionu o większej wielkości.
Kwaternion zbudowana z punktów i dwóch wektorów będzie miał taką samą wielkość jak w przypadku produktów:
length(u) * length(v)
. Zamiast dzielić wszystkie cztery składniki przez ten czynnik, możemy zamiast tego skalować w górę kwaternion tożsamości. A jeśli zastanawiałeś się, dlaczego zaakceptowana odpowiedź pozornie komplikuje sprawę przy użyciusqrt(length(u) ^ 2 * length(v) ^ 2)
, to dlatego, że długość kwadratu wektora jest szybsza do obliczenia niż długość, więc możemy zapisać jednosqrt
obliczenie. Wynik to:A następnie znormalizuj wynik. Pseudokod następujący:
źródło
Przedstawiony problem nie jest dobrze zdefiniowany: nie ma unikalnej rotacji dla danej pary wektorów. Rozważmy na przykład przypadek, w którym u = <1, 0, 0> i v = <0, 1, 0> . Jeden obrót od u do v byłby obrotem pi / 2 wokół osi z. Kolejny obrót od u do v oznaczałby obrót pi wokół wektora <1, 1, 0> .
źródło
Dlaczego nie przedstawić wektora za pomocą czystych kwaternionów? Może lepiej, jeśli najpierw je znormalizujesz.
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q rot = q 2
Pomnóż wstępnie przez q 1 -1
q rot = q 1 -1 q 2
gdzie q 1 -1 = q 1 spój / q norm
Można to traktować jako „lewy podział”. Dzielenie od prawej, które nie jest tym, czego chcesz, to:
q rot, right = q 2 -1 q 1
źródło
Nie jestem dobry w Quaternion. Jednak walczyłem z tym godzinami i nie mogłem sprawić, by rozwiązanie Polaris878 działało. Próbowałem przed normalizacją v1 i v2. Normalizowanie q. Normalizowanie q.xyz. Jednak nadal nie rozumiem. Wynik nadal nie dał mi właściwego wyniku.
W końcu jednak znalazłem rozwiązanie, które to zrobiło. Jeśli to pomoże komuś innemu, oto mój działający (w Pythonie) kod:
Należy zrobić specjalny przypadek, jeśli v1 i v2 są równoległe, jak v1 == v2 lub v1 == -v2 (z pewną tolerancją), gdzie uważam, że rozwiązaniami powinny być Quaternion (1, 0,0,0) (bez rotacji) lub Quaternion (0, * v1) (obrót o 180 stopni)
źródło
quat = diffVectors(v1, v2); assert quat * v1 == v2
.angle
uzyskuje swoją wartość z iloczynu skalarnego.Wydaje się, że niektóre odpowiedzi nie uwzględniają możliwości, że iloczyn poprzeczny może wynosić 0. Poniższy fragment wykorzystuje reprezentację kąta-osi:
toQuaternion
Mogą być realizowane w następujący sposób:Jeśli korzystasz z biblioteki Eigen, możesz również po prostu:
źródło
toQuaternion(axis, ang)
-> zapomniałeś sprecyzować, co to jestang
angle
częścią reprezentacji kąta osi kwaternionu, mierzoną w radianach.Z punktu widzenia algorytmu najszybsze rozwiązanie wygląda w pseudokodzie
Upewnij się, że potrzebujesz kwaternionów jednostkowych (zwykle jest to wymagane do interpolacji).
UWAGA: Quaternions inne niż jednostki mogą być używane z niektórymi operacjami szybciej niż jednostka.
źródło