Espero que alguém possa me ajudar a entender o GLViewport e o que acontece quando o redimensionamos
Isso ilustrará minha confusão ....
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.
fonte
glScissor
vez deglViewport
, simplesmente cortará os pixels sem alterar onde algo é renderizado.glViewport
comporta-se mais como redimensionar a imagem original, em vez de cortá-la; é por isso que esmaga sua caixa.Respostas:
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.
fonte
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 porglOrtho
. Embora todos esses comandos sejam obsoletos, os documentos sobre eles são uma excelente fonte de algumas matemáticas pré-derivadas.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.
fonte
Para a primeira foto:
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);
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:
Estamos criando a mesma matriz de projeção com os mesmos parâmetros de antes. Então: Aspect_Ratio_2A = Aspect_Ratio_1A;
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.
fonte