W jaki sposób rozwiązano problem zablokowania gimbala za pomocą akumulacyjnych transformacji macierzowych

12

Czytam książkę online „Uczenie się nowoczesnego programowania grafiki 3D” Jasona L. McKessona

Na razie mam problem z blokadą gimbala i jak go rozwiązać za pomocą czwartorzędów.

Jednak tutaj, na stronie Quaternions .

Częściowym problemem jest to, że próbujemy zapisać orientację jako serię 3 skumulowanych obrotów osiowych. Orientacje to orientacje, a nie rotacje. A orientacje z pewnością nie są serią obrotów. Musimy więc traktować orientację statku jako orientację, jako określoną ilość.

Wydaje mi się, że to pierwsze miejsce, w którym zaczynam się mylić. Powodem jest to, że nie widzę dramatycznej różnicy między orientacjami a obrotami. Nie rozumiem też, dlaczego orientacja nie może być reprezentowana przez serię obrotów ...

Również:

Pierwszą myślą w tym celu byłoby zachowanie orientacji jako matrycy. Kiedy nadchodzi czas na modyfikację orientacji, po prostu stosujemy transformację do tej macierzy, zapisując wynik jako nową bieżącą orientację.

Oznacza to, że każde odchylenie, skok i przechylenie zastosowane do bieżącej orientacji będzie względem tej bieżącej orientacji. Właśnie tego potrzebujemy. Jeśli użytkownik zastosuje odchylenie dodatnie, chcesz, aby odchylenie obracało je względem miejsca, w którym są obecnie skierowane, a nie względem jakiegoś stałego układu współrzędnych.

Rozumiem pojęcie, ale nie rozumiem, w jaki sposób, jeśli akumulacja transformacji macierzowych jest rozwiązaniem tego problemu, w jaki sposób kod podany na poprzedniej stronie to nie tylko to.

Oto kod:

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack currMatrix;
    currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
    currMatrix.RotateX(g_angles.fAngleX);
    DrawGimbal(currMatrix, GIMBAL_X_AXIS, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
    currMatrix.RotateY(g_angles.fAngleY);
    DrawGimbal(currMatrix, GIMBAL_Y_AXIS, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
    currMatrix.RotateZ(g_angles.fAngleZ);
    DrawGimbal(currMatrix, GIMBAL_Z_AXIS, glm::vec4(1.0f, 0.3f, 0.3f, 1.0f));

    glUseProgram(theProgram);
    currMatrix.Scale(3.0, 3.0, 3.0);
    currMatrix.RotateX(-90);
    //Set the base color for this object.
    glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
    glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

    g_pObject->Render("tint");

    glUseProgram(0);

    glutSwapBuffers();
}

Według mnie, to, co robi (modyfikując macierz na stosie), nie rozważa akumulacji macierzy, ponieważ autor połączył wszystkie indywidualne transformacje obrotu w jedną macierz, która jest przechowywana na górze stosu.

Rozumiem, że macierz polega na tym, że są one używane do ustalenia punktu względem początku (powiedzmy ... modelu) i uczynienia go względem innego początku (kamery). Jestem pewien, że jest to bezpieczna definicja, ale wydaje mi się, że brakuje czegoś, co blokuje mi zrozumienie problemu blokady gimbala.

Jedną rzeczą, która nie ma dla mnie sensu jest: jeśli macierz określa różnicę względną między dwiema „spacjami”, to dlaczego obrót wokół osi Y dla, powiedzmy, toczenia, nie umieszcza punktu w „przestrzeni toczenia” „które można następnie przekształcić jeszcze raz w stosunku do tego rzutu ... Innymi słowy, żadne dalsze przekształcenia do tego punktu nie powinny dotyczyć tej nowej„ przestrzeni rzutu ”, a zatem nie powinny mieć obrotu względem poprzedniego” model area ”, co powoduje blokadę kardanową.

Właśnie dlatego występuje blokada gimbala, prawda? Wynika to z faktu, że obracamy obiekt wokół osi X, Y i Z, zamiast obracać obiekt wokół własnych osi względnych . A może się mylę?

Ponieważ najwyraźniej ten kod, który podłączyłem, nie jest kumulacją transformacji macierzy, możesz podać przykład rozwiązania wykorzystującego tę metodę.

Podsumowując:

  • Jaka jest różnica między obrotem a orientacją?
  • Dlaczego kod nie jest powiązany z przykładem akumulacji transformacji macierzowych?
  • Jaki jest prawdziwy, konkretny cel matrycy, jeśli źle ją popełniłem?
  • Jak można rozwiązać problem blokady gimbala za pomocą akumulacji transformacji macierzowych?
  • Dodatkowo, jako bonus: dlaczego przekształcenia po obrocie są nadal względem „obszaru modelu”?
  • Kolejna premia: czy mylę się przy założeniu, że po transformacji nastąpią dalsze transformacje w stosunku do prądu?

Ponadto, jeśli nie zostało to dorozumiane, używam OpenGL, GLSL, C ++ i GLM, więc przykłady i objaśnienia w odniesieniu do nich są bardzo mile widziane, jeśli nie są konieczne.

Im więcej szczegółów, tym lepiej!

Z góry dziękuję.

Łukasz San Antonio Białecki
źródło

Odpowiedzi:

11

Nie jestem pewien, czy jest to dobry sposób na przedłożenie tego, poza tym, że mam nadzieję, że do końca ładnie się ze sobą łączy. To powiedziawszy, zanurzmy się w:

Rotacja i orientacja są różne, ponieważ pierwsza opisuje transformację, a druga opisuje stan. Obrót to sposób, w jaki obiekt przechodzi w orientację , a orientacja to lokalna obrócona przestrzeń obiektu . Może to być bezpośrednio związane z matematycznym przedstawieniem tych dwóch elementów: macierz przechowuje transformacje z jednej przestrzeni współrzędnych do drugiej (poprawność była poprawna), a kwaternion bezpośrednio opisuje orientację. Dlatego macierz może opisać tylko, w jaki sposób obiekt orientuje się , poprzez serię obrotów. Problemem jest jednak blokada gimbala.

Blokada gimbala pokazuje trudność w ustawieniu obiektu za pomocą serii obrotów. Problem występuje, gdy co najmniej dwie z osi obrotu są wyrównane:

Zdjęcie dzięki uprzejmości deepmesh3d.com
Na lewym zdjęciu powyżej niebieskie i pomarańczowe osie wykonują ten sam obrót! Jest to problem, ponieważ oznacza to, że jeden z trzech stopni swobody został utracony, a dodatkowe obroty z tego punktu mogą dawać nieoczekiwane rezultaty. Zastosowanie czwartorzędów rozwiązuje ten problem, ponieważ zastosowanie czwartorzędu do przekształcenia orientacji obiektu spowoduje bezpośrednie ustawienie nowej orientacji obiektu (to najlepszy sposób, jaki mogę to powiedzieć), zamiast rozbijania transformacji na operacje przewijania, skoku i odchylenia.

Teraz jestem sceptycznie nastawiony do tego, że akumulowanie matryc jest kompletnym rozwiązaniem tego problemu, ponieważ akumulacja matryc (a zatem akumulacja rotacji) jest dokładnie tym, co może spowodować problem z blokadą Gimbala. Właściwym sposobem obsługi transformacji przez ćwiartkę jest wykonanie mnożenia czwartorzędu w punkcie:

pTransformed = q * pAsQuaternion * qConjugate

lub przez przekształcenie czwartorzędu w macierz i przekształcenie punktu za pomocą tej macierzy.

Zwykły obrót matrycy (taki jak odchylenie o 45 stopni) zawsze będzie definiowany w przestrzeni globalnej. Jeśli chcesz zastosować transformację w przestrzeni lokalnej, musisz przekształcić transformację w lokalną przestrzeń tych obiektów. Brzmi dziwnie, więc rozwinę się. W tym miejscu wkracza znaczenie kolejności rotacji. Polecam tu wziąć książkę, abyś mógł śledzić transformacje.

Zacznij od książki płaskiej, z okładką skierowaną do góry pod sufitem, zorientowaną tak, jakbyś miał ją otworzyć i zacząć czytać. Teraz przechyl przód książki o 45 stopni (przednia okładka powinna z grubsza być skierowana w Twoją stronę):

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(45);

Powiedzmy, że chcesz wyregulować odchylenie książki o 45 stopni (myślę, że zakładam układ współrzędnych po prawej stronie, więc zmieni się kierunek w lewo), i chcesz, aby to dotyczyło lokalnej książki koordynuj przestrzeń, aby okładka książki nadal była skierowana w Twoją stronę:

bookMatrix.RotateY(45);

Problem polega na tym, że ten obrót występuje w globalnej przestrzeni współrzędnych, więc okładka książki kończy się przodem do twojego prawego ramienia. Aby ta zmiana kierunku miała miejsce w lokalnej przestrzeni współrzędnych, należy ją najpierw zastosować!

glutil::MatrixStack bookMatrix;
bookMatrix.RotateY(45);
bookMatrix.RotateX(45);

Wypróbuj to! Zacznij od nowa książkę skierowaną do góry pod sufitem. Zmień jego odchylenie o 45 stopni, a następnie ustaw go o 45 stopni wzdłuż globalnej osi X (biegnącej od lewej do prawej). Tej orientacji oczekiwałeś ze skokiem 45 i odchyleniem 45 w lokalnej przestrzeni książki.

Co to znaczy? Wszystko sprowadza się do tego, że kolejność operacji ma znaczenie. Dokonane transformacje stają się najpierw transformacjami lokalnymi w kontekście transformacji wykonanych później. Dużo staje się wokół głowy i w ten sposób czwartorzędy oszczędzają wielu kłopotów. Pomiń wszystkie rzeczy zależne od zamówienia.

Inną ogromną zaletą czwartorzędów jest to, że umożliwiają interpolację orientacji. Próba interpolacji między kątami Eulera jest prawie niemożliwa z powodu zależności od kolejności. Matematyczne właściwości czwartorzędu pozwalają na dobrze zdefiniowaną sferyczną interpolację liniową między nimi.

Podsumowując i rozwiązując pierwotne pytanie: akumulacyjne transformacje macierzowe naprawdę nie rozwiążą problemu blokady Gimbala, chyba że transformacje zostaną starannie wybrane i zastosowane w dokładnej kolejności. Dlatego zawsze używaj czwartorzędów i stosuj czwartorzędy do punktów za pomocą mnożenia czwartorzędów.

Mam nadzieję że to pomoże :)

kevintodisco
źródło
4
tylko dla przypomnienia, czwartorzędy mogą nadal wprowadzać blokadę gimbala, jeśli opisano to za pomocą kątów Eulera; ponieważ będziesz wykonywać te same obliczenia w inny sposób (czwartorzędy niż macierze)
concept3d
1
@ concept3d - gratulacje za wspomnienie o tym! Ważne jest, aby zrozumieć, co powoduje, że mechanizm gimbala jest podatny na utratę pewnego stopnia swobody: jest to jak połączenie zrobotyzowane nieodłącznie opisujące nadmiernie określony układ równań. Jeśli zbudujesz ten mechanizm z czwartorzędami, matrycami lub magią, nadal będziesz miał dwuznaczności - rozumienie go i nieużywanie go w pierwszej kolejności jest prawdziwym rozwiązaniem (chyba że musisz go używać do celów demonstracyjnych lub technicznych) .
teodron
ćwiartki są trudne do wyobrażenia, zawsze myślę o tym, że one (ćwiartki jednostkowe) reprezentują przestrzeń 3-sferyczną, stąd mogą reprezentować dowolną orientację, podczas gdy rozumiem, że kąty Eulera reprezentują koła / turos, stąd nie jest to kompletna sfera nie jest zbyt dokładnym sposobem przedstawienia orientacji (3 koła / torus nie mogą tak naprawdę wygenerować każdej możliwej orientacji, chyba że obracają się one niezależnie, co nie jest możliwe w przypadku kątów eulera), nie jestem pewien, czy dokładnie to wytłumaczyłem :)
concept3d
1

Nagromadzenie macierzy może w rzeczywistości rozwiązać blokadę gimbala. Gromadząc obroty, dodajesz kardana, umożliwiając dowolną rotację. Schemat dostarczony przez ktodisco pokazuje blokadę gimbala na lewym schemacie. Macierz dla tej orientacji można zdefiniować jako:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);

Z powodu rotacji gimbala y gimbale X i Z są teraz zablokowane, więc straciliśmy jeden stopień ruchu. W tym momencie nie mamy ziewania (lokalne y, globalne z) za pomocą tych trzech kardanowych. Ale dodając kolejny gimbal, mogę obracać się lokalnie wokół y:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);
bookMatrix.RotateY(90);

Dla każdego nowego rzutu, skoku i odchylenia po prostu dodaj kolejny gimbal, Kumulując je w jedną matrycę. Tak więc za każdym razem, gdy potrzebny jest kolejny obrót lokalny, tworzony jest obrót i mnożony do macierzy akumulacji. Jak wspomniano w rozdziale, nadal występują problemy, ale blokada gimbala nie jest jedną z nich.

Justin Ehrlich
źródło