Confusion sur GLViewport

9

J'espère que quelqu'un pourra m'aider à comprendre le GLViewport et ce qui se passe lorsque nous le redimensionnons

Cela illustrera ma confusion ...

entrez la description de l'image ici

Donc, ici, j'ai un quad coincé au milieu de l'écran. Si mon GLViewport correspond à la largeur et à la hauteur de l'appareil, j'obtiens ce qui se trouve sur la première image (à gauche). Exactement ce à quoi je m'attendrais.

  • Résolution de l'appareil, 2560 x 1600
  • Résolution de la fenêtre 2560 x 1600
  • Quad taille 200 x 200 (Remarque, l'image ci-dessus n'est pas à l'échelle !!! :-))
  • Forme quadruple, apparaît comme carré

Maintenant, pour la 2e photo (à droite) ...

  • Résolution de l'appareil, 2560 x 1600
  • Résolution de la fenêtre 2560 x 1200 (et centrée verticalement)
  • Taille quadruple (200, 200)
  • Forme quadruple, apparaît sous forme de rectangle

Ma question est la suivante: pourquoi le quad s'affiche-t-il maintenant comme un rectangle et non comme un carré? J'ai confirmé en enregistrant que mon quad faisait 200 x 200 pixels - la taille des pixels physiques reste sûrement la même? Ils ne peuvent pas changer. Que se passe-t-il?

Je pensais (clairement de façon incorrecte) que lorsque j'ai redimensionné la fenêtre, elle a littéralement juste coupé les pixels.

J'apprécierais si quelqu'un pouvait expliquer comment cela fonctionne.

Éditer

Actuellement, je configure ma fenêtre comme ceci:

width = (int) Math.min(deviceWidth, deviceHeight * 1.702127659574468);    
height = (int) Math.min(deviceHeight, deviceWidth / 1.702127659574468);

ratio = width / height;
GLES20.glViewport(offsetX, offsetY, width, height);

Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

offsetX et offsetY sont juste pour que lorsqu'il y a des boîtes aux lettres, la fenêtre soit centrée.

BungleBonce
la source
Avez-vous changé votre matrice de projection ainsi que la fenêtre d'affichage lors du passage de 1600 à 1200 pixels verticaux? (vous devez)
bcrist
Salut @bcrist, veuillez voir ma modification pour montrer comment je configure ma fenêtre. Tout ce que je dessine qui a un nombre égal de pixels (disons 50 x 50 ou 100 x 100) dessine «étiré» - Des idées?!
BungleBonce
BTW, si vous utilisez à la glScissorplace de glViewport, il supprimera simplement les pixels sans changer l'emplacement du rendu. glViewportse comporte plus comme redimensionner l'image originale, plutôt que de la recadrer; c'est pourquoi il écrase votre boîte.
Nathan Reed
Merci @NathanReed, je suis toujours vraiment confus. Ce que j'ai, c'est ceci: une fenêtre qui occupe tout l'écran. Une boîte à ciseaux qui est mise à l'échelle pour garder le rapport de l'appareil d'origine (afin que je puisse afficher le jeu dans la boîte à ciseaux et dessiner des trucs en dehors de cela pour le remplissage), tout semble étiré (verticalement), donc plus long qu'il n'est large. Qu'est-ce que je fais mal?
BungleBonce
Hmm. Le ciseau rect ne doit rien changer au rapport d'aspect ou à la mise à l'échelle de l'image. S'il semble correct sans les ciseaux, l'activation du ciseau - en gardant la même fenêtre de visualisation, la même matrice de projection, etc. - devrait simplement recadrer l'image.
Nathan Reed

Réponses:

11

Pour comprendre ce qui se passe, vous devez comprendre le pipeline de rendu:

Votre géométrie (le quad) est initialement définie dans l'espace du monde, pensez à cela comme un système de coordonnées global. À l'intérieur du vertex shader, ceux-ci sont transformés en coordonnées de périphérique normalisées (NDC), un système de coordonnées virtuel défini de telle sorte que tout de -1 à 1 sera dessiné à l'écran. Notez que le NDC va de -1 à 1 en X et Y, et il est totalement indépendant du rapport d'aspect et de la résolution des appareils. Cette transformation de l'espace mondial en NDC se fait par le modèle, la vue et la matrice de projection (sous une forme simple, une seule matrice pour tout ou la géométrie a même été définie dans NDC pour commencer!).

L'unité de rastérisation doit savoir où et quelle taille elle doit raster et c'est ce que vous définissez avec l'appel glViewport: par où commencer sont les deux premiers paramètres, la taille sont les deux seconds. Le matériel convertit ensuite le NDC en coordonnées pixel par une simple échelle et un décalage - et c'est ce que vous voyez dans votre exemple: une échelle sur l'axe Y.

Donc, pour vous assurer que votre quadruple est rendu dans le rapport d'aspect correct, vous devez également ajuster la matrice de projection pour inclure le rapport d'aspect attendu de l'appel glViewport.

Robert
la source
Bonjour @Robert, merci beaucoup pour cela, j'ai du mal à essayer de l'implémenter, pourriez-vous donner un exemple de configuration de la matrice de projection dans votre réponse? Merci!
BungleBonce
4
Bonjour user22241, il n'y a pas de commandes OpenGL pour faire cela pour vous, vous devez définir la matrice par vous-même (un tableau de 4 x 4 flottants) et les fournir à votre vertex shader comme uniforme. La projection dont vous avez besoin (perspective, orthogonale) dépend de ce que vous voulez faire. Si les concepts mathématiques des projections 3D sont nouveaux pour vous, vous voudrez peut-être rechercher des didacticiels OpenGL enseignant le profil de base qui fonctionne de la même manière que OpenGL ES à cet égard.
Robert
@BungleBonce bien qu'il n'y ait pas de commandes OpenGL pour cela dans le profil de base, vous pouvez toujours consulter la documentation des commandes obsolètes comme glFrustum, qui répertorie la matrice exacte qui est construite par ces fonctions. Une autre matrice de projection commune que vous pourriez souhaiter a été créée par glOrtho. Bien que toutes ces commandes soient obsolètes, les documents qu'elles contiennent sont une excellente source de mathématiques prédérivées.
Ruslan
0

Dans votre appel à glViewport, vous spécifiez moins de pixels en largeur et en hauteur. Votre matrice de projection est définie en termes de pixels. C'est pourquoi vous devrez calculer une nouvelle matrice de projection après un appel glViewport.

bogglez
la source
Bonjour @bogglez, merci pour votre réponse. J'ai modifié ma question pour montrer (à la fin) quel code j'utilise pour ma fenêtre. Tout ce que j'utilise est glViewPort - est-ce une façon incorrecte de le faire? Pourriez-vous montrer un exemple de ce que vous voulez dire dans votre réponse? Merci.
BungleBonce
Lisez ceci: songho.ca/opengl/gl_projectionmatrix.html Pour la 2D, vous voulez une matrice de projection orthogonale, pour la 3D, vous voulez probablement une matrice de perspective. Si vous utilisez OpenGL moderne, vous fournirez une matrice à un shader. Si vous utilisez OpenGL obsolète avec le pipeline graphique fixe, vous utiliserez des fonctions telles que glLoadMatrix, glFrustum, etc. pour calculer la matrice de projection. La bibliothèque d'utilitaires GLU a une fonction gluPerspective ( opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml ) et gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ) pour vous aider avec cela.
bogglez
0

Pour la première photo:

  1. Nous créons une matrice de projection. Par exemple, les paramètres utilisés sont: Left1, Right1, Bottom1, Top1, Near1, Far1. Ici, Aspect_Ratio_1A = (Right1 - Left1) / (Top1 - Bottom1);

  2. Ensuite, nous faisons une transformation du port de vue. Par exemple, les paramètres utilisés sont: Largeur1, Hauteur1. (Je ne mentionne pas les paramètres de décalage pour plus de simplicité). Ici, Aspect_Ratio_1B = Largeur1 / Hauteur1;

Pour la deuxième photo:

  1. Nous créons la même matrice de projection avec les mêmes paramètres qu'auparavant. Donc: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. Cette fois, la transformation du port de vue a différents paramètres: Largeur2 et Hauteur2. Ici, Aspect_Ratio_2B = Largeur2 / Hauteur2.

Nous notons que Aspect_Ratio_1B et Aspect_Ratio_2B sont différents. Plus précisément, ils sont:

Aspect_Ratio_1B = 2560/1600 = 1,6 Aspect_Ratio_2B = 2560/1200 = 2,13

Donc, si nous résumons ce que nous faisons pour le deuxième cas, c'est:

Nous projetons l'image sur un plan avec Aspect_Ratio_2A et avant de la montrer à l'utilisateur, nous la mettons à l'échelle en Aspect_Ratio_2B. D'autres utilisateurs nous demandent de corriger notre matrice de projection de telle manière que Aspect_Ratio_2A = Aspect_Ratio_2B.

Nous pouvons également lire les commentaires de Robert à quelques reprises pour mieux comprendre.

De plus, je ne peux pas convenir que le quad rouge de la deuxième image a une taille de 200 par 200 pixels lorsqu'il est dessiné à l'écran. Comme nous le savons, un pixel est un carré, si le quadrilatère a l'un des côtés plus long que l'autre, le côté le plus long nécessite plus de pixels pour être dessiné à coup sûr. Personnellement, je ne sais pas ce qu'est la journalisation, mais il se peut que cela ne renvoie pas la taille des pixels de l'écran.

Jamil
la source