A maneira mais eficiente de desenhar grande número dos mesmos objetos, mas com transformações diferentes

8

Gostaria de desenhar um grande número (vários milhares) de malhas simples (cada uma talvez ... um máximo de 50 triângulos, mas mesmo esse é um limite superior muito grande), todos exatamente iguais.

Como uma maneira simples de força bruta, agora eu estou apenas fazendo milhares de chamadas de empate, onde apenas altero as matrizes de transformação de que os shaders precisam e depois desenha os mesmos objetos novamente.

É claro que isso é terrivelmente lento, já que (eu acho) existem muitas chamadas de empate para o driver e meu PC lidar com eficiência.

O que posso fazer para torná-lo mais rápido?

TravisG
fonte
4
Não posso lhe dar uma resposta completa, mas a resposta de alto nível é usar instâncias geométricas .
Seth Battin
Pesquisa no Google por "Geometry Instancing", talvez você possa encontrar algo que ajuda você desse jeito
Luis W

Respostas:

11

A solução para isso é instanciar. Este tutorial explica alguns métodos de instanciamento. Se você tiver ARB_draw_instancede ARB_instanced_arrays, use-os.

A idéia geral é armazenar todas as transformações de suas malhas em um objeto de buffer separado e vinculá-lo a uma matriz de atributos que usa um "vértice" por instância via glVertexAttribDivisor.

Se, depois disso, você ainda não estiver executando o mais rápido que deseja, provavelmente estará vinculado ao processador de vértices. Faça o descarte de frustum nas malhas e, de preferência, construa uma BVH para atravessar, em vez de fazer o abate em todas as malhas de maneira independente.

Robert Rouhani
fonte
11
+1; com muitos milhares de objetos, você também pode ficar vinculado à CPU nas transformações (basta enviar posição e rotação no buffer por instância e calcular a matriz por objeto na GPU pode ajudar aqui) e não se esqueça de observar como você atualiza esse buffer de vértice dinâmico!
Maximus Minimus
@ Robert Rouhani: Obrigado, eu pesquisei e prontamente o implementei. Agora eu posso desenhar 5000 malhas com 20 tris cada a 250 FPS. A propósito, o caminho sugerido parece um pouco desatualizado. Como o instanciamento da geometria do OpenGL 3.algo é parte oficial da especificação principal do OpenGL, não é mais necessário o ARB_xxx. Eu uso um buffer uniforme para armazenar as matrizes e uso glDrawElementsInstanced. Dentro do vertex shader, há uma matriz uniforme de layout (std140) {mat4 array [5000]; } onde eu posso acessar o elemento relevante via array [gl_InstanceID]
TravisG 4/13
11
@ TravisG Eu costumo tentar suportar versões mais antigas. Entendo que essas duas extensões foram promovidas para o núcleo por um tempo, a sequência de extensões ainda estará presente, no entanto :). Além disso, o uso glVertexAttribDivisor(que não é obsoleto ou desatualizado por qualquer meio) tem o benefício de não ter um limite superior na contagem de instâncias. O desempenho tem sido historicamente melhor que os buffers uniformes, mas provavelmente é o mesmo ou muito semelhante agora, e os dois lados fazem o trabalho.
Robert Rouhani
@ Robert Rouhani: Mhm ... acho que é verdade. Alguém com drivers desatualizados pode suportar ARB_xxx, mas não os principais recursos oficiais do OpenGl 3.x. Vou dar uma olhada no glVertexAttribDivisor, obrigado.
TravisG 4/13
@ Robert Rouhani: implementei as duas versões (usando buffers uniformes e, alternativamente, a sua versão sugerida, onde uso um atributo de vértice que muda apenas uma vez por instância), e a versão do buffer uniforme é duas vezes mais rápida (4000 fps no modo de lançamento, vs ~ 2000 com glVertexAttribDivisor, o número de 250 fps era apenas para o lado da CPU).
TravisG