Kwarteniony (Quaternions) w kosmicznym trójwymiarze

Teoria

Kwartenionów (z ang. Quaternion) można użyć do zapobieżenia utraty stopnia swobody (tzw. Gimbal Lock).

Każdy Kwartenion składa się z dwóch elementów – wektora w przestrzeni urojonej, służącego do określenia osi obrotu w trzech wymiarach, oraz skalara oznaczającego kąt obrotu wokół zdefiniowanej osi.

Poniżej znajduje się rysunek obrazujący ideę użycia Kwartenionu do przeprowadzenia rotacji w trójwymiarowym świecie.

quaternion

Kolejne kolorowe osie (czerwona, zielona i niebieska) reprezentują poszczególne kierunki trójwymiarowego świata. Czarna strzałka jest wektorem w przestrzeni urojonej, i jest zarazem osią obrotu (rotation axis). Kąt obrotu (rotation angle) określany jest przez rzeczywisty skalar Kwartenionu.

Praktyka

Użyjmy Kwartenionów do przeprowadzenia rotacji w trójwymiarowym świecie. Jako wejście posłuży nam ruch myszki – odbywa się on w dwóch kierunkach, tzn. na boki, i z góry na dół. Przyjmijmy zatem, że odległość od środka ekranu będzie wartością zmiany położenia kamery:

dx = mouse.getX()
dy = mouse.getY()

Można założyć, że dx i dy to zmiany w poziomie i w pionie w przestrzeni Eulerowskiej. Jeśli użylibyśmy bezpośrednio tych zmiennych do rotacji utracilibyśmy stopień swobody przy osiągnięciu rotacji 90′:

glRotated(dx, 1, 0, 0)
glRotated(dy, 0, 1, 0)

Sięgnijmy po Kwaterniony. Określmy najpierw jeden Kwaternion, będący naszym punktem w przestrzeni, którego będziemy obracać. Zacznijmy od Kwartenionu jednostkowego:

Quaternion position = new Quaternion(0, 0, 0, 1);

To on będzie wyznaczał nasze osie obrotu – nie Eulerowski układ współrzędnych. Weźmy nasze zmiany prędkości obrotu i stwórzmy odpowiedni Kwartenion:

Quaternion rotation = new Quaternion().fromEuler(dx, dy, 0)

Teraz zaaplikujmy naszą rotację do pozycji, którą określiliśmy wcześniej. Wykorzystamy mnożenie Kwartenionów:

position = rotation * position

Otrzymaliśmy przekształconą, niezależną pozycję naszego punktu w przestrzeni. Wykonajmy więc rotację macierzy obrotu przy pomocy naszego Kwaterniona. Aby to zrobić, musimy zamienić go na postać osi obrotu:

x, y, z
rotationAngle = position.toAxisAngle(x, y, z)

Czyli musimy uzyskać naszą oś i kąt obrotu. W takiej postaci możemy zaaplikować naszą rotację do macierzy obrotu:

glRotated(rotationAngle, x, y, z)

W ten sposób uwolniliśmy się od utraty stopni swobody przy pomocy niezależnego od osi obrotu Kwarteniona.

Ten wpis został opublikowany w kategorii Bez kategorii. Dodaj zakładkę do bezpośredniego odnośnika.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *