Quais são as técnicas comuns de otimização de renderização para a passagem da geometria em um renderizador de sombreamento adiado? [fechadas]

16

Estou desenvolvendo um mecanismo de jogo usando OpenGL 3 e C ++ (e glfw para gerenciamento de janelas). Eu tenho avançado até agora, consegui a maioria das coisas, exceto entidades sólidas e otimizações. O mecanismo usa sombreamento diferido, portanto, como o sombreamento diferido é um processo cansativo para uma GPU média, desejo otimizar o processo de renderização o máximo possível.

O sistema atual consiste em uma cena, contendo um renderizador e o mundo atual e o mundo mantém entidades e entidades de iluminação como separadas std::vectors.

Então, basicamente, toda vez que a Cena é chamada ->render(), chama o Renderer, passando o mundo como um parâmetro e obtém os iteradores de entidade do mundo, os atrai para o FBO e depois passa pelas entidades de iluminação para o segundo passe. E acho que isso não é suficiente.

Meu algoritmo atual percorre tudo, mesmo que a entidade não esteja no espaço da tela. Estou pensando em uma maneira de otimizar o algoritmo de renderização atual, para que ele chame apenas as funções da API apenas para os objetos visíveis; então, quais são as técnicas comuns para otimizar esse renderizador?

deniz
fonte

Respostas:

41

O sombreamento adiado é apenas uma técnica para "adiar" a operação real de sombreamento para estágios posteriores; isso pode ser ótimo para reduzir o número de passes necessários (por exemplo) para renderizar 10 luzes que precisam de 10 passes. Meu argumento é que, independentemente da técnica de renderização que você está usando, há certas otimizações de renderização possíveis que reduzem o número de objetos (vértices, normais etc.) que seu pipeline de renderização precisa processar.

Não há um padrão de fato para otimizações de renderização, mas várias técnicas que podem ser usadas de forma intercambiável ou em conjunto para atingir determinadas características de desempenho. O uso de cada técnica depende muito da natureza da cena que está sendo renderizada.

A renderização adiada tenta resolver o problema quando o número de luzes aumenta, o que na renderização para frente pode fazer o número de passes explodir.

Essas técnicas não otimizam diretamente a parte de sombreamento adiado, mas, de acordo com sua descrição, a parte de sombreamento adiado NÃO é seu problema. Seu problema, porém, é que você está enviando a cena inteira para o pipeline de renderização. Portanto, seu mecanismo precisa processar (por exemplo, todos os 100 milhões de vértices) em sua cena apenas para poder enviar o resultado ao buffer g, enquanto a maioria desses 100 milhões de vértices pode ser descartada trivialmente e não enviada ao o vértice do pré-processo e os fragmentos passam.

No caso de um renderizador direto, o N vértice será processado pelo estágio de vértice como um total vertex count*lights counte pelo estágio de fragmento como um total fragments count*number Lights, o sombreamento adiado reduz efetivamente isso apenas vertex countpara o estágio de vértice e fragments counta contagem de fragmentos, antes de resolver o problema. sombreamento real. Mas ainda assim N pode ser muito difícil de processar, especialmente quando a maioria deles pode ser descartada trivialmente.

Isso torna o abate mais eficaz no caso de renderização direta / passes múltiplos. Mas lembre-se de que a maioria dos mecanismos usará uma abordagem de renderização dupla, porque o sombreamento diferido por si só não pode resolver objetos transparentes, isso faz com que o uso dessas otimizações seja obrigatório. Não conheço nenhum mecanismo comercial que não faça todos eles.

Frustum Culling

Somente os objetos incluídos total ou parcialmente no perfil da exibição precisam ser enviados ao pipeline de renderização. Esse é o conceito básico de seleção de frustum, infelizmente, verificar se uma malha está dentro / fora da vista frustum pode ser uma operação cara; portanto, os projetistas de motores usam um volume limite aproximado, como uma caixa delimitadora ou esfera delimitadora de eixo (AABB) ou esfera delimitadora , mesmo que isso não seja tão preciso quanto usar a malha real, a diferença de precisão não vale a pena verificar com a malha real.

insira a descrição da imagem aqui

Mesmo com volumes delimitadores, você realmente não precisa verificar cada um deles; em alternativa, você pode construir uma hierarquia de volumes delimitadores para realizar uma seleção anterior, pois isso depende muito da complexidade da cena.

Essa é uma técnica boa e simples para um mecanismo menor e é quase usada em todos os mecanismos que já usei. Eu recomendo o uso de uma verificação de volume / volume limite "normal" sem hierarquias se o seu mecanismo não exigir a renderização de cenas muito complexas.

Hierarquia de volume delimitador

Seleção da face traseira

Esta é uma obrigação, por que desenhar rostos que não serão visíveis de qualquer maneira? As APIs de renderização fornecem uma interface para ativar / desativar o descarte da face traseira. A menos que você tenha um forte motivo para não ativá-lo, como alguns dos aplicativos CAD que precisam chamar a atenção em determinadas circunstâncias, isso é algo que deve ser feito.

Seleção de Oclusão

Usando o buffer Z, você pode resolver a determinação da visibilidade. Mas o problema é que o buffer Z nem sempre é ótimo em termos de desempenho, já que o buffer Z só pode ser resolvido em estágios posteriores do pipeline, os objetos ocluídos devem ser rasterizados e podem ser gravados no buffer Z e no Buffer de cores antes de falhar no teste Z.

A seleção por oclusão resolve isso, fazendo alguns testes iniciais para selecionar objetos ocluídos que estão no frustum de renderização. Uma implementação prática do descarte de oclusão é usar consultas baseadas em pontos e verificar se certos objetos são visíveis a partir de uma vista de ponto específica. Isso também pode ser usado para selecionar luzes que não contribuem para a imagem final, o que é especialmente útil em um renderizador de mecanismo adiado.

insira a descrição da imagem aqui

Um ótimo exemplo do mundo real dessa técnica está no GTA5, onde os arranha-céus estão estratigicamente posicionados no centro da cidade, não são apenas decorações, mas também funcionam como oclusores, efetivamente ocluindo o resto da cidade e impedindo que ela seja rasterizado.

LOD

Nível de detalhe

O nível de detalhe é uma técnica amplamente utilizada, a idéia é usar uma versão mais simples da malha quando a malha estiver menos contribuindo para a cena. existem duas implementações comuns; basta trocar a malha por uma mais simples quando não está mais contribuindo muito, a malha é selecionada com base em algum fator, como a distância e o número de pixels (área na tela) que a malha está ocupando. A outra versão dinamicamente mosaicos da malha, isso é amplamente utilizado na renderização do terreno.

insira a descrição da imagem aqui

E se tudo isso não funcionasse?

Bem, essa é uma boa pergunta.

A primeira coisa que você precisa fazer é criar um perfil do aplicativo usando um criador de perfil de gráficos e determinar onde está o gargalo. Lembre-se de que o gargalo pode mudar à medida que o conteúdo que está sendo renderizado é alterado. Os gargalos também podem fazer parte do código em execução na CPU, portanto você também precisa medir isso.

Depois disso, você precisa fazer algumas otimizações no gargalo, lembre-se de que não há resposta certa para isso e será diferente de hardware para outro.

Alguns truques comuns de otimização de GPU:

  • Evite ramificações em shaders.
  • Tente estruturas de vértices diferentes, por exemplo, {VNT}intercaladas na mesma matriz ou {V},{N},{T}em matrizes diferentes.
  • Desenhe a cena da frente para trás.
  • Desative o buffer Z em alguns pontos, por exemplo, se uma imagem não precisar de teste Z.
  • Use texturas compactadas.

Alguns truques comuns de otimização de CPU:

  • Use funções embutidas para pequenas funções.
  • Use SIMD (dados múltiplos de instrução única) quando possível.
  • Evite cache de saltos de memória hostis.
  • Use VBOs com a quantidade "correta" de dados. (dependendo do seu hardware), mas geralmente menos chamadas de empate são melhores.

Mas e se meu gargalo estivesse no sombreado adiado?

Nesse caso, como o sombreamento diferido está mais preocupado com as luzes, a parte mais óbvia é otimizar os cálculos reais do sombreamento. alguns dos pontos a serem observados:

  • Renderize luzes que realmente afetam a imagem final. Em outras palavras, abasteça as luzes que não contribuem. Isso pode ser efetivamente implementado usando a seleção de oclusão mencionada anteriormente.
  • Essa luz precisa do especular ou de alguns outros componentes? Talvez não.
  • Essa luz lança sombra? Algumas luzes não precisam projetar sombras.
  • Essa contribuição leve pode ser pré-calculada? Se não estiver em movimento, provavelmente alguns aspectos podem ser pré-calculados.
concept3d
fonte
Desculpe, eles não têm nada a ver com sombreamento diferido, eles são realmente os problemas de desempenho exatos que a técnica atenua de maneira eficaz e, portanto, as otimizações menos úteis a serem feitas, o foco deve estar no (s) passe (s) de iluminação, porque se o custo de iluminação não for o sombreamento diferido dominante e demorado é provavelmente a escolha errada.
MickLH #
@MickLH Infelizmente, aparentemente, você não leu a pergunta, o problema dele era principalmente que ele repete toda a cena toda vez, e ele não mencionou nenhum gargalo em relação ao sombreamento diferido. Mencionei a princípio que o sombreamento diferido resolve o problema de explosão de passes quando há muitas luzes / materiais. Mas, em seguida, acrescentei que essas são otimizações obrigatórias para qualquer mecanismo, independentemente da técnica de sombreamento adiante ou defferida. Considerando que essas são as questões exatas que a técnica migra, eu discordo totalmente, não posso abordar todos os pontos aqui (a seguir)
concept3d
é realmente estúpido construir um mecanismo diferido sem seleção de frustum, por exemplo, para que o mecanismo processe por exemplo (100 milhões de vértices) apenas para poder enviar o resultado ao buffer g. O sombreamento diferenciado resolve um problema diferente, o que não era problema dele, o problema era submeter toda a geometria ao pipeline.
concept3d
embora eu concorde com a parte de que alguma otimização deve ocorrer nos cálculos de iluminação e, se os cálculos de luz não forem dominantes, o diferido é o caminho errado a seguir. mas novamente isso não era problema dele.
concept3d
Retirei meu voto negativo se você deixar claro que essas otimizações são realmente as menos eficazes para um renderizador diferido, pois significa que você não mostrou a ele / ela + googlers que o problema de desempenho não tem nada a ver com sombreamento diferido.
MickLH
6

Seu problema não está relacionado ao sombreamento diferido , você precisa implementar os elementos básicos de um renderizador antes de tentar acelerar alguma parte específica.

Quando você concluir o que o concept3d explicou, se você realmente achar que precisa otimizar o sombreador diferido (em oposição a toda a passagem de rasterização), poderá implementar o sombreamento diferido baseado em bloco.

Se você não está limitado pelo número de luzes dinâmicas, deve considerar por que está usando sombreamento diferido, mas se estiver , precisará tentar a otimização que tornou possível o Battlefield 3. (Eles sugerem isso no slide 10 do PDF público: http://dice.se/wp-content/uploads/GDC11_DX11inBF3_Public.pdf )

MickLH
fonte