OpenGL: Zmiana rozmiaru ekranu i glOrtho / glViewport

16

Zbadałem to pytanie z kilku źródeł i nie znalazłem jeszcze jednoznacznej odpowiedzi, która brzmiałaby: „tak, to poprawne myślenie” lub „nie, oto jak to się robi”.

Staram się zapewnić niezależność rozdzielczości dzięki renderowaniu OpenGL. Moim zdaniem powinienem zająć się tym, aby stworzyć projekcję, używając glOrthodowolnego współrzędnych świata. Na przykład glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0). Następnie ustaw rzutnię na rozdzielczość ekranu , tj glViewport(0, 0, 800, 600). - . Wreszcie, za każdym razem, gdy rozmiar okna jest zmieniany, wykonaj połączenie glViewportz zaktualizowaną rozdzielczością ekranu. To skaluje twoje liczby.

Czy to właściwy sposób, aby zapewnić, że modele zajmują tyle samo miejsca na ekranie w różnych rozdzielczościach? Czy powinienem także używać projekcji równej rozdzielczości? Znalazłem kilka odpowiedzi, które mówią, że glOrthopowinny używać rozdzielczości twojego okna, podczas gdy inni twierdzą, że powinno / może być inaczej.

Myśli?

Chris Henderson
źródło

Odpowiedzi:

20

To, co opisałeś, jest całkowicie odpowiednie i odpowiednie, aby zapewnić niezależność w zakresie rozwiązywania problemów. Wszystko, co narysujesz, rzeczywiście zawsze zajmuje tę samą część twojego okna.

Jeśli jednak nie zrobisz nic więcej, będziesz mieć problemy ze współczynnikiem proporcji . Na przykład, biorąc pod uwagę liczby, które zapisałeś, jeśli narysujesz okrąg, zostanie on zgnieciony - szerszy niż wysoki, ponieważ twoja skala pozioma wynosi 800 / (50 + 50) = 8, a twoja skala pionowa to 600 / (50+ 50) = 6.

Nie może być żadnego automatycznego rozwiązania tego problemu ; będziesz musiał wybrać pożądany wynik graficzny i rozważyć jego wpływ na rozgrywkę. Niektóre typowe przykłady:

  • W grze 3D z rzutowaniem perspektywicznym bez interfejsu, zwykłym prostym rozwiązaniem (dostępnym w OpenGL jako część gluPerspective) jest ustalenie pola widzenia projekcji względem wymiaru pionowego . Oznacza to, że w takiej grze, jeśli zmienisz rozmiar okna w poziomie, zobaczysz mniej więcej scenę, a środkowa część obrazu w ogóle się nie zmieni.

    Ten sam pomysł można zastosować również do widoku 2D / 2.5D.

    (Pamiętaj, że pozwala to graczowi powiększyć pole widzenia w poziomie, tworząc szerokie, ale nie wysokie okno. Może to być niepożądane w konkurencyjnej grze wieloosobowej).

  • Jeśli masz grafikę wypełniającą rzutnię o stałym współczynniku kształtu (na przykład nieprzewijającą mapę 2D lub dekoracyjną ramkę) lub jeśli inaczej nie możesz zmienić układu, musisz zrobić coś takiego, jak czarne paski na dwóch boki, aby wypełnić nieużywane miejsce.

    Lub możesz stworzyć grafikę, która ma spójny tematycznie materiał wypełniający wokół krawędzi, który można przyciąć, aby dopasować do wyświetlacza bez szkody dla rozgrywki.

  • Jeśli masz HUD na wierzchu innej grafiki, możesz zdecydować, że każdy element HUD jest przymocowany do części okna (lewy górny, środkowy dolny itd.) I obliczyć jego współrzędne; „rozciąganie” różnych proporcji zostaje pochłonięte przez „białą przestrzeń” między elementami interfejsu.

Co do matematyki konkretne sprawy, biorąc pod uwagę, że robisz niezależność rozdzielczości, wszystko czego potrzebujesz, aby rozpocząć się ma proporcje, pojedynczy numer: width / height. Na przykład, jeśli okno jest kwadratowe, będzie miało wartość 1; jeśli to 800 na 600, to będzie 800/600 = 4/3 = 1,333̅.

Załóżmy na przykład, że chcesz, aby rzut ortograficzny , który napisałeś, zyskał dodatkowe miejsce po lewej i prawej stronie, jeśli okno zostanie rozszerzone. Możesz to zrobić w następujący sposób:

float aspect = width / height;
glViewport(0, 0, width, height);
glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);

Gwarantuje to, że dla okien o szerokości co najmniej tak dużej, jak to tylko możliwe, wszystko, co narysujesz za pomocą współrzędnych xiy w zakresie od -50 do 50, będzie widoczne.

Z drugiej strony, jeśli okno jest węższe niż wysokie, zakres od -50 do -50 zostanie odcięty. Załóżmy, że chcesz się upewnić, że jest zawsze widoczny (aby zawartość była w maksymalnym rozmiarze, jeśli okno jest kwadratowe, ale w przeciwnym razie jest mniejsza); w takim przypadku po prostu robisz to samo na wysokości zamiast na szerokości.

float aspect = width / height;
glViewport(0, 0, width, height);
if (aspect >= 1.0)
  glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);
else
  glOrtho(-50.0, 50.0, -50.0 / aspect, 50.0 / aspect, 1.0, -1.0);

Zauważ, że w drugim przypadku dzielimy, a nie mnożymy. Jest tak po prostu dlatego, że obliczyliśmy proporcje width / heightzamiast height / width; weźcie odwrotność, jeśli łatwiej będzie wam to zrozumieć.

Ponownie, nie jest to jedyny sposób zarządzania współczynnikiem proporcji; jest to po prostu bardzo prosty sposób, aby upewnić się, że zawartość nie jest zgnieciona ani odcięta. Zastanów się, co chcesz zrobić, gdy twoje okno jest szerokie, wysokie lub cokolwiek innego; następnie opracuj jego matematykę.

Kevin Reid
źródło
Dziękujemy za BARDZO wnikliwą odpowiedź. Odpowiedzi na moje pytanie były niewystarczające.
Chris Henderson