OpenGL: ridimensionamento del display e glOrtho / glViewport


16

Ho cercato questa domanda da diverse fonti e non ho ancora trovato una risposta ferma dicendo che "sì, è il pensiero corretto" o "no, ecco come è fatto".

Sto cercando di garantire l'indipendenza della risoluzione con il rendering OpenGL. Il modo in cui penso di doverlo fare è creare una proiezione usando glOrthoqualunque cosa io voglia che siano le coordinate del mondo. Ad esempio glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0),. Quindi, imposta il viewport sulla risoluzione dello schermo , ovvero - glViewport(0, 0, 800, 600). Infine, ogni volta che la finestra viene ridimensionata, effettuare una chiamata glViewportcon la risoluzione dello schermo aggiornata. Questo ridimensionerà le tue figure.

È questo il modo corretto per garantire che i modelli occupino la stessa proporzione di spazio su schermo con risoluzioni diverse? Dovrei usare anche una proiezione uguale alla risoluzione? Ho trovato alcune risposte dicendo che glOrthodovrebbe usare la risoluzione della tua finestra mentre altri hanno detto che dovrebbe / può essere diverso.

Pensieri?

Risposte:


20

Quello che hai descritto è del tutto adeguato e appropriato per garantire l'indipendenza dalla risoluzione. Tutto ciò che disegni occuperà sempre la stessa proporzione della tua finestra.

Tuttavia, se non fai altro che questo, avrai problemi di proporzioni . Ad esempio, dati i numeri che hai scritto, se disegni un cerchio, verrà schiacciato - più largo di quanto sia alto, perché la tua scala orizzontale è 800 / (50 + 50) = 8 e la tua scala verticale è 600 / (50+ 50) = 6.

Non ci può essere alcuna soluzione automatica a questo problema ; dovrai scegliere quale risultato grafico vuoi e considerare il suo effetto sul gameplay. Alcuni esempi comuni:

  • In un gioco 3D a proiezione prospettica senza HUD, la solita soluzione semplice (disponibile in OpenGL come parte di gluPerspective) è quella di fissare il campo visivo della proiezione rispetto alla dimensione verticale . Ciò significa che in un gioco del genere, se ridimensionate la finestra in orizzontale, vedrete più o meno la scena e la parte centrale dell'immagine non cambierà affatto.

    La stessa idea può essere applicata anche a una vista 2D / 2.5D.

    (Si noti che ciò consente al giocatore di allargare il proprio campo visivo in senso orizzontale creando una finestra ampia ma non alta. Ciò potrebbe essere indesiderato in una partita multiplayer competitiva.)

  • Se hai una grafica che riempie la finestra con proporzioni fisse (ad esempio, una mappa 2D non scorrevole o un bordo decorativo) o se non riesci altrimenti a modificare il layout, devi fare qualcosa come avere barre nere su due lati per riempire lo spazio inutilizzato.

    Oppure puoi creare grafici con materiale di riempimento tematicamente coerente attorno ai bordi che possono essere ritagliati per adattarsi al display senza danneggiare il gameplay.

  • Se hai un HUD in cima ad altri elementi grafici, puoi decidere che ogni elemento HUD è fissato a una parte della finestra (in alto a sinistra, in basso al centro, ecc.) E calcolarne le coordinate; lo "stiramento" del variare delle proporzioni viene assorbito dallo "spazio bianco" tra gli elementi HUD.

Per quanto riguarda la matematica specifica della questione, dato che stai facendo l'indipendenza dalla risoluzione, tutto ciò di cui hai bisogno è iniziare con le proporzioni, un singolo numero: width / height . Ad esempio, se la finestra è quadrata sarà 1; se è 800 per 600 sarà 800/600 = 4/3 = 1.333̅.

Ad esempio, supponiamo che tu voglia la proiezione ortografica che hai scritto per guadagnare spazio aggiuntivo sui lati sinistro e destro se la finestra è allargata. Puoi farlo in questo modo:

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

Ciò garantisce che, per le finestre larghe almeno quanto alte, sarà visibile qualsiasi cosa tu disegni con coordinate xey entro -50 a 50.

D'altra parte, se la finestra è più stretta di quanto sia alta, l'intervallo da -50 a 50 verrà tagliato. Supponiamo che tu voglia assicurarti che sia sempre visibile (in modo che il tuo contenuto abbia le dimensioni massime se la finestra è quadrata, ma altrimenti più piccola); in tal caso, fai semplicemente la stessa cosa all'altezza anziché alla larghezza.

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);

Si noti che nel secondo caso dividiamo piuttosto che moltiplicare. Questo semplicemente perché abbiamo calcolato le proporzioni width / heightpiuttosto che height / width; prendi il reciproco se trovi più facile capire in quel modo.

Ancora una volta, questo non è l'unico modo per gestire le proporzioni; questo è molto semplice per assicurarsi che i tuoi contenuti non siano né schiacciati né tagliati. Scopri cosa vuoi che accada quando la tua finestra è larga, alta o altro; quindi elaborarne la matematica.


Grazie per la risposta MOLTO perspicace. Ha risposto sufficientemente alla mia domanda.
Chris Henderson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.