Obrót kamery 3D

9

Proszę, wybacz mi, ale potrzebuję pomocy i utknąłem w tym od kilku tygodni, nie robię postępów i wszędzie idę i widzę inną odpowiedź, wszystko, co próbuję, nie działa. Mam już wystarczająco dużo wskazówek i porad, teraz naprawdę potrzebuję tylko kogoś, kto udzieli mi odpowiedzi, aby móc pracować wstecz, ponieważ nie mogę tego zrozumieć.

To, co sprawiło, że ten temat jest najbardziej zagmatwany, to sposób, w jaki każdy stosuje inny zestaw konwencji lub reguł, a ich odpowiedzi oparte są na ich własnych konwencjach, nie określając, czym one są.

Oto zestaw konwencji, które utworzyłem w oparciu o to, co wydaje się najbardziej powszechne i logiczne:

  1. Reguła prawej ręki dla osi.
  2. Pozytywne Y jest w górę, Pozytywne Z jest skierowane w stronę widza, Pozytywne X jest w prawo.
  3. Wiersze Główne matryce, transponowane, gdy są wysyłane do shaderów.
    • Skok: obrót wokół osi X.
    • Odchylenie: obrót wokół osi y
    • Roll: obrót wokół osi Z.
  4. Kolejność rotacji: Roll, Pitch, Yaw (czy to prawda? Czy ktoś może mnie sprawdzić?)
  5. Dodatnie wartości obrotu, patrząc od dodatniego końca osi, powodują obrót w prawo.
  6. Domyślnym kierunkiem obrotu 0 we wszystkich osiach jest wektor skierowany w dół do ujemnego Y.

.. biorąc pod uwagę te konwencje (z całą pewnością popraw mnie, jeśli się mylą!), w jaki sposób:

  • Napisz funkcję LookAt? (lookAt (pozycja wektora, wektorowe ustawienie ostrości, wektor w górę))
  • Oblicz macierz obrotu. (obrót (x, y, z))

Próbowałem odpowiedzieć na te dwa pytania samemu przynajmniej w ciągu ostatnich 3 tygodni, przepisałem moją funkcję LookAt & Rotation Matrix co najmniej 30 razy, przetestowałem dziesiątki metod i przeczytałem materiał, który widziałem na setki stron internetowych i przeczytałem wiele odpowiedzi na pytania, skopiowałem kod innych osób i nic, co do tej pory nie zrobiłem, nie zadziałało, wszystko przyniosło zły wynik. Niektóre z nich stworzyły zabawnie dziwaczne wyniki, które nie są nawet bliskie prawidłowej rotacji.

Pracowałem nad tym każdej nocy, z wyjątkiem ostatniej nocy, ponieważ byłem tak sfrustrowany powtarzającymi się niepowodzeniami, że musiałem się zatrzymać i zrobić sobie przerwę.

Proszę, po prostu pokaż mi, jaka jest poprawna metoda, abym mógł cofnąć się od tego i dowiedzieć się, jak to działa, po prostu nie otrzymuję poprawnej odpowiedzi, co doprowadza mnie do szału!

Piszę w Javie, ale wezmę kod napisany w dowolnym języku, większość mojego kodu do renderowania 3D działa naprawdę doskonale, to tylko matematyka, której nie rozumiem.

AKTUALIZACJA: ROZWIĄZANE

Dziękuję za pomoc! Mam teraz działającą funkcję LookAt, którą właściwie rozumiem i nie mogłem być szczęśliwszy (jeśli ktoś chciałby to zobaczyć, pytaj).

Ponownie próbowałem utworzyć matrycę obrotu opartą na zmiennych nachylenia / odchylenia / przechylenia i znów wydawało się, że zawiodło, ale zdecydowałem się zrzucić próbę użycia kątów Eulera dla kamery freelook, ponieważ wydaje się ona nieodpowiednia dla rola, zamiast tego zamierzam stworzyć klasę czwartorzędową, może lepiej będzie zejść tą ścieżką, w przeciwnym razie skorzystam z pitch / yaw jako współrzędnych sferycznych i polegam na nowej działającej funkcji LookAt do obracania.

Jeśli ktoś ma podobny problem i chce mi zadać pytania, nie krępuj się.

Przynajmniej nie utknąłem już, dzięki za pomoc!

Grady
źródło

Odpowiedzi:

15

To, czego szukasz, można znaleźć w tym bardzo dobrym wyjaśnieniu: http://www.songho.ca/opengl/gl_transform.html

Ale odkąd uznałem to za mylące bez trzymania ręki, postaram się to tutaj wyjaśnić.

W tym momencie należy rozważyć 5 układów współrzędnych i ich wzajemne relacje. Są to współrzędne okna, znormalizowane współrzędne urządzenia, współrzędne oka, współrzędne świata i współrzędne obiektu.

Współrzędne okna można postrzegać jako „fizyczne” piksele na ekranie. Są to współrzędne, do których odnosi się system okienkowy, a jeśli pracujesz w natywnej rozdzielczości swoich monitorów, w rzeczywistości są to pojedyncze piksele. Układ współrzędnych okna to liczby całkowite 2D i odnosi się do okna. Tutaj x + jest w lewo, a y + jest w dół, z początkiem w lewym górnym rogu. Napotykasz je, gdy na przykład dzwonisz glViewport.

Drugi zestaw to znormalizowane współrzędne urządzenia. Odnoszą się one do ustawienia przestrzeni przez port aktywnego widoku. Widoczny obszar portu widoku wynosi od -1 do +1, a zatem ma początek w środku. Pozostawia x +, a y + jest w górę. Masz również, że Z + jest „poza” sceną. Oto, co opisujesz w 1.

Nie masz kontroli nad tym, jak przechodzisz od znormalizowanych współrzędnych urządzenia do współrzędnych okna, dzieje się to domyślnie dla Ciebie. Jedyne, co masz, to kontrola glViewportlub podobne.

Podczas pracy z openGL końcowy wynik zawsze będzie w znormalizowanych współrzędnych urządzenia. W rezultacie musisz się martwić, jak renderować w nich scenę. Jeśli ustawisz macierz rzutu i widoku modelu na macierz tożsamości, możesz bezpośrednio narysować te współrzędne. Odbywa się to na przykład podczas stosowania efektów pełnoekranowych.

Następny to współrzędne oka. To świat widziany z kamery. W rezultacie początek znajduje się w kamerze i mają zastosowanie te same oś osi, co współrzędne urządzenia.

Aby uzyskać współrzędne oka do współrzędnych urządzenia, należy zbudować matrycę projekcji. Najprostsza jest rzut ortograficzny, który po prostu odpowiednio skaluje wartości. Rzut perspektywiczny jest bardziej skomplikowany i obejmuje perspektywę symulacji.

Wreszcie masz światowy układ współrzędnych. Jest to układ współrzędnych, w którym twój świat jest zdefiniowany, a twoja kamera jest jego częścią. W tym miejscu należy zauważyć, że orientacje osi są takie, jak je definiujesz . Jeśli wolisz Z + jak wyżej, to w porządku.

Aby przejść ze współrzędnych światowych do współrzędnych oka, zdefiniuj macierz widoku. Można to zrobić za pomocą czegoś takiego lookAt. To, co robi ta matryca, to „przesuwanie” świata, tak aby kamera znajdowała się na początku i patrzyła w dół względem osi Z.

Aby obliczyć matrycę widoku jest zaskakująco prosta, musisz przekształcić kamerę. Zasadniczo musisz sformułować następującą macierz:

M=x[1]y[1]z[1]p[1]x[2]y[2]z[2]p[2]x[3]y[3]z[3]p[3]0001

Wektory x, y i z można pobrać bezpośrednio z kamery. W przypadku, gdy spojrzysz na nie, wyprowadzisz je z wartości celu, oka (środka) i wzwyż. Tak jak:

z=normalize(eyetarget)x=normalize(up×z)y=zx

Ale jeśli zdarzy ci się, że te wartości leżą wokół, możesz po prostu je przyjąć takimi, jakie są.

Uzyskanie p jest nieco trudniejsze. To nie jest pozycja we współrzędnych światowych, ale pozycja we współrzędnych kamery. Prostym obejściem jest tutaj zainicjowanie dwóch macierzy, jednej tylko z x, y i z, a drugiej z -eye i pomnożenie ich razem. Wynikiem jest macierz widoków.

Jak to może wyglądać w kodzie:

mat4 lookat(vec3 eye, vec3 target, vec3 up)
{
    vec3 zaxis = normalize(eye - target);    
    vec3 xaxis = normalize(cross(up, zaxis));
    vec3 yaxis = cross(zaxis, xaxis);     

    mat4 orientation(
       xaxis[0], yaxis[0], zaxis[0], 0,
       xaxis[1], yaxis[1], zaxis[1], 0,
       xaxis[2], yaxis[2], zaxis[2], 0,
         0,       0,       0,     1);

    mat4 translation(
              1,       0,       0, 0,
              0,       1,       0, 0, 
              0,       0,       1, 0,
        -eye[0], -eye[1], -eye[2], 1);

    return orientation * translation;
}

pełny kod

I wreszcie, dla kompletności, masz również układ współrzędnych obiektu. Jest to układ współrzędnych, w którym przechowywane są siatki. Za pomocą matrycy modelu współrzędne siatki są przekształcane w światowy układ współrzędnych. W praktyce macierze modelu i widoku są łączone w tak zwaną macierz widoku modelu.

Rioki
źródło
1
Gdybym mógł głosować tę odpowiedź sto razy, zrobiłbym to. Dziękuję za dokładną i kompletną odpowiedź dotyczącą wszystkiego, co mnie pomyliło, oraz podanie kodu i linku! Spędziłem cały dzień czytając książki matematyczne na ten temat, z twoją odpowiedzią, przykładowym kodem i linkowaną stroną, jeśli to nie wystarczy, żebym to zrozumiał, to powinienem teraz rzucić palenie. Gdybym mógł poprosić tylko o jedno wyjaśnienie, w tej ostatniej próbce kodu, czy miałbym rację twierdząc, że te macierze są w porządku głównym kolumny, a powyższy jest w rzędzie głównym?
Grady
Jest to nieco mylące, macierze są główne, ale kolumna jest w rzędzie. Aby zmapować rzeczywistą matematykę na kod, musisz przenieść macierz. Zobacz github.com/rioki/glm/blob/master/src/matrix.h#l72 To odwzorowuje dokładnie openGL i jak by to było, gdybyś używał float[16].
rioki
Ach, tak myślałem, ale chciałem być pewien, jeszcze raz dziękuję! Byłaś ogromną pomocą, naprawdę to doceniam.
Grady