Jogos 2D e OpenGL moderno

10

Preconceitos

Ok, então o que eu reuni até agora é o seguinte:

  • não use pipeline fixo (descontinuado ou será descontinuado)
  • o vbos armazena "modelos de objetos" (n dados de vértices, principalmente)
  • vaos descrevem como os dados são estabelecidos para que as chamadas de chamada saibam qual parte de cada vbo é para que tipo de informação de vértice (um vao pode se referir a vários vbos, o oposto é meio difícil)
  • cada chamada de desenho também envia dados de vértice para shaders

Como vejo 3D (opcional)

Dadas essas informações, posso ver como desenhar objetos complicados em 3D é muito bom com o OpenGL moderno. Você basicamente carrega vários modelos de objetos (provavelmente do Blender ou outro software similar) nos VBOs com coordenadas locais e simplesmente fornece a cada instância de um objeto um parâmetro de sombreador diferente (deslocamento) para desenhar no espaço do mundo.

Problema / pergunta

Em 2D, problemas e prioridades são completamente diferentes. Você não desenha objetos muito complexos, não precisa de matrizes de projeção complicadas e outros enfeites e shaders são muito mais simples.

Qual seria a melhor maneira de desenhar geometrias que mudam frequentemente (realmente frequentemente, basicamente todos os quadros) com o OpenGL moderno?

No parágrafo a seguir, você pode ver algumas idéias de problemas (o problema do círculo e do retângulo), que identificam melhor o tipo de mudança em que estou interessado.

Minhas tentativas (opcional)

Então, comecei a pensar em como lidaria com o desenho de geometria 2D básica na tela:

  • um quadrado: carrega um [(1, 0), (1, 1), (0, 1), (0, 0)]VBO para a geometria de um quadrado no espaço local e, em seguida, forneça ao shader a largura real do quadrado e as coordenadas do mundo e as informações de cores

esfria, parece fácil. Vamos para um círculo:

  • um círculo: ventilador triangular com ... eh. quanta precisão (número de vértices)? para pequenos círculos, a precisão deve ser pequena e, para círculos de erros, a precisão deve ser alta. O carregamento claro de 1 VBO não pode atender a todos os casos. E se eu precisar adicionar precisão porque um círculo é redimensionado para ser maior?

Menos legal. Vamos para algo um pouco mais fácil, um retângulo:

  • um retângulo: eh. não há "geometria geral do retângulo". Você apenas tem uma proporção de largura / altura e é isso, mas cada retângulo provavelmente é diferente se o tamanho mudar.

Como você pode ver, as coisas vão ladeira abaixo a partir daí. Especialmente com polígonos complexos e outros enfeites.

Nenhuma política de código: P

Eu só preciso de uma visão geral da idéia, nenhum código é necessário, especialmente código C ou C ++. Apenas diga coisas como: "faça um VBO com esses dados de vértice e ligue-o, ...".

Sapato
fonte
Acho que entendi o que você está perguntando, mas você pode querer dar a essa pergunta um pouco mais de orientação. Não está claro o que está sendo solicitado - o que é realmente um motivo próximo.
Lysol
@AidanMueller Não sei ao certo o que você quer dizer, mas fique à vontade para dar mais orientações, se achar necessário.
Shoe
A resposta principal atualmente começa dizendo "Sua principal pergunta parece ser". Isso indica que não está claro o que você está perguntando. Talvez você deva dar um resumo do que não precisa saber ao final da sua pergunta. Afinal, este é um questionário, não uma discussão.
Lysol
@AidanMueller Não nesse contexto, acredito. Ele diz "Sua pergunta principal parece ser ..." e depois cita a pergunta que eu postei. O que na verdade indica que é claro o suficiente para ser citado. Além disso, a frase indica não que minha pergunta não esteja clara, mas que há uma pergunta principal e outra secundária (que é: qual é a solução para os casos específicos que apresentei). Realmente não vejo o problema com a minha pergunta atual e, aparentemente, nem os respondentes viram como achei as duas respostas muito úteis e objetivas.
Shoe
Você pode desenhar um círculo preciso com um shader de fragmento.
user253751

Respostas:

5

Sua principal pergunta parece ser:

Qual seria a melhor maneira de desenhar geometrias que mudam frequentemente (realmente frequentemente, basicamente todos os quadros) com o OpenGL moderno?

De muitas maneiras, não há grande diferença entre 2D e 3D OpenGL. O pipeline gráfico possui uma coordenada extra, Z, que não será usada tanto em 2d, mas é isso.

Existem algumas maneiras de alterar a geometria em cada desenho.

  • Você pode enviar novos vértices fornecidos pela CPU a cada quadro. (Consulte /programming/14155615/opengl-updating-vertex-buffer-with-glbufferdata para obter algumas notas sobre a reutilização de buffers.)

  • Você pode desenhar diferentes partes de um buffer existente, com glDrawArrays(mode, first, count). Se a animação repetir, talvez você possa colocar os quadros pré-computados com as diferentes listas de vértices em um buffer grande e desenhar a parte apropriada do buffer em cada quadro.

  • Você pode influenciar a lista de vértices com outros dados, como uma matriz uniforme ou uma textura. No seu shader de vértice, leia esses dados e aplique-os adequadamente. Essas são apenas outras expressões idiomáticas para a apresentação de dados na GPU e provavelmente não terão muita diferença no desempenho.

  • Se você tiver muitas instâncias da mesma geometria (possivelmente influenciadas por atributos), glDrawElementsInstanced()poderá ser útil

  • Você pode influenciar a lista de vértices algoritmicamente nos shaders de vértice, geometria ou mosaico. Se a animação puder ser descrita matematicamente, você poderá manter a mesma lista de vértices e alterar apenas alguns uniformes de shader a cada quadro.

E talvez sua animação possa ser expressa em texturas puras, com todas as animações feitas pixel por pixel pelo processador ou pré-renderizadas a partir do disco.

No geral, eu diria: "Os computadores são rápidos, fazem com que funcione da maneira mais fácil possível, o que provavelmente é configurando vértices frescos da CPU a cada quadro. Depois, veja se isso é bom o suficiente. Analise o uso da bateria / CPU primeiro, pegada de memória segundo. "

Sua outra pergunta , parafraseada, "Qual é uma boa maneira de desenhar círculos e retângulos?"

Círculos.

  • Com os shaders de mosaico (ou shaders de geometria), você pode tornar sua geometria dinâmica.

  • Você pode desenhar quadrados e, no fragmento, o shader apenas opaco (alfa = 1,0) dentro de um raio e transparente (alfa = 0,0) fora do raio. Então, é pixel perfeito todas as vezes. (Faça seus vértices quadrados de -1 a +1 e, no fragmento shader, algo como outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;,. Também poderia suavizar um pouco a borda, ficaria bom lá ...)

  • Você sempre pode usar, digamos, uma ventoinha de 120 triângulos. Provavelmente bom o suficiente.

Retângulos.

  • Eu acho que você respondeu sua própria pergunta, nessa. O que você sugere funcionará bem!
david van brink
fonte
O fragmento-shader / raio é bem legal, obrigado. Com relação a responder minha própria pergunta, acho que não entendi o que você quis dizer.
Shoe
Ah, assim como com um quadrado, você menciona para controlar a largura (com uniforme, presumo) e escreveu: "Você apenas tem uma proporção de largura / altura e é isso, mas cada retângulo é provavelmente diferente se o tamanho mudar" . Portanto, para um retângulo, faça o mesmo que um quadrado, mas você precisará de 4 valores (x, y, w, h) em vez de 3 (x, y, w). Ou passe (xlow, xhigh, ylow, yhigh) como quatro uniformes. Com sua entrada (0,0) a (1,1), é suficiente para o Vertex Shader fazer o que precisa.
David van brink
Oh, entendo, isso faz sentido.
Shoe
Existe um ventilador automático no GL moderno, como GL_TRIANGLE_FAN, do pipeline de função fixa?
John P
5

Não posso dizer que sou especialista nesse assunto e, no (s) meu (s) projeto (s) de jogo, concentrei-me mais no lado 3D, então meu lado 2D é bastante simples, geralmente usando coisas feitas para o lado 3D; e, obviamente, minha perspectiva é do lado dos jogos, então meus gráficos 2D têm mais a ver com sprites do que com geometria. Nessa perspectiva,

1) Quadrados e retângulos são bem fáceis. Eu tenho apenas uma caixa 1x1 em um VBO que eu uso para cegar tudo. Eu passo matrizes MVP para sombreador com essa "caixa de unidade" e a combinei com escala adicional para dimensionar a caixa para as dimensões corretas - como você sabe, você pode ter diferentes escalas x e y.

Para meus propósitos, tenho pensado em deixar de usar a "caixa unitária" para algum tipo de mecanismo de partículas para misturar sprites 2D, mas isso é outra história.

2) Não trabalho muito com círculos, apenas uso VBOs fixos com número específico de vértices. Mas eu poderia imaginar que poderia dar alguns passos para afetar o número de vértices desenhados para o círculo.

Ao conectar dados VBO a atributos de sombreador, uso glVertexAttribPointer. Possui parâmetro de passada destinado a ser usado para dados intercalados (que eu uso). Mas pode ser possível usá-lo assim:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

... para escolher cada enésimo vértice do buffer, afetando assim o número de vértices desenhados para o círculo. Eu poderia criar vários VAOs com o mesmo VBO com passo diferente afetando o número de vértices desenhados para o círculo. Eu não tentei isso, pensou.

Em geral, sim, trabalhar com VBOs e outros torna os ajustes do lado da CPU um pouco mais complexos, por que tenho estudado coisas diferentes para fazer ajustes no lado da GPU (shaders). Ainda assim, de acordo com este artigo, o uso de VBOs é mais eficiente em hardware moderno, mesmo se você precisar de muita "intervenção" do lado da CPU:

http://www.quelsolaar.com/opengl_performance.txt

Espero que isso ajude um pouco a projetar e decidir suas direções.

MaKo
fonte
2
"passo aprimorado para afetar o número de vértices desenhados para o círculo" Super legal!
David van brink