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 ...
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.
la source
glScissor
place deglViewport
, il supprimera simplement les pixels sans changer l'emplacement du rendu.glViewport
se comporte plus comme redimensionner l'image originale, plutôt que de la recadrer; c'est pourquoi il écrase votre boîte.Réponses:
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.
la source
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 parglOrtho
. Bien que toutes ces commandes soient obsolètes, les documents qu'elles contiennent sont une excellente source de mathématiques prédérivées.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.
la source
Pour la première photo:
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);
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:
Nous créons la même matrice de projection avec les mêmes paramètres qu'auparavant. Donc: Aspect_Ratio_2A = Aspect_Ratio_1A;
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.
la source