Confusão sobre o GLViewport

9

Espero que alguém possa me ajudar a entender o GLViewport e o que acontece quando o redimensionamos

Isso ilustrará minha confusão ....

insira a descrição da imagem aqui

Então, aqui tenho um quad preso no meio da tela. Se meu GLViewport corresponder à largura e altura do dispositivo, recebo o que está na primeira foto (mão esquerda). Exatamente o que eu esperaria.

  • Resolução do dispositivo, 2560 x 1600
  • Resolução de viewport 2560 x 1600
  • Quad tamanho 200 x 200 (Observe que a imagem acima não está à escala !!! :-))
  • Formato quad, aparece como quadrado

Agora, para a segunda foto (mão direita) ...

  • Resolução do dispositivo, 2560 x 1600
  • Resolução de viewport 2560 x 1200 (e centralizada verticalmente)
  • Tamanho quádruplo (200, 200)
  • Forma quad, aparece como retângulo

Minha pergunta é: por que o quad está exibindo agora um retângulo e não um quadrado? Confirmei, registrando que meu quad tem 200 x 200 pixels - certamente o tamanho dos pixels físicos permanece o mesmo? Eles não podem mudar. Então, o que está acontecendo aqui?

Eu pensei (claramente incorretamente) que, quando redimensionei a janela de visualização, ela apenas cortou pixels.

Gostaria que alguém pudesse explicar como isso funciona.

Editar

Atualmente, estou configurando minha viewport assim:

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 e offsetY são apenas para que, quando houver caixas de correio, a viewport seja centralizada.

BungleBonce
fonte
Você mudou sua matriz de projeção e a janela de visualização ao mudar de 1600 para 1200 pixels verticais? (você precisa)
bcrist
Olá @bcrist, consulte minha edição para mostrar como estou configurando minha janela de exibição. Tudo o que desenho com um número igual de pixels (digamos 50 x 50 ou 100 x 100) está desenhando 'esticado' - Alguma idéia ?!
BungleBonce
BTW, se você usar em glScissorvez de glViewport, simplesmente cortará os pixels sem alterar onde algo é renderizado. glViewportcomporta-se mais como redimensionar a imagem original, em vez de cortá-la; é por isso que esmaga sua caixa.
Nathan Reed
Obrigado @ NathanReed, ainda estou muito confuso. O que tenho é o seguinte: uma janela de visualização que exibe toda a tela. Uma caixa de tesoura dimensionada para manter a proporção do dispositivo original (para que eu possa exibir o jogo na caixa de tesoura e desenhar coisas fora dela para preenchimento), tudo parece esticado (verticalmente), por mais tempo do que largo. O que estou fazendo errado?
BungleBonce
Hmm. O retângulo de tesoura não deve mudar nada na proporção ou no dimensionamento da imagem. Se parecer correto sem a tesoura, apenas ativar a tesoura - mantendo a mesma janela de visualização, matriz de projeção etc. - deve simplesmente cortar a imagem.
Nathan Reed

Respostas:

11

Para entender o que está acontecendo, você precisa entender o pipeline de renderização:

Sua geometria (quad) é inicialmente definida no espaço do mundo, pense nisso como um sistema de coordenadas global. Dentro do shader de vértice, eles são transformados em coordenadas de dispositivo normalizadas (NDC), um sistema de coordenadas virtual definido para que tudo de -1 a 1 seja atraído para a tela. Observe que o NDC varia de -1 a 1 em X e Y e é totalmente independente da proporção e resolução dos dispositivos. Essa transformação do espaço mundial em NDC é feita pelo modelo, visão e matriz de projeção (de uma forma simples, apenas uma matriz para tudo ou a geometria foi definida no NDC para começar!).

A unidade de rasterização precisa saber onde e qual deve ser o tamanho da varredura, e é isso que você define com a chamada glViewport: por onde começar são os dois primeiros parâmetros, o tamanho é o segundo. O hardware será convertido das coordenadas NDC para pixel em uma escala e deslocamento simples - e é isso que você vê no seu exemplo: uma escala no eixo Y.

Portanto, para garantir que seu quad seja renderizado na proporção correta, você também precisa ajustar a matriz de projeção para incluir a proporção esperada da chamada glViewport.

Robert
fonte
Oi @Robert, muito obrigado por isso, estou tendo alguma dificuldade em tentar fazer isso ser implementado. Você poderia dar um exemplo de como configurar a matriz de projeção na sua resposta? Obrigado!
BungleBonce
4
Olá user22241, não há comandos OpenGL para fazer isso por você, você precisa definir a matriz por conta própria (uma matriz de flutuadores 4 por 4) e fornecê-los ao seu shader de vértice como um uniforme. Qual projeção você precisa (perspectiva, ortogonal) depende do que você deseja fazer. Se os conceitos matemáticos das projeções em 3D são novos para você, convém consultar os tutoriais do OpenGL que ensinam o perfil principal que funciona da mesma forma que o OpenGL ES a esse respeito.
Robert
@BungleBonce enquanto não houver comandos OpenGL para isso no perfil principal, você sempre pode olhar para a documentação de comandos obsoletos como glFrustum, que lista a matriz exata que é construída por essas funções. Outra matriz de projeção comum que você pode querer foi criada por glOrtho. Embora todos esses comandos sejam obsoletos, os documentos sobre eles são uma excelente fonte de algumas matemáticas pré-derivadas.
Ruslan
0

Na sua chamada para o glViewport, você está especificando menos pixels em largura e altura. Sua matriz de projeção é definida em termos de pixels. É por isso que você terá que calcular uma nova matriz de projeção após uma chamada glViewport.

bogglez
fonte
Olá @bogglez, obrigado pela sua resposta. Editei minha pergunta para mostrar (no final) qual código estou usando para minha janela de exibição. Tudo o que eu estou usando é glViewPort - essa é a maneira incorreta de fazer isso? Por favor, você poderia mostrar um exemplo do que você quer dizer com sua resposta? Obrigado.
BungleBonce
Leia isto: songho.ca/opengl/gl_projectionmatrix.html Para 2D, você deseja uma matriz de projeção ortogonal, para 3D, provavelmente, uma matriz de perspectiva. Se você usa o OpenGL moderno, você fornecerá uma matriz para um shader. Se você usar o OpenGL descontinuado com o pipeline gráfico fixo, usará funções como glLoadMatrix, glFrustum etc. para calcular a matriz de projeção. A biblioteca de utilitários GLU tem uma função gluPerspective ( opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml ) e gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ) para ajudá-lo com isso.
precisa saber é o seguinte
0

Para a primeira foto:

  1. Estamos criando uma matriz de projeção. Por exemplo, os parâmetros usados ​​são: Esquerda1, Direita1, Inferior1, Top1, Near1, Far1. Aqui, Aspect_Ratio_1A = (Direita1 - Esquerda1) / (Superior1 - Inferior1);

  2. Então, estamos fazendo uma transformação de porta de exibição. Por exemplo, os parâmetros usados ​​são: Largura1, Altura1. (Não estou mencionando parâmetros de turno por simplicidade). Aqui, Aspect_Ratio_1B = Largura1 / Altura1;

Para segunda imagem:

  1. Estamos criando a mesma matriz de projeção com os mesmos parâmetros de antes. Então: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. Desta vez, a transformação da porta de visualização está tendo parâmetros diferentes: Largura2 e Altura2. Aqui, Aspect_Ratio_2B = Largura2 / Altura2.

Observamos que Aspect_Ratio_1B e Aspect_Ratio_2B são diferentes. Especificamente eles são:

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

Portanto, se resumirmos o que estamos fazendo para o segundo caso, é:

Estamos projetando a imagem em um plano com Aspect_Ratio_2A e antes de mostrá-la ao usuário, estamos dimensionando-a para Aspect_Ratio_2B. Outros usuários estão nos pedindo para corrigir nossa matriz de projeção de forma que o Aspect_Ratio_2A = Aspect_Ratio_2B.

Também podemos ler os comentários de Robert algumas vezes para entender melhor.

Além disso, não posso concordar que o quad vermelho na segunda foto tenha um tamanho de 200 por 200 pixels quando desenhado na tela. Como sabemos, um pixel é um quadrado, se o quadrilátero tiver um dos lados mais longo que o outro, o lado mais longo precisará de mais pixels para ser desenhado. Pessoalmente, não sei o que é o log, mas pode ser que ele não retorne o tamanho do pixel da tela.

Jamil
fonte