OpenGL: Redimensionando a tela e glOrtho / glViewport

16

Eu pesquisei essa questão de várias fontes e ainda não encontrei uma resposta firme dizendo que "sim, isso é pensamento correto" ou "não, eis como é feito".

Estou tentando garantir a independência da resolução com a renderização do OpenGL. O jeito que acho que devo fazer isso é criar uma projeção usando o glOrthoque eu quiser que as coordenadas do mundo sejam. Por exemplo glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0),. Em seguida, defina a janela de exibição para a resolução da tela , ou seja, - glViewport(0, 0, 800, 600). Por fim, sempre que a janela for redimensionada, faça uma chamada glViewportcom a resolução de tela atualizada. Isso vai escalar seus números.

Essa é a maneira correta de garantir que os modelos ocupem a mesma proporção de espaço na tela em diferentes resoluções? Devo estar usando uma projeção igual à resolução também? Encontrei algumas respostas dizendo que glOrthodeveria usar a resolução da sua janela enquanto outros disseram que deveria / pode ser diferente.

Pensamentos?

Chris Henderson
fonte

Respostas:

20

O que você descreveu é inteiramente adequado e apropriado para fornecer independência de resolução. Qualquer coisa que você desenhar sempre terá a mesma proporção da sua janela.

No entanto, se você não fizer nada além disso, terá problemas de proporção . Por exemplo, dados os números que você escreveu, se você desenhar um círculo, ele será esmagado - mais largo do que alto, porque sua escala horizontal é 800 / (50 + 50) = 8 e sua escala vertical é 600 / (50+ 50) = 6.

Não pode haver nenhuma solução automática para esse problema ; você terá que escolher qual resultado gráfico deseja e considerar seu efeito na jogabilidade. Alguns exemplos comuns:

  • Em um jogo 3D de projeção em perspectiva sem HUD, a solução simples usual (disponível no OpenGL como parte de gluPerspective) é fixar o campo de visão da projeção em relação à dimensão vertical . Isso significa que, em um jogo desse tipo, se você redimensionar a janela horizontalmente, verá mais ou menos a cena e a parte do meio da imagem não será alterada.

    A mesma idéia também pode ser aplicada a uma visualização 2D / 2.5D.

    (Observe que isso permite ao jogador ampliar seu campo de visão horizontalmente, criando uma janela larga, mas não alta. Isso pode ser indesejado em um jogo multiplayer competitivo.)

  • Se você tiver gráficos de preenchimento de viewport com uma proporção fixa (por exemplo, um mapa 2D sem rolagem ou uma borda decorativa), ou se não conseguir alterar o layout, precisará fazer algo como ter barras pretas nas duas lados para preencher o espaço não utilizado.

    Ou você pode criar gráficos que tenham material de preenchimento tematicamente consistente em torno das bordas, para que possam ser cortados para caber na tela sem prejudicar a jogabilidade.

  • Se você tiver um HUD em cima de outros gráficos, poderá decidir que cada elemento do HUD será fixo a uma parte da janela (canto superior esquerdo, centro inferior etc.) e calcular suas coordenadas; o 'alongamento' da variação das proporções é absorvido pelo 'espaço em branco' entre os elementos do HUD.

Quanto aos matemática especificidades desta questão, uma vez que você está fazendo independência de resolução, tudo que você precisa para começar com é a relação de aspecto, um único número: width / height. Por exemplo, se a janela for quadrada, será 1; se for 800 por 600, será 800/600 = 4/3 = 1,33333.

Por exemplo, suponha que você queira que a projeção ortográfica que você escreveu ganhe espaço adicional nos lados esquerdo e direito se a janela for ampliada. Você pode fazer isso assim:

float aspect = width / height;
glViewport(0, 0, width, height);
glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);

Isso garante que, para janelas com pelo menos a largura de altura, qualquer coisa que você desenhe com as coordenadas xey entre -50 e 50 será visível.

Por outro lado, se a janela for mais estreita do que alta, o intervalo de 50 a 50 será cortado. Digamos que você queira ter certeza de que ele esteja sempre visível (para que seu conteúdo tenha o tamanho máximo se a janela for quadrada, mas menor caso contrário); nesse caso, você simplesmente faz a mesma coisa com a altura, em vez da largura.

float aspect = width / height;
glViewport(0, 0, width, height);
if (aspect >= 1.0)
  glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);
else
  glOrtho(-50.0, 50.0, -50.0 / aspect, 50.0 / aspect, 1.0, -1.0);

Observe que no segundo caso, dividimos em vez de multiplicar. Isso é simplesmente porque calculamos a proporção da imagem em width / heightvez de height / width; tome o recíproco se achar mais fácil entender dessa maneira.

Novamente, essa não é a única maneira de gerenciar a proporção; este é apenas um método muito simples para garantir que seu conteúdo não seja esmagado nem cortado. Descubra o que você quer que aconteça quando sua janela for larga, alta ou o que for; então elabore a matemática disso.

Kevin Reid
fonte
Obrigado pela resposta MUITO perspicaz. Respondeu à minha pergunta além do suficiente.
22413 Chris Henderson