OpenGL: redimensionnement de l'affichage et glOrtho / glViewport

16

J'ai fait des recherches sur cette question à partir de plusieurs sources et je n'ai pas encore trouvé de réponse ferme disant que «oui, c'est la pensée correcte» ou «non, voici comment cela se fait».

J'essaie d'assurer l'indépendance de la résolution avec le rendu OpenGL. La façon dont je pense que je devrais m'y prendre, est de créer une projection en utilisant glOrthoce que je veux que les coordonnées du monde soient. Par exemple glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0),. Ensuite, définissez la fenêtre sur la résolution d'écran , c'est-à-dire - glViewport(0, 0, 800, 600). Enfin, chaque fois que la fenêtre est redimensionnée, appelez glViewportavec la résolution d'écran mise à jour. Cela mettra à l'échelle vos chiffres.

Est-ce la bonne façon de garantir que les modèles prennent la même proportion d'espace d'écran sur différentes résolutions? Dois-je également utiliser une projection égale à la résolution? J'ai trouvé quelques réponses disant qu'il glOrthofallait utiliser la résolution de votre fenêtre tandis que d'autres ont dit qu'elle devrait / peut être différente.

Pensées?

Chris Henderson
la source

Réponses:

20

Ce que vous avez décrit est tout à fait adéquat et approprié pour assurer l'indépendance de la résolution. Tout ce que vous dessinez occupera en effet toujours la même proportion de votre fenêtre.

Cependant, si vous ne faites rien de plus que cela, vous aurez des problèmes de rapport d'aspect . Par exemple, étant donné les nombres que vous avez écrits, si vous dessinez un cercle, il sera écrasé - plus large que haut, car votre échelle horizontale est 800 / (50 + 50) = 8 et votre échelle verticale est 600 / (50+ 50) = 6.

Il ne peut y avoir aucune solution automatique à ce problème ; vous devrez choisir quel résultat graphique vous voulez, et considérer son effet sur le gameplay. Quelques exemples courants:

  • Dans un jeu 3D de projection en perspective sans HUD, la solution simple habituelle (disponible dans OpenGL en tant que partie de gluPerspective) est de fixer le champ de vision de la projection par rapport à la dimension verticale . Cela signifie que dans un tel jeu, si vous redimensionnez la fenêtre horizontalement, vous verrez plus ou moins la scène et la partie centrale de l'image ne changera pas du tout.

    La même idée peut également être appliquée à une vue 2D / 2.5D.

    (Notez que cela permet au joueur d'élargir son champ de vision horizontalement en créant une fenêtre large mais pas haute. Cela pourrait être indésirable dans un jeu multijoueur compétitif.)

  • Si vous avez des graphiques remplissant la fenêtre avec un rapport d'aspect fixe (par exemple, une carte 2D sans défilement ou une bordure décorative), ou si vous ne pouvez pas changer la mise en page, vous devez faire quelque chose comme avoir des barres noires sur deux côtés pour remplir l'espace inutilisé.

    Ou vous pouvez créer des graphiques qui ont un matériau de remplissage thématiquement cohérent sur les bords afin qu'ils puissent être rognés pour s'adapter à l'écran sans nuire au gameplay.

  • Si vous avez un HUD au-dessus d'autres graphiques, vous pouvez décider que chaque élément HUD est fixé à une partie de la fenêtre (en haut à gauche, en bas au centre, etc.) et calculer ses coordonnées; «l'étirement» de la variation des rapports d'aspect est absorbé par «l'espace blanc» entre les éléments HUD.

En ce qui concerne les mathématiques spécifiques de la matière, étant donné que vous faites l' indépendance de la résolution, tout ce que vous devez commencer avec est le rapport d'aspect, un seul numéro: width / height. Par exemple, si la fenêtre est carrée, elle sera 1; s'il est de 800 par 600, ce sera 800/600 = 4/3 = 1,333̅.

Par exemple, supposons que vous souhaitiez que la projection orthographique que vous avez écrite gagne de l'espace supplémentaire sur les côtés gauche et droit si la fenêtre est élargie. Vous pouvez faire ça comme ceci:

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

Cela garantit que, pour des fenêtres au moins aussi larges que hautes, tout ce que vous dessinez avec des coordonnées x et y comprises entre -50 et 50 sera visible.

D'un autre côté, si la fenêtre est plus étroite que haute, la plage -50 à 50 sera coupée. Supposons que vous vouliez vous assurer qu'il est toujours visible (afin que votre contenu soit à sa taille maximale si la fenêtre est carrée, mais plus petite sinon); dans ce cas, vous faites simplement la même chose pour la hauteur au lieu de la largeur.

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

Notez que dans le deuxième cas, nous divisons plutôt que nous multiplions. C'est simplement parce que nous avons calculé le rapport d'aspect width / heightplutôt que height / width; prenez la réciproque si vous trouvez plus facile à comprendre de cette façon.

Encore une fois, ce n'est pas la seule façon de gérer les proportions; ceci est juste très simple pour vous assurer que votre contenu n'est ni écrasé ni coupé. Déterminez ce que vous voulez que votre fenêtre soit large, haute ou autre; puis en travailler les mathématiques.

Kevin Reid
la source
Merci pour la réponse TRÈS perspicace. J'ai suffisamment répondu à ma question.
Chris Henderson