Czy układ współrzędnych OpenGL jest leworęczny czy praworęczny?

87

Próbuję zrozumieć układ współrzędnych OpenGL. Jednak niektóre samouczki mówią, że domyślny układ współrzędnych jest leworęczny (patrz http://www.c-sharpcorner.com/UploadFile/jeradus/OpenGLBasics11172005014307AM/OpenGLBasics.aspx ), a inne mówią, że jest praworęczny (patrz http: // www .falloutsoftware.com / tutorials / gl / gl0.htm ). Który jest poprawny? Rozumiem, że możemy przekształcić jedno w drugie przez odbicie lustrzane, ale chciałbym poznać domyślne współrzędne.

341008
źródło
3
Czy to nie zależy całkowicie od tego, jak piszesz swoje transformacje w shaderach i dlatego zależy wyłącznie od Ciebie?
jcoder
Tylko moje dwa centy evl.uic.edu/ralph/508S98/coordinates.html , ma kilka zrozumiałych obrazów.
rraallvv
Przypuszczam, że nie rozważałbyś aktualizacji zaakceptowanej odpowiedzi?
Jonathan Mee

Odpowiedzi:

132

Jest tu trochę zamieszania.

wprowadź opis obrazu tutaj

OpenGL jest praworęczny w przestrzeni obiektów i przestrzeni świata.

Ale w przestrzeni okna (aka przestrzeni ekranu) nagle stajemy się leworęczni .

Jak to się stało ?

Sposób, w jaki przechodzimy od praworęcznych do leworęcznych, to ujemny wpis skalowania z w macierzy glOrtholub glFrustummacierzy projekcji. Skalowanie z o -1 (pozostawiając niezmienione x i y) ma wpływ na zmianę ręczności układu współrzędnych.

Dla glFrustum,

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

dalekie i bliskie mają być pozytywne, z daleka > blisko . Powiedz daleko = 1000 i blisko = 1. Wtedy C = - (1001) / (999) = -1,002.

Zobacz tutaj, aby uzyskać więcej szczegółów i schematów.

Z perspektywy ortograficznej glOrtho generuje taką macierz:

wprowadź opis obrazu tutaj

Tutaj lewa , prawa , dół i góra to tylko współrzędne dla lewej pionowej , prawej pionowej , dolnej poziomej , górnej poziomej płaszczyzny przycinającej (odpowiednio) .

Jednak bliskie i dalekie płaszczyzny są określane inaczej . Pobliżu parametr określa się jako

  • Blisko: odległość do bliższej płaszczyzny przycięcia głębokości. Odległość ta jest ujemna, jeśli samolot ma znajdować się za widzem.

i daleko:

  • zFar Odległość do dalszej płaszczyzny tnącej głębokości. Odległość ta jest ujemna, jeśli samolot ma znajdować się za widzem.

Tutaj mamy typową kanoniczną objętość widoku

kanoniczny

Ponieważ mnożnik z wynosi (-2 / (daleko-blisko)), znak minus skutecznie skaluje z o -1 . Oznacza to, że „z” jest obracane w lewo podczas transformacji widoku, o czym większość ludzi nie wie, ponieważ po prostu pracują w OpenGL jako „praworęczny” układ współrzędnych.

Więc jeśli zadzwonisz

glOrthof(-1, 1, -1, 1, 10, -10) ; // near=10, FAR=-10,

Wtedy BLISKI SAMOLOT jest 10 jednostek przed tobą . Gdzie jesteś? Na początku, z osią X po prawej stronie, osią Y na czubku głowy i nosem skierowanym w dół na ujemną oś Z (to jest domyślne ustawienie „Domyślnie kamera jest umieszczona na początku , wskazuje ujemną oś z i ma wektor w górę (0, 1, 0). ” ). Więc najbliższa płaszczyzna ma z = -10. Daleka płaszczyzna znajduje się 10 jednostek za tobą, w punkcie z = + 10 .

bobobobo
źródło
1
„wektor do przodu jest zanegowany w gluLookAt” - czy możesz potwierdzić, że tak jest? Nie gluPerspective czy glFrustum czy glOrtho?
Kos
1
Nagle jesteśmy leworęczni od przestrzeni klipu, a nie tylko przestrzeni okna.
legends2k
3
+1 dla całej odpowiedzi, -1 (poczekaj, a raczej -2) dla „Sposób, w jaki przechodzimy od osób praworęcznych do leworęcznych jest taki, że wektor do przodu jest negowany w standardowej implementacji funkcji gluLookAt (), która jest funkcją wszyscy używają do tworzenia macierzy widoku. Kiedy zanegujesz wektor do przodu, ma to wpływ na zmianę ręczności układu współrzędnych ”. , co jest zwykłym śmieciem ...
Christian Rau
2
... Negowanie wektora do przodu w gluLookAtobliczeniach nie ma nic wspólnego ze zmianą ręczności przestrzeni współrzędnych, tak właśnie jest obliczana ta macierz (w rzeczywistości + z jest rzeczywiście „wstecz” w przestrzeni prawoskrętnej). gluLookAtnie robi nic poza obliczeniem zwykłej transformacji ciała sztywnego (obrót + przesunięcie) w przestrzeni prawoskrętnej. To macierze projekcji używane przez potok funkcji stałych (i zazwyczaj również przez shadery), które dokonują rzeczywistej zmiany ręczności w ich negacji składowej z, jak już zauważyłeś w swojej odpowiedzi.
Christian Rau
2
@bobobobo Twoje powiedzenie, gdybyś obliczył macierz widoku tylko przy użyciu funkcji rotacji i translacji (których, jak sądzę, nie zarzucałbyś zmianie ręczności), zamiast tego gluLookAtnie byłoby zmiany podstawy, skoro tak gluLookAt? Zdecydowanie nie (ponieważ prawdopodobnie wiesz, że nie "wszyscy" używają gluLookAtdo obliczania macierzy widoku), ponieważ jak powinieneś wiedzieć, gluLookAtnie robi nic innego niż zbiór wywołań rotacji i tłumaczenia (czy nawet ukrywają się jako zmiana " terminu " wysokiego poziomu " base ” ) bez żadnych odbić.
Christian Rau
26

Domyślnie znormalizowane współrzędne urządzenia są leworęczne.

Zakres glDepthRange to domyślnie [0, 1] (blisko, daleko), dzięki czemu oś + z wskazuje na ekran, a przy + x w prawo i + y w górę jest to system leworęczny.

Zmiana zakresu głębokości na [1, 0] spowoduje, że system będzie praworęczny.

Cytując poprzednią odpowiedź Nicola : (przekreślenie to moja praca, wyjaśnione poniżej)

Dziwię się, że nikt o czymś nie wspomniał: OpenGL działa również w lewoskrętnym układzie współrzędnych. Przynajmniej tak jest, gdy pracujesz z modułami cieniującymi i używasz domyślnego zakresu głębi.

Gdy wyrzucisz potok funkcji o ustalonej funkcji, masz do czynienia bezpośrednio z "przestrzenią obcinania". Specyfikacja OpenGL definiuje przestrzeń obcinania jako jednorodny układ współrzędnych 4D. Kiedy podążasz za transformacjami przez znormalizowane współrzędne urządzenia, aż do przestrzeni okna, znajdziesz to.

Przestrzeń okna jest przestrzenią pikseli okna. Początek znajduje się w lewym dolnym rogu, gdzie + Y idzie w górę, a + X w prawo. To brzmi bardzo jak prawoskrętny układ współrzędnych. Ale co z Z?

Domyślny zakres głębokości (glDepthRange) ustawia bliską wartość Z na 0 i dalszą wartość Z na jeden . Więc + Z odchodzi od widza.

To lewoskrętny układ współrzędnych. Tak, możeszzmień test głębokości z GL_LESS na GL_GREATER izmień zakres glDepthRange z [0, 1] na [1, 0]. Ale domyślnym stanem OpenGL jest praca w lewoskrętnym układzie współrzędnych. I żadna z transformacji potrzebnych do przejścia do przestrzeni okna z clip-space nie neguje Z. Więc clip-space, wyjście Vertex Shadera (lub geometrii) jest lewoskrętną przestrzenią (trochę. Jest to jednorodna przestrzeń 4D, więc ciężko jest określić ręczność).

W potoku o ustalonej funkcji standardowe macierze projekcji (produkowane przez glOrtho, glFrustum i tym podobne) przekształcają się z przestrzeni praworęcznej w leworęczną . Odwracają znaczenie Z; po prostu sprawdź macierze, które generują. W przestrzeni oczu + Z przesuwa się w kierunku widza; w przestrzeni po projekcji oddala się.

Podejrzewam, że Microsoft (i GLide) po prostu nie zadał sobie trudu, aby wykonać negację w swoich macierzach projekcji.

Uderzyłem jedną część, ponieważ odbiegała od moich ustaleń.

Zmiana DepthRange lub DepthFunc i użycie ClearDepth (0) działa, ale podczas używania obu anulowały się nawzajem z powrotem do systemu leworęcznego.

hultqvist
źródło
Zakres głębokości nie może wynosić [1, -1]. Myślę, że miałeś na myśli [1, 0]. Również to zostało wskazane wcześniej .
Nicol Bolas
Twoja odpowiedź jest świetna, szkoda, że ​​jest na pytanie dotyczące DirectX, powinieneś ją ponownie opublikować tutaj!
hultqvist
3
@SigTerm, dlaczego uważasz, że poprawianie fałszywego oświadczenia nie jest tego warte? Spędziłem kilka godzin na rozwiązywaniu problemów ze współrzędnymi wierzchołków i generowaniem rotacji macierzy, aby dowiedzieć się, że domyślny układ współrzędnych w rzeczywistości nie był praworęczny.
hultqvist
1
Pytanie brzmiało, czy był to system leworęczny czy praworęczny. Ta odpowiedź zawiera więcej szczegółów, wyjaśniając dwa inne sposoby, aby uzyskać to praworęczne, dodanie -1 w transformacji macierzowej to kolejny sposób zrobienia tego. Ale nic z tego nie ma znaczenia, jeśli uważasz, że system jest domyślnie praworęczny, możesz coś zmienić tylko wtedy, gdy wiesz, z czego się zmieniasz. Still
hultqvist
1
Odpowiedź wydała mi się bardzo pouczająca i pojawiła się w wyszukiwaniach, więc była tego warta.
Naucz się OpenGL ES
13

TYLKO NDC

Należy tylko zauważyć, że OpenGL zna tylko NDC! a to jest lewoskrętny układ współrzędnych.

Niezależnie od używanego układu współrzędnych - lewoskrętny lub prawoskrętny układ współrzędnych oś - wszystkie muszą być odzwierciedlone w NDC. Jeśli chcesz, możesz całkowicie obsłużyć przestrzeń świata jako lewoskrętny układ współrzędnych.

Dlaczego zwykle używamy prawoskrętnego układu współrzędnych w przestrzeni świata?

Myślę, że to konwencjonalne. Po prostu działa. Może po prostu chce odróżnić się od DirectX.

ZK_
źródło
3
Myślę, że to nie jest wystarczająco powtarzane. Wszystkie te diagramy przedstawiające „transformację modelowania”, „transformację widoku”, „transformację perspektywiczną” nie pokazują, że nie są one nieodłączną częścią OpenGL. Możesz nawet wykonać wszystkie transformacje ręcznie, z shaderem lub bez, z matrycami lub bez.
Tom
3
Lepiej byłoby jednak powtórzyć to i dodać słowa „znormalizowane współrzędne urządzenia”.
Tommy
6
OpenGL wyprzedza DirectX o kilka lat, więc OpenGL z pewnością nie próbował odróżniać się od DirectX. Główny programista DirectX, Alex St. John, powiedział, że decyzja Microsoftu o przejściu na leworęczny system współrzędnych była „po części z osobistych preferencji” i „arbitralnym wyborem”.
Chris Nolet,
To nie jest całkowicie poprawne. OpenGL zna również układ współrzędnych obcinania, ponieważ obcinanie ma miejsce w tym. Układ współrzędnych klipu ma taką samą ręczność jak układ współrzędnych NDC.
plasmacel
7

Książka „WebGl Programming Guide” autorstwa Kouichi Matsudy zajmuje prawie dziesięć stron na temat „WebGl / OpenGl: Left or Right Handed?”

Według książki:

  • W praktyce większość ludzi używa systemu praworęcznego

  • OpenGl jest wewnętrznie systemem leworęcznym

  • Wewnętrznie, głębiej, tak naprawdę nie jest. Na samym dole OpenGl nie dba o wartość z. Kolejność rysowania określa, co jest rysowane na górze (najpierw narysuj trójkąt, a następnie kwadrat, kwadrat przesłania trójkąt).

Nie do końca zgadzam się z twierdzeniem „to też nie”, ale i tak jest to prawdopodobnie kwestia filozoficzna.

Heinzlmaen
źródło
7
The order in which you draw things determines what is drawn on top (draw a triangle first, then a quad, the quad overrides the triangle). To prawda, jeśli nie ma testów głębokości. W przypadku testowania głębokości wartość z fragmentu jest porównywana z wartością w buforze głębokości, a fragment odrzucany, jeśli nie przejdzie testu głębokości, więc quad może, ale nie musi, nadpisać trójkąt w zależności od ich głębokości i używana funkcja głębokości.
chrisvarnz
3

Opengl jest zdecydowanie leworęczny. Widzisz wiele samouczków stwierdzających coś przeciwnego, ponieważ negują one wartość z w macierzy projekcji. Kiedy końcowe wierzchołki są obliczane w Vertex Shader, konwertuje to wierzchołki, które przekazujesz ze strony klienta (koordynatory po prawej stronie) do leworęcznych, a wierzchołki zostaną następnie przesłane do Geometry Shader i Fragment Shader. Jeśli używasz prawego układu współrzędnych po stronie klienta, Opengl nie obchodzi. Zna tylko znormalizowany układ współrzędnych, który jest leworęczny.

Edycja: Jeśli mi nie ufasz, po prostu eksperymentuj w swoim Vertex Shader, dodając macierz translacji i możesz łatwo sprawdzić, czy Opengl jest leworęczny, czy nie.

ForeignDevil
źródło
0

Korzystając z wbudowanych w OpenGL funkcji projekcji i transformacji, obserwowanie ruchów na ekranie odbywa się zgodnie z regułami praworęcznego układu współrzędnych. Na przykład, jeśli obiekt znajdujący się przed Twoim widokiem zostanie przesunięty w dodatnim kierunku z, obiekt ten przesunie się w Twoją stronę.

Bufor głębokości jest zupełnie odwrotny i tutaj do gry wchodzą NDC (znormalizowane współrzędne urządzenia). Jeśli przekazanie GL_LESS do funkcji glDepthFunc oznacza, że ​​piksele będą rysować, gdy będą bliżej Ciebie niż to, co jest już w buforze głębi, wówczas uważa się, że piksele żyją w lewoskrętnym układzie współrzędnych.

Jest jeszcze jeden układ współrzędnych i to jest rzutnia! Układ współrzędnych rzutni jest taki, że + x wskazuje w prawo, a + y w dół. Myślę, że w tym momencie ręczność jest dyskusyjna, ponieważ w tym momencie mamy do czynienia tylko z x, y.

Wreszcie, gluLookAt pod maską musi zanegować wektor patrzenia. Ponieważ matematyka zakłada, że ​​wektor jest skierowany w dodatnim kierunku w kierunku obiektu, na który patrzy, a kamera patrzy w dół -z, wektor patrzenia musi zostać zanegowany, aby był wyrównany z kamerą.

Coś do gryzienia. Nie ma sensu nazywać kierunku z prawoskrętnego układu współrzędnych wektorem do przodu :). Myślę, że Microsoft zdał sobie z tego sprawę, kiedy zaprojektował Direct3D.

weatx
źródło