Qual é a melhor maneira de desenhar muitas árvores

8

Estou escrevendo um aplicativo que processa uma ilha aleatória plantada com árvores. As árvores são atualmente dois quadriláteros, cruzados e desenhados com texturas. Planejo ter malhas mais complexas que formem diferentes tipos de plantas, como palmeiras, carvalhos, gramíneas etc.

Ilha da amostra

O problema que enfrento é que, como as texturas são transparentes, preciso desenhá-las de trás para frente. O plano-b é usar o descarte no frag shader, mas a ordem z fornece melhores resultados:

uniform float uTreeAlpha;
uniform sampler2D uTexture;

varying vec2 vTexCoordOut;

void main (void)
{
  vec4 colour = texture2D(uTexture, vTexCoordOut);
  if (colour.a < 0.1) {
    discard;
  }
  gl_FragColor = vec4(colour.rgb, colour.a * uTreeAlpha);   
}

O segundo problema é que a ordem muda dependendo da câmera e da aparência. Não conheço uma maneira eficiente de desenhá-las no OpenGL em uma única chamada.

Atualmente, meu código de renderização se parece com este pseudocódigo:

if cameraChangedFromLastTime() then
  sortTreesBackToFront();
end
for i = 0 to trees.size() -1
  drawTree()
end

Onde todo drawTree () define alguns uniformes, define a textura e chama glDrawArrays (). Eu tenho algumas otimizações para pular a configuração de uma textura ou atualizar as cordas de textura, se a última árvore e a corrente forem iguais, e definir alguns uniformes comuns fora do loop e pular árvores que estão muito distantes, mas basicamente se eu tiver 3000 árvores I ir 3000 vezes ao redor do loop.

Desenhar cada árvore individualmente é o assassino de desempenho. Se eu pudesse desenhá-los em uma única chamada ou em lotes (preservando a ordem Z), provavelmente o faria em 1/10 do tempo.

Então, como eu faria isso. Lembre-se de que minhas árvores são espaços reservados e, eventualmente, eu teria:

  • Malhas diferentes para árvores diferentes
  • Diferentes escalas e ângulos para as árvores para dar um pouco mais de variedade
  • Texturas diferentes para árvores diferentes, potencialmente várias texturas aplicadas a uma malha (por exemplo, deixa uma textura, tromba outra)
  • As árvores são todas misturadas, portanto, não há maneira simples de desenhar um tipo e depois outro
  • Alguma forma de animação cíclica simples (galhos balançando ao vento)
  • Todas as texturas residiriam em um único atlas

Então, qual é a melhor abordagem aqui? É possível renderizar em uma única passagem? Se eu usasse glDrawElements, reconstruindo os índices, mas não os vértices, conseguiria isso?

locka
fonte
vterrain.org , consulte a coluna da direita em plantas de seção para renderização de planta, respectiva coluna esquerda, renderização de seção para nível de detalhe / acelerações gerais de renderização. Cuidado, porém: a fonte é mais uma lista de trabalhos de pesquisa do que um tutorial.
Exilyth 27/03
Eu não sei muito sobre essas coisas. Mas confira o software VUE. É usado para criar paisagens com árvores, montanhas, atmosfera e muito mais, em 3d. Mas eu não tenho certeza se ele vai ajudar na sua situação
user1981248

Respostas:

3

O que você quer é instanciamento de hardware . Nota: Fiz isso no XNA (DirectX), mas não sei muito sobre o OpenGL. Estou certo de que existe um recurso comparável. Basicamente, o que isso significa é vincular os vértices do seu modelo de árvore a outro fluxo de vértices que carrega coordenadas mundiais para cada instância.

DrHeinous
fonte
11
O equivalente ao OpenGL seria a extensão opengl.org/registry/specs/EXT/draw_instanced.txt . Mas, para começar, exibir Listas nos objetos OpenGL e Vertex Array Legacy / Vertex Buffer Objects no OpenGL moderno pode funcionar. Nos dois casos, um objeto / malha é armazenado em List / VAO / VBO, e cada instância é desenhada com uma transformação diferente. Usando malhas estáticas, os dados podem ser carregados uma vez e depois reutilizados. sol.gfxile.net/instancing.html fornece uma breve visão geral sobre os diferentes métodos.
Exilyth 27/03
Obrigado, instanciar é uma ideia interessante. No entanto, não consegui usar uma extensão draw_instanced, pois estou usando o OpenGL ES 2.0 e estou trabalhando em algo que funciona em tudo. Talvez eu esteja pensando que posso carregar as várias malhas da árvore em um VBO (potencialmente com modelos mais simples mais distantes), classificar z e desenhá-las em lotes a partir de um buffer de índice que eu criaria para cada lote. Eu posso desenhar 30 ou 40 de cada vez dessa maneira.
31 de
2

A transparência só precisa ser solicitada se usar mistura não aditiva. Para uma tonelada de outdoors distantes, a mistura é desnecessária (você realmente não pode vê-lo). Renderize pelo menos os outros com transparência de recorte (alfa de apenas 1 ou 0) e não será necessário classificá-los.

Você pode usar uma espécie de folha de sprite para renderizar diferentes tipos de árvores, com animações criadas. Desenhe malhas para árvores mais próximas, que você pode animar com mais fidelidade com base nos ventos ou o que quiser.

Sean Middleditch
fonte
Eu experimentei o uso do descarte e da não classificação, mas os resultados parecem um pouco duff - as árvores tendem a se sobrepor muito; portanto, se não houver uma ordem consistente, recebo bastante pop onde uma árvore fica na frente da outra e " ganha "o pixel. Deixei o descarte porque ainda há colisões ocasionais (por exemplo, 2 árvores com a mesma distância exata da câmera), mas é um recuo. Também experimentei outdoors e o efeito é muito falso, especialmente para viadutos.
locka 28/03
Use cartazes melhores. Idealmente, tenha um modelo de árvore. Gere o sprite do outdoor para um ângulo de visão e use-o onde o ângulo corresponder aproximadamente. Para recortes, eles funcionam melhor à distância, onde você não vê a diferença. À medida que você se aproxima, você precisa usar modelos mais complicados (talvez alguns quadriláteros por árvore) ou pode mudar para a transparência da porta de tela.
Sean Middleditch 28/03
Em algum momento, você precisa descobrir o equilíbrio aceitável entre qualidade e velocidade. Você não será "incrivelmente rápido" e "perfeito" para as cenas mais complexas de hardware comum.
Sean Middleditch 28/03