Usando instanciamento para tudo?

16

A instância melhora o desempenho (significativamente) ao renderizar várias cópias (centenas? Milhares?) Da mesma malha ao mesmo tempo. Mas quanto sobrecarga ela tem ao renderizar exatamente uma cópia com uma chamada de desenho? Seria uma boa ou má idéia usar instanciamento para toda a geometria renderizada pelo mecanismo?

Edit: Digamos que estamos criando um jogo de FPS. A maioria dos objetos tem apenas um exemplo: uma faca, uma arma, uma metralhadora, um prédio e uma torre de rádio. Mas também existem alguns objetos com várias instâncias: árvores (por exemplo, três tipos de árvores com centenas de instâncias), grama e assim por diante ... O que quero dizer é: em vez de renderizar os objetos de uma instância da maneira "tradicional" e árvores e grama usando instanciamento, renderizamos todos eles usando instanciação. Portanto, nossa torre de rádio possui apenas uma instância (cujas informações armazenamos em um buffer de dados da instância) e processamos essa torre usando algum tipo de DrawInstanced()chamada com contagem de instâncias igual 1. O mesmo acontece com todos os outros objetos (é claro, árvores e grama têm várias instâncias).

Então, minha pergunta é: é uma má idéia desenhar uma única instância de um objeto usando instanciamento? O instanciamento tem muita sobrecarga (em termos de memória e desempenho) ou é de alguma forma indesejável para renderizar objetos de instância única?

NPS
fonte

Respostas:

19

No D3D9 com XPDM, você quase certamente deseja instar sempre que possível. O overhead de chamadas em draw é tão alto que faz sentido. Nesse cenário, o ponto de cruzamento pode ser tão baixo quanto 2 ou 3 instâncias.

Se você tiver apenas uma instância de uma determinada malha, pode parecer tentador, na superfície, desenhá-la sem instancia. No entanto, observe o que está envolvido:

  • Você precisa alternar entre carregar dados em um buffer por instância e fazer upload de constantes de sombreador.
  • Você precisa manter duas cópias do seu shader de vértice: uma para instância e outra para não instanciada.
  • Você precisa manter duas cópias do seu código de renderização: da mesma forma.
  • Você precisa mudar os shaders.
  • Você precisa mudar os formatos de vértice.
  • Pode ser necessário alternar os buffers de vértice.
  • E então você precisará fazer tudo de novo se voltar ao instanciado desenho para o próximo grupo de malhas.

Mesmo se você tiver apenas uma única malha (como o modelo de arma em um FPS), há casos em que a instanciação é útil. Digamos que você esteja acumulando luz multipass em um renderizador para a frente e com um pré-passe z. Em vez de um passe extra para cada luz, você cria os dados das luzes por instância e os desenha instanciados.

Com base no primeiro cenário, a moral da história é que, se qualquer classe de objeto pode usar instanciação, faz sentido sempre usar instanciação para todos os objetos dessa classe.

Com base no segundo cenário, a moral da história é que instanciar pode ter usos não óbvios que vão além de apenas dizer "eu preciso desenhar 20 árvores".

Maximus Minimus
fonte
As razões que você deu são as mesmas que me fizeram fazer essa pergunta em primeiro lugar. Obrigado.
NPS
12

(No meu sistema, não testei em nenhum outro lugar) No GL, instanciar uma única malha (desenho com contagem = 1) tem uma sobrecarga desagradável, mas não sei de onde ela vem. Eu sugiro fortemente que não faça isso.

Testei isso em uma aplicação prática há alguns meses. Codifiquei alguns algoritmos de iluminação global na cena Crytek Sponza, que consiste em aproximadamente 350 malhas (não me lembro exatamente), das quais algumas compartilham algumas instâncias. No começo, eu fiz como você sugere, instale tudo e desenhe o restante com a contagem de instâncias 1, pois isso simplificou um pouco o código de renderização.

Mais tarde, ao otimizar o renderizador, apenas passar de instanciar os objetos count = 1 para enviá-los da maneira usual me salvou em cerca de 3,5 milissegundos por quadro em um i7 3770k (e GTX 770). Mudar as malhas com várias instâncias para apenas fazê-las da maneira tradicional me salvou mais 0,5 ms. No geral, o aplicativo passou de ~ 120 FPS para cerca de ~ 230 FPS.

É claro que esses números sempre dependem de onde estão os gargalos em seu aplicativo, e os últimos 0,5 ms podem realmente se tornar um abrandamento em um aplicativo em que você é muito limitado. Mas, caso contrário, na minha experiência, a instanciação tem uma sobrecarga desagradável se você não estiver desenhando muitas coisas ao mesmo tempo.

TravisG
fonte
Interessante, mas seria bom ver dados para os drivers AMD e Intel também; caso contrário, você realmente deveria dizer "No meu sistema" em vez de "No GL". Por outro lado, mesmo que não seja um problema com outras implementações, o fato de que isso possa acontecer é uma razão suficiente para evitar instâncias se você não estiver usando.
bcrist 5/05
2

Você pode ter certeza de que desenhar um único objeto instanciado é mais caro do que desenhar um único objeto normalmente. Para instanciar, a GPU está se preparando para uma grande quantidade de objetos e essa preparação será diferente da de um único objeto. No entanto, o tamanho dessa lacuna de desempenho só pode ser encontrado através da experimentação e depende muito da sua configuração de renderização real. A única maneira de saber com certeza é testando você mesmo. O benchmarking de uma única chamada de empate é difícil. Aqui estão várias idéias sobre como você pode proceder.

Roy T.
fonte
2

Faz quatro anos ... e acho seguro dizer que é perfeitamente adequado enviar chamadas de instancia "instanciadas" com 1. Como você deve ter notado, as novas APIs DX12 e Vk têm uma contagem de instâncias que pode variar de 0 a NUM_INSTANCES . Observe também que não há DrawIndexed (...) .

EDITAR

Como uma nota de cautela, o acima exposto provavelmente é bom com essas APIs modernas, talvez o uso de algo antigo como Gl <3.3 ou DX11 exija alguns perfis, conforme mencionado por outros usuários.

Nacho
fonte