Renderização eficiente com muitas fontes de luz

10

Para renderizar uma cena com uma única fonte de luz usando sombreamento phong, é possível calcular a cor final de cada fragmento passado no sombreador de fragmentos com base nos componentes ambiente / difuso / especular do material e da fonte de luz.

Isso pode ser facilmente estendido para acomodar várias fontes de luz, adicionando os resultados da aplicação de cada fonte de luz individual ao fragmento, como tal:

final_color = (0, 0, 0, 1)
for each light:
    final_color += apply_light(material, light)
final_color = clamp(final_color, (0,0,0,1), (1,1,1,1))

No entanto, com um número muito grande de fontes de luz, esse processo é bastante lento; com Nluzes, essa abordagem requer cálculos para que o sombreamento phong seja feito Nvezes por fragmento.

Existe uma abordagem melhor para renderizar cenas com um número muito grande de fontes de luz (centenas, milhares, etc.)?

es1024
fonte

Respostas:

15

Sim, mas você precisa de uma mudança de paradigma.

O que você está acostumado é chamado de renderização direta. Você envia sua geometria e prossegue imediatamente com o passe de sombreamento. Na renderização básica básica, você pode fazer um loop dentro do shader para cada luz ou executar um passe por luz e misturar o resultado (com mistura aditiva).

Mas as coisas evoluíram bastante. Entra: renderização adiada

Agora que existem tantas variantes que as descrevem em detalhes, será muito mais do que aceitável para uma resposta aqui. Então, aqui vou descrever a essência do sombreamento adiado. Existem muitos outros recursos que você pode encontrar facilmente usando o google. Espero que, depois de ler isso, você tenha as palavras-chave certas para encontrar o que precisa.

A idéia básica é adiar o sombreamento para depois do pipeline. Você tem duas etapas principais:

  1. Renderize sua geometria e todas as informações necessárias para sombreamento em vários destinos de renderização. Isso significa que, tipicamente em uma implementação básica, você teria um buffer de profundidade, um buffer contendo as normais da sua geometria e a cor do albedo. Você logo descobrirá que precisa de outras informações sobre os materiais (por exemplo, rugosidade, fator "metálico" etc.).

Esta imagem da wikipedia mostra três buffer (cores, profundidade e normais)

insira a descrição da imagem aqui

Novamente, a quantidade, o tipo e o conteúdo dos buffers usados ​​variam bastante entre os diferentes projetos. Você encontrará o conjunto de buffers com o nome de GBuffers.

  1. Após este é o momento de aplicar a iluminação real. Durante o passe de iluminação para cada luz, você deseja desenhar um volume de luz que depende do tipo de luz:
    • Para uma luz direcional, você renderiza um quad em tela cheia.
    • Para uma luz pontual, você renderiza uma esfera em que o raio se baseia na atenuação da luz pontual.
    • Para uma luz spot, você renderiza um cone cujas dimensões dependem novamente das características da sua luz.

No sombreador de pixels deste passe, você passa seus GBuffers e executa sua iluminação e sombreamento usando as informações neles. Dessa forma, você processa apenas os pixels afetados por cada uma das luzes com uma velocidade sensata se comparada à renderização direta clássica.

Ele também tem várias desvantagens, principalmente o manuseio de objetos transparentes e maior consumo de largura de banda e memória de vídeo. Mas também é mais complicado lidar com vários modelos de materiais.

Você tem outras vantagens colaterais (como ter muitas informações prontas para o pós-processamento) e também é muito fácil de implementar. Mas isso não é a coisa mais legal por aí para muitas luzes.

As técnicas mais recentes são, por exemplo, as de renderização lado a lado. A idéia principal é subdividir a cena no espaço da tela "tiles" e atribuir a cada tile as luzes que o afetam. Isso existe tanto de maneira adiada quanto para a frente. Essas técnicas levam a alguns problemas quando você tem várias descontinuidades de profundidade em um bloco, mas geralmente é mais rápido que o clássico adiado e resolve vários problemas dele. Por exemplo, entre as vantagens, com diferido em mosaico, você lê os GBuffers uma vez por fragmento aceso e os pixels no mesmo mosaico processam coerentemente as mesmas luzes.

Uma evolução adicional desse lado é o sombreamento em cluster, que é conceitualmente semelhante às abordagens baseadas em ladrilhos, tendo, em vez de blocos de espaço na tela, clusters com uma extensão 3D Esse método lida melhor com o problema das descontinuidades de profundidade e geralmente tem um desempenho melhor do que os métodos lado a lado.

NOTA IMPORTANTE: Descrevi o básico do sombreamento adiado. Existem várias variações, otimizações e melhorias, então peço que você experimente uma versão simples e faça algumas pesquisas sobre outras técnicas, como a que mencionei acima.

cifz
fonte
1
Aqui estão dois recursos de código fonte para Azulejo e Cluster
RichieSams