Shader simples para luzes pontuais no nevoeiro

Eu precisava de um shader simples e rápido para criar nevoeiro, iluminado por fontes pontuais de luz. Para implementá-lo, escrevi o efeito do espaço na tela, cujos resultados são mostrados abaixo. O transportador é quase tão simples quanto as fontes pontuais comuns. Não requer estruturas de volume de dados, marchas de raios e pode ser facilmente conectado a um sombreador de iluminação existente.

O princípio mais importante é que você pode calcular de forma fechada a luz que emana do nevoeiro, como se fosse iluminada por uma fonte pontual de iluminação. Minha solução foi encontrar a fórmula e sua substituição no shader.


Uma pequena cena com uma nave espacial renderizada no nevoeiro usando minha técnica

A configuração básica

Modelo de nevoeiro


O shader faz algumas suposições sobre o nevoeiro com o qual estamos trabalhando. De fato, ele considera cada fragmento do nevoeiro uma pequena superfície translúcida de dispersão branca.

  • O sombreador sugere que o nevoeiro dispersa a luz uniformemente em todas as direções. Névoa ou fumaça reais nem sempre possuem essa propriedade, mas essa é uma boa aproximação para a imagem que estamos buscando.
  • Shader sugere que todos os comprimentos de onda da luz interajam com o nevoeiro da mesma maneira. Na realidade, esse geralmente não é o caso. Por exemplo, a dispersão Rayleigh torna o céu azul, espalhando a luz azul mais do que outros comprimentos de onda.
  • A luz que emana do nevoeiro varia dependendo do quadrado inverso da distância da fonte de luz ao nevoeiro. Na realidade, isso não acontece, mas parece normal. Existem muitos recursos que explicam como a névoa realmente dispersa a iluminação e tenho certeza de que você pode complementar minha metodologia com essas fórmulas.

Não obstante. os resultados parecem plausíveis, mesmo ao usar essas simplificações.

Solução analítica


Que haja um fragmento infinitesimal de neblina (imagine um pequeno cubo de neblina). Então a luz emitida por este fragmento de neblina no meu sistema será semelhante a:

light=1(distance from light to fog fragment)2


Essa fórmula mostra que a luz proveniente de cada fragmento do nevoeiro diminui conforme o quadrado inverso de sua distância da fonte de luz, como é o caso da luz proveniente de uma superfície que difunde a luz.

Por conveniência, reescrevemos a equação:

d=distance from light to fog fragment


light=1d2


view linelight atxdx


Ou, se mais formalmente:

L=light position


w=world fragment position


c=camera position


light arriving at camera=cw1|xL|2dx



Essa integral expressa exatamente o que precisamos, mas seu cálculo é mais complicado do que precisamos. Como todas as variáveis ​​na imagem acima são vetores com três valores, precisamos essencialmente lidar com 12 variáveis. Eliminarei a maioria dessas variáveis ​​fazendo uma simples reparameterização.

Defina um novo espaço chamado " espaço da luz "

  • O eixo x é a linha de visão
  • Eixo Y para iluminação


Agora, em vez de uma integral linear no espaço tridimensional, eu simplesmente faço a integração ao longo do eixo X da câmera para um fragmento do mundo. Em seguida, precisamos reescrever a integral. Distância do pontox no eixo x para a fonte de luz é h2+x2. Portanto, a integral da linha de visão assume a forma

1h2+x2dx


Resolvendo-o manualmente ou em seu sistema de álgebra computacional favorito, obtemos:

1h2+x2dx=tan1(xh)h


Ou seja, para obter a iluminação vinda do nevoeiro para uma determinada linha de visão, eu calculo essa integral da câmera para um fragmento do mundo. Se a câmera estiver emx=ae um fragmento do mundo em x=b, a iluminação que entra no pixel a partir da neblina iluminada ao longo da linha de visão tem a forma:

ab1h2+x2dx=tan1(bh)htan1(ah)h


Reflexões sobre a implementação


Consegui implementar esse shader no meu pipeline de shader atrasado sem grandes modificações. Para fazer isso, foi necessário adicionar cerca de dez linhas de código GLSL. Se o transportador já calcula a iluminação especular difusa + com fontes pontuais de luz, o sombreador da fonte pontual já deve ter acesso à posição da câmera. a fonte de luz e o pixel atual no mundo, e é tudo o que você precisa!

O processamento de várias fontes de luz é muito simples. Basta resumir o efeito da dispersão da luz pelo nevoeiro para cada fonte. Para que o sistema seja eficaz para várias fontes, é necessário calcular a integral apenas para pixels tão próximos da fonte de luz que possa contribuir para a quantidade de luz visualmente visível na cena. Por exemplo, em um pipeline de shader atrasado, você pode renderizar uma malha esférica em torno de uma fonte de luz para que o shader calcule apenas os efeitos da luz para pixels próximos a essa fonte.

Eu descobri que a parte mais difícil de implementar esse shader é a localização correta da câmera e um fragmento do mundo no espaço de iluminação, para que possamos usar a integral simplificada.

resultados



Gere baixo nível de mundos com pouca iluminação de nevoeiro


Se houver mais fontes, o efeito se tornará mais forte


Se você também acompanhar as informações sobre a direção das fontes de luz, poderá criar uma bela iluminação figurada no meio do nevoeiro.

Leitura adicional


Introdução à dispersão de luz: uma perspectiva das ciências da imagem

Um modelo prático de dispersão analítica para renderização em tempo real

Algoritmo de dispersão atmosférica e volumétrico de nevoeiro parte 1

All Articles