Korzystanie z Quaternions: Co mogę z nimi zrobić? (bez matematyki)

24

Jestem programistą gier i nie studiowałem matematyki. Chcę tylko używać Quaternions jako narzędzia. Aby móc pracować z obrotem 3D, konieczne jest użycie Quaternions (lub Matryc, ale zatrzymajmy się w Quaternions tutaj w tym pytaniu). Myślę, że jest to ważne dla wielu programistów, aby z nich korzystać. Dlatego chcę podzielić się moją wiedzą i mam nadzieję wypełnić dziury, które mam. Teraz....

O ile rozumiem:

Quaternion może opisać 2 rzeczy:

  1. Obecna orientacja obiektu 3d.
  2. Transformacja obrotu, którą mógłby wykonać Obiekt. (rotationChange)

Możesz zrobić z Quaternion:

Multiplikacje:

  1. Końcówka czwartorzędu = obrót czwartorzędu Zmień * Prąd czwartorzędu;

    Na przykład: Mój obiekt 3D jest obrócony o 90 ° w lewo - a mój obrót zwielokrotniam to obrót o 180 ° w prawo, w końcu mój obiekt 3D jest obrócony w prawo.

  2. Quaternion rotationChange = Quaternion endRotation * Quaternion.Inverse (startRotation);

    Dzięki temu otrzymujesz opcję obrotuZmień, którą można zastosować do innej Orientacji.

  3. Vector3 endPostion = Obrót czwartorzędu Zmień * Vector3 currentPosition;

    Na przykład: Mój obiekt 3D jest w pozycji (0,0,0), a mój obrót zwielokrotniam to obrót o 180 ° w prawo, moja pozycja końcowa jest podobna (0, -50,0). Wewnątrz czwartorzędu znajduje się oś - i obrót wokół tej osi. Obracasz swój punkt wokół tej osi Y stopni.

  4. Vector3 rotatedOffsetVector = Obrót czwartorzędu Zmień * Vector3 currentOffsetVector;

    Na przykład: Mój kierunek startu pokazuje W GÓRĘ - (0,1,0), a mój obrót zwielokrotniam to obrót o 180 ° w prawo, mój kierunek końcowy jest skierowany w dół. (0, -1,0)

Mieszanie (Lerp i Slerp):

  1. Quaternion currentOrientation = Quaternion.Slerp (startOrientation, endOrientation, interpolator)

    jeśli interpolatorem jest 1: currentOrientation = endOrientation

    jeśli interpolatorem jest 0: currentOrientation = startOrientation

    Slerp interpoluje bardziej precyzyjnie, Lerp interpoluje bardziej wydajnie.

Moje pytania):

Czy wszystko, co wyjaśniłem do tej pory, jest prawidłowe?

Czy to „wszystko”, co możesz zrobić z Quaternions? (oczywiście nie)

Co jeszcze możesz z nimi zrobić?

Do czego służą produkty Dot i Cross między 2 czwartorzędami?

Edytować:

Zaktualizowano pytanie z kilkoma odpowiedziami

OC_RaizW
źródło
Powiedz, że nie masz 2, ale nróżne orientacje (postawy, pozy itp.). Następnie możesz je uśrednić za pomocą wag, skutecznie uogólniając slerp / lerp. Możesz także przekształcić ćwiartkę w wirnik, co jest równoważne zastosowaniu prędkości kątowej przez określony czas do sztywnego korpusu. Dlatego też można opisać całkowanie prędkości kątowej również z czwartorzędami. Możesz także oszacować, jak różne są dwie orientacje (obliczyć długość łuku rozpiętego przez dwa ćwiartki na hipersferze).
teodron
I tak, na pierwszy rzut oka twoje uzasadnienie jest prawidłowe (twoje rozumienie czwartorzędów jest całkiem dobre dla osoby nietechnicznej). To nieodpowiednie dla komentarza, ale gratulacje! Nawet utalentowani technicznie nie znają wszystkich zastosowań czwartorzędu, chociaż używają ich tylko jako narzędzia inżynierii oprogramowania do określonego celu.
teodron
4
„Aby móc pracować z obrotem 3D, konieczne jest użycie Czwartorzędów”. Nie mogę wystarczająco podkreślić, jak fałszywe jest to zdanie. Możesz użyć kątów Eulera lub Tait-Bryana do rozwoju gry, jedynym problemem jest blokada gimbala. Jeśli chcesz zostać twórcą gry, w pewnym momencie potrzebujesz matematyki. Naucz się jej.
Bálint
1
„twórca gier” i „nie studiujący matematyki” to oksymoron.
Margaret Bloom
2
Doceniam to, co próbujesz zrobić z pytaniem, ale odpowiedzi powinny zawierać odpowiedź, a nie pytanie. Udziel odpowiedzi „podsumowującej”, jeśli uważasz, że warto je zestawić.
Podstawowy

Odpowiedzi:

23

Mnożenie

Przynajmniej jeśli chodzi o implementację Quaternions przez Unity, kolejność mnożenia opisana w pytaniu jest nieprawidłowa. Jest to ważne, ponieważ obrót 3D nie jest przemienny .

Tak więc, jeśli chcę obrócić obiekt, rotationChangezaczynając od jego currentOrientation, zapisałbym go w następujący sposób:

Quaternion newOrientation = rotationChange * currentOrientation;

(tj. Transformacje układają się w górę w lewo - tak samo jak w konwencji macierzy Unity. Obrót w prawo jest stosowany najpierw / na „najbardziej lokalnym” końcu)

A gdybym chciał przekształcić kierunek lub wektor przesunięcia przez obrót, zapisałbym to w ten sposób:

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(Unity wygeneruje błąd kompilacji, jeśli zrobisz coś przeciwnego)

Mieszanie

W większości przypadków można uniknąć rotacji Lerping. Wynika to z faktu, że kąt zastosowany „pod maską” w ćwiartce jest o połowę mniejszy od obrotu, co czyni go znacznie bliższym liniowemu przybliżeniu Lerpa niż coś w rodzaju Matrycy (która ogólnie nie będzie dobrze Lerpem!). Zapoznaj się z około 40 minutami tego filmu, aby uzyskać więcej wyjaśnień .

Jedynym przypadkiem, gdy naprawdę potrzebujesz Slerpa, jest to, że potrzebujesz stałej prędkości w czasie, na przykład interpolacji między klatkami kluczowymi na osi czasu animacji. W przypadkach, w których zależy ci tylko na tym, aby wynik był pośredni między dwoma wejściami (jak mieszanie warstw animacji), zwykle Lerp działa całkiem dobrze.

Co jeszcze?

Iloczyn skalarny dwóch kwaternionów jednostkowych daje cosinus kąta między nimi, dzięki czemu można korzystać z iloczynu skalarnego jako miara podobieństwa jeśli trzeba porównać obroty. Jest to jednak trochę niejasne, więc dla bardziej czytelnego kodu często używałbym Quaternion.Angle (a, b) , co wyraźniej wyraża, że ​​porównujemy kąty w znanych jednostkach (stopniach).

Tego rodzaju metody wygody, które Unity zapewnia dla Quaternions, są bardzo przydatne. W prawie każdym projekcie używam tego co najmniej kilka razy :

Quaternion.LookRotation(Vector3 forward, Vector3 up)

Tworzy to kwaternion, który:

  • obraca lokalną oś z +, aby wskazywać dokładnie wzdłuż forwardargumentu wektorowego
  • obraca lokalną oś y +, aby wskazywała jak najbliżej upargumentu wektorowego, jeśli jest podany, lub (0, 1, 0)jeśli jest pominięty

Powodem, dla którego „wzrost” jest „jak najbliższy”, jest to, że system jest zawyżony. Stawianie forwardczoła z + powoduje wykorzystanie dwóch stopni swobody (tj. Odchylenie i skok), więc mamy tylko jeden stopień swobody (przechylenie).

Dość często szukam czegoś o przeciwnych właściwościach dokładności: chcę, aby lokalny y + wskazywał dokładnie wzdłuż up, a lokalny z + zbliżał się tak blisko, jak to możliwe forwardz pozostałą swobodą.

Pojawia się to na przykład podczas próby utworzenia ramki współrzędnych względem kamery do wprowadzania ruchu: chcę, aby mój lokalny kierunek w górę pozostawał prostopadły do ​​podłogi lub nachylonej powierzchni normalnej, więc mój wkład nie próbuje tunelować postaci w teren lub lewitować ich z tego.

Możesz to również uzyskać, jeśli chcesz, aby obudowa wieży skierowana była w stronę celu, bez odrywania się od korpusu czołgu podczas celowania w górę / w dół.

W tym celu możemy zbudować naszą własną funkcję wygody, używając LookRotationdo podnoszenia ciężkich przedmiotów:

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
    Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);

    return rotateZToUp * rotateYToZ;
}

Tutaj najpierw obracamy lokalne y + do z +, a lokalne z + do y-.

Następnie obracamy nowe z + do naszego kierunku w górę (więc wynik netto to lokalne y + punkty bezpośrednio wzdłuż exactUp), a nowy y + jak najbliżej zanegowanego kierunku do przodu (więc wynik netto to lokalne punkty + + jak najbliżej) approximateForward)

Inną przydatną metodą wygody jest Quaternion.RotateTowards, z której często korzystam:

Quaternion newRotation = Quaternion.RotateTowards(
                             oldRotation, 
                             targetRotation,
                             maxDegreesPerSecond * Time.deltaTime
                         );

To pozwala nam zbliżać się targetRotationze stałą, kontrolowaną prędkością bez względu na liczbę klatek na sekundę - ważne dla rotacji, które wpływają na wynik / uczciwość mechaniki rozgrywki (np. Obracanie ruchu postaci lub śledzenie wieżyczki na graczu). Naiwny Lerping / Slerping w tej sytuacji może łatwo prowadzić do przypadków, w których ruch staje się szybszy przy wysokich prędkościach klatek, co wpływa na równowagę gry. (Nie oznacza to, że te metody są niewłaściwe - istnieją sposoby na ich prawidłowe użycie bez zmiany uczciwości, wymaga jedynie opieki. RotateTowardsDaje wygodny skrót, który się tym za nas opiekuje)

DMGregory
źródło
Wskazówka: Dodaj & t = 40 m na końcu adresu URL filmu, aby przeskoczył tam prosto (opcjonalnie np. 40m5s). Produkty kropek czwartorzędowe przydają się również w przypadku sferycznych światów gier - lub szerzej w przypadku orientowania fragmentów wirujących sfer.
Luke Briggs,
@Luke Briggs: Sferyczny punkt świata gry brzmi, jakbyś był wart rozwinięcia swojej własnej odpowiedzi (szczególnie z diagramami), gdybyś był na to gotowy. :)
DMGregory
Świetny pomysł - tutaj jest trzecia nad ranem (więc myślę, że wyjdzie to trochę bełkotu!), Ale chętnie połączę coś jutro (jeśli pamiętam!)
Luke Briggs,
1
Edycja: Trochę mnie poniosło myślenie o odpowiedzi, więc wyzwanie zostało przyjęte! Przynajmniej zaznaczę to jako szorstkie cięcie, aby ludzie mogli zdawać sobie sprawę z późnego poparzenia nocy, które do niego doszło: P
Luke Briggs
No to jedziemy! Próbowałem przedstawić to w formie graficznego przeglądu na podstawie tego, że twoja odpowiedź naprawdę dobrze obejmuje podstawowe funkcje. Czas na sen, tak myślę!
Luke Briggs,
14

Gdzie jest używany produkt kropkowy?

W Unity jednym z najczęstszych użytkowników produktu kropkowego jest za każdym razem, gdy sprawdzisz, czy dwa czwarte są równe przez ==lub !=. Unity oblicza iloczyn skalarny, aby sprawdzić podobieństwo zamiast bezpośrednio porównywać wewnętrzne wartości x, y, z, w. Warto o tym pamiętać, ponieważ powoduje to, że połączenie jest droższe, niż można się spodziewać.

Używamy go również w ciekawym przypadku użycia ..

Zabawa z produktami kropek czwartorzędowych - sferyczne światy i orbitale

Coraz powszechniejsze stają się symulacje całych planet, a nawet całych układów słonecznych. Aby to zrobić w czasie rzeczywistym, potrzebujemy również produktu kropki czwartorzędu. Wiele z nich. Produkt kropki czwartorzędu jest bardzo słabo wykorzystywany, ale z pewnością ma swoje zastosowania - rzućmy okiem

Po pierwsze, mamy do rozważenia całą serię obrotów:

  1. (Opcjonalnie) Gwiazda wokół centrum galaktyki
  2. Planeta wokół gwiazdy
  3. Pochylenie planety
  4. Obrót planety
  5. Położenie pobliskich komórek siatki (obróconych wokół rdzenia planet) *
  6. Wiele płaszczyzn orbitalnych

Połącz je wszystkie razem, a skończysz z dużą złożonością (i dużą liczbą!). Kiedy widz stoi na powierzchni planety, nie chcemy, aby pędzili z niesamowitą prędkością przez naszą przestrzeń świata gry. W rzeczywistości wolelibyśmy, aby były nieruchome i gdzieś w pobliżu źródła - zamiast tego przenieś wszechświat wokół gracza.

Obracająca się planeta

Co ważne, abyśmy w tym scenariuszu mogli uzyskać prawidłowy obrót i pochylenie planety, musimy zablokować biegun w osi, aby mógł on tylko przesuwać się w górę / w dół na powyższym obrazie (tj. Przesuwać „w górę” podczas podróży gracza północ). Właśnie tam pojawia się iloczyn czwartorzędowy. Gdybyśmy nie użyli iloczynu kropkowego i zamiast tego pomnożyli również nachylenie, to by się stało:

Nieprawidłowo przechylone „planety”

Zauważ, że bieguny naszych orbitujących „planet” zawsze przechylają się w kierunku gwiazdy. W rzeczywistości tak się nie dzieje - przechylenie jest ustalone .

Bez wchodzenia zbyt daleko w temat, oto krótkie podsumowanie:

  • Orientacja na kuli również starannie opisuje pozycję na powierzchni.
  • Mamy wiele rotacji do połączenia.
  • Opisz wszystko jako obrót; pozycja widza również. Pomaga to zwiększyć wydajność, ponieważ ostatecznie wykonujemy mniej operacji.
  • Kąt między obrotami (nasz iloczyn skalarny) pomaga następnie zmierzyć długość geograficzną i działa szczególnie dobrze w radzeniu sobie z przechyłami.

Uzyskując tylko kąt, upuszczamy część tego niechcianego obrotu . W tym samym czasie zakończyliśmy również pomiar długości geograficznej, który jest przydatny do nawigacji, a także lokalnego klimatu.

* Planety są zbudowane z wielu komórek siatki . Wyświetlane są tylko te znajdujące się w pobliżu.

Luke Briggs
źródło
2
To świetna robota, ustalając scenę i motywując problem, ale wciąż jestem trochę rozmyślany nad tym, jak matematyka iloczynu czwartorzędowego (tj. Iloczynu skalarnego dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.ww przeciwieństwie do składu czwartorzędowego, którego użylibyśmy do połączenia rotacje) pomogłyby nam rozwiązać ten problem. Z przyjemnością głosuję, jeśli będziesz w stanie rozwinąć tę kwestię nieco później (nie mam na myśli powstrzymywania cię od skąpstwa ... Mam na myśli sen!)
DMGregory
@DmGregory, krótka odpowiedź to tilt jest dziwny; wszystko ładnie komponuje się z wyjątkiem tego (w przeciwnym razie planeta kołysałaby się wokół swojej gwiazdy). (Mam nadzieję!) Dodam jutro trochę więcej kontekstu!
Luke Briggs,
@DMGregory Dodałem kilka dodatkowych informacji (nie mogłem spać!) - mam nadzieję, że to wszystko wyjaśni.
Luke Briggs,
1
Przepraszam, jeśli jestem trochę gęsty, ale po kilkukrotnym przeczytaniu nadal nie wiem, jak użyłbym produktu kropkowego w formule, aby osiągnąć opisaną transformację. Czy byłbyś w stanie dodać mały pseudokod określający operacje, które wykonujesz jawnie?
DMGregory
@DMGregory Nie znam czwartorzędów, ale jeśli są to rotacje na kuli, to nie są to kompozycje rotacyjne. Wykorzystuje się geometrię sferyczną z wektorami do obliczenia wektora normalnego dla „linii” na powierzchni kuli AKA o dowolnym obwodzie. Po raz kolejny odpowiedź nie ma sensu, podobnie jak to pytanie, ale uważam, że używają geometrii sferycznej.
The Great Duck