Confusión sobre GLViewport

9

Espero que alguien pueda ayudarme a comprender el GLViewport y lo que sucede cuando cambiamos el tamaño

Esto ilustrará mi confusión ...

ingrese la descripción de la imagen aquí

Entonces, aquí tengo un quad atrapado en el medio de la pantalla. Si mi GLViewport coincide con el ancho y la altura del dispositivo, obtengo lo que está en la primera imagen (izquierda). Exactamente lo que esperaría.

  • Resolución del dispositivo, 2560 x 1600
  • Resolución de la ventana de visualización 2560 x 1600
  • Tamaño cuádruple 200 x 200 (¡¡¡Nota, la imagen de arriba no está a escala !!! :-))
  • Forma cuádruple, aparece como cuadrado

Ahora, para la segunda foto (mano derecha) ...

  • Resolución del dispositivo, 2560 x 1600
  • Resolución de la vista 2560 x 1200 (y centrada verticalmente)
  • Tamaño cuádruple (200, 200)
  • Forma cuádruple, aparece como rectángulo

Mi pregunta es, ¿por qué el quad se muestra ahora como un rectángulo y no como un cuadrado? He confirmado al iniciar sesión que mi quad es de 200 x 200 pixeles, ¿seguramente el tamaño de los píxeles físicos se mantiene igual? No pueden cambiar. Entonces, ¿qué está pasando aquí?

Pensé (claramente incorrectamente) que cuando escalé la ventana gráfica, literalmente solo cortó píxeles.

Agradecería si alguien pudiera explicar cómo funciona esto.

Editar

Actualmente, estoy configurando mi ventana gráfica de esta manera:

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 y offsetY son solo para que cuando haya buzones, la ventana se centre.

BungleBonce
fuente
¿Cambió su matriz de proyección y la ventana gráfica al cambiar de 1600 a 1200 píxeles verticales? (lo necesitas)
bcrist
Hola @bcrist, mira mi edición para mostrar cómo estoy configurando mi ventana gráfica. Todo lo que dibujo que tiene el mismo número de píxeles (digamos 50 x 50, o 100 x 100) está dibujando 'estirado' - ¿Alguna idea?
BungleBonce
Por cierto, si usa en glScissorlugar de glViewport, simplemente recortará los píxeles sin cambiar el lugar donde se representa. glViewportse comporta más como cambiar el tamaño de la imagen original, en lugar de recortarla; Es por eso que golpea tu caja.
Nathan Reed
Gracias @NathanReed, todavía estoy realmente confundido. Lo que tengo es esto: una ventana gráfica que ocupa toda la pantalla. Una caja de tijera que se escala para mantener la proporción del dispositivo original (para que pueda mostrar el juego en la caja de tijera y dibujar cosas fuera de este para el relleno), todo parece estirado (verticalmente), por más tiempo que ancho. ¿Qué estoy haciendo mal?
BungleBonce
Hmm El rectificador de tijera no debería cambiar nada sobre la relación de aspecto o la escala de la imagen. Si parece correcto sin la tijera, entonces solo habilitar la tijera, manteniendo la misma ventana gráfica, matriz de proyección, etc., simplemente debería recortar la imagen.
Nathan Reed

Respuestas:

11

Para comprender lo que está sucediendo, debe comprender la canalización de representación:

Su geometría (el quad) se define inicialmente en el espacio mundial, piense en esto como un sistema de coordenadas global. Dentro del sombreador de vértices, estos se transforman en coordenadas de dispositivo normalizadas (NDC), un sistema de coordenadas virtual definido de modo que todo, desde -1 a 1, se dibujará en la pantalla. Tenga en cuenta que NDC varía de -1 a 1 en X e Y, y es totalmente independiente de la relación de aspecto y la resolución de los dispositivos. Esta transformación del espacio mundial a NDC se realiza mediante el modelo, la vista y la matriz de proyección (en una forma simple, ¡solo una matriz para todo o incluso la geometría se definió en NDC para empezar!).

La unidad de rasterización necesita saber dónde y qué tan grande debe rasterizar y esto es lo que define con la llamada glViewport: dónde comenzar son los dos primeros parámetros, el tamaño son los segundos dos. El hardware luego convertirá de NDC a coordenadas de píxel mediante una escala y un desplazamiento simples, y esto es lo que ve en su ejemplo: una escala en el eje Y.

Por lo tanto, para asegurarse de que su quad se procese en la relación de aspecto correcta, también debe ajustar la matriz de proyección para incluir la relación de aspecto esperada de la llamada glViewport.

Robert
fuente
Hola @Robert, muchas gracias por esto, tengo algunas dificultades para intentar implementar esto, ¿podrías dar un ejemplo de cómo configurar la matriz de proyección en tu respuesta? ¡Gracias!
BungleBonce
44
Hola usuario22241, no hay comandos de OpenGL para hacer esto por usted, debe definir la matriz por su cuenta (un conjunto de flotadores de 4 por 4) y proporcionarlos a su sombreador de vértices como un uniforme. La proyección que necesita (perspectiva, ortogonal) depende de lo que quiera hacer. Si los conceptos matemáticos de las proyecciones 3D son nuevos para usted, es posible que desee buscar tutoriales de OpenGL que le enseñen el perfil principal que funciona igual que OpenGL ES en este sentido.
Robert
@BungleBonce, aunque no hay comandos de OpenGL para esto en el perfil principal, siempre puede consultar la documentación de comandos obsoletos como glFrustum, que enumera la matriz exacta construida por estas funciones. Otra matriz de proyección común que puede desear fue creada por glOrtho. Si bien todos estos comandos son obsoletos, los documentos en ellos son una excelente fuente de algunas matemáticas derivadas previamente.
Ruslan
0

En su llamada a glViewport, está especificando menos píxeles de ancho y alto. Su matriz de proyección se define en términos de píxeles. Es por eso que tendrá que calcular una nueva matriz de proyección después de una llamada a glViewport.

bogglez
fuente
Hola @bogglez, gracias por tu respuesta. Edité mi pregunta para mostrar (al final) qué código estoy usando para mi ventana gráfica. Todo lo que estoy usando es glViewPort: ¿es esta forma incorrecta de hacer esto? ¿Podría mostrar un ejemplo de lo que quiere decir en su respuesta? Gracias.
BungleBonce
Lea esto: songho.ca/opengl/gl_projectionmatrix.html Para 2D desea una matriz de proyección ortogonal, para 3D probablemente desee una matriz de perspectiva. Si usa OpenGL moderno, suministrará una matriz a un sombreador. Si usa OpenGL en desuso con la tubería de gráficos fija, usará funciones como glLoadMatrix, glFrustum, etc. para calcular la matriz de proyección. La biblioteca de utilidades GLU tiene una función gluPerspective ( opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml ) y gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ) para ayudarlo con eso.
bogglez
0

Para la primera foto:

  1. Estamos creando una matriz de proyección. Por ejemplo, los parámetros utilizados son: Left1, Right1, Bottom1, Top1, Near1, Far1. Aquí, Aspect_Ratio_1A = (Derecha1 - Izquierda1) / (Superior1 - Inferior1);

  2. Entonces estamos haciendo una transformación del puerto de vista. Por ejemplo, los parámetros utilizados son: Ancho1, Altura1. (No estoy mencionando los parámetros de cambio por simplicidad). Aquí, Aspect_Ratio_1B = Ancho1 / Altura1;

Para la segunda foto:

  1. Estamos creando la misma matriz de proyección con los mismos parámetros que antes. Entonces: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. Esta vez, la transformación del puerto de vista tiene diferentes parámetros: Ancho2 y Altura2. Aquí, Aspect_Ratio_2B = Width2 / Height2.

Observamos que Aspect_Ratio_1B y Aspect_Ratio_2B son diferentes. Específicamente son:

Aspect_Ratio_1B = 2560/1600 = 1.6 Aspect_Ratio_2B = 2560/1200 = 2.13

Entonces, si resumimos lo que estamos haciendo para el segundo caso es:

Estamos proyectando la imagen en un plano con Aspect_Ratio_2A y antes de mostrársela al usuario, la estamos ampliando a Aspect_Ratio_2B. Otros usuarios nos piden que corrijamos nuestra matriz de proyección de tal manera que Aspect_Ratio_2A = Aspect_Ratio_2B.

También podemos leer los comentarios de Robert un par de veces para tener una mejor comprensión.

Además, no puedo aceptar que el quad rojo en la segunda imagen tenga un tamaño de 200 por 200 píxeles cuando se dibuja en la pantalla. Como sabemos, un píxel es un cuadrado, si el quad tiene uno de los lados más largo que el otro, el lado más largo requiere más píxeles para dibujar con seguridad. Yo, personalmente, no sé qué es el registro, pero es posible que no devuelva el tamaño de píxel de la pantalla.

Jamil
fuente