Sombreamento diferido - como combinar várias luzes?

9

Estou começando com o GLSL e implementei sombreamento diferido simples que gera buffer G com posições, normais e albedo.

Também escrevi um sombreador de luz pontual simples.

Agora eu desenho uma esfera para o ponto de luz e a saída entra em um buffer de iluminação.

O problema é: como combinar os resultados do buffer de iluminação ao desenhar várias luzes?

Por exemplo, quando estou desenhando a segunda luz no buffer de luz usando o shader de luz pontual, como adiciono a primeira luz à segunda luz no buffer de iluminação. Quero dizer, você não pode ler e escrever no mesmo buffer de saída?

JBeurer
fonte

Respostas:

12

Mistura aditiva, ou seja, glBlendFunc (GL_ONE, GL_ONE) e glEnable (GL_BLEND).

Nathan Reed
fonte
o teste de profundidade precisa ser desativado para isso?
Woojoo666 26/05
11
@ woojoo666 Não. Na verdade, ele deve ser ativado com o teste de profundidade definido como menor, para que as superfícies que correspondam exatamente à passagem anterior sejam aprovadas. Se o teste de profundidade estiver desativado, as superfícies acumularão incorretamente luz do que estiver atrás deles. :)
Nathan Reed
hmm, parece que é exatamente o que está acontecendo. ativar a mistura faz com que as faces frontais se misturem às faces traseiras, mesmo que eu tenha mantido o teste de profundidade ativado. preciso fazer algo com a máscara de profundidade também?
Woojoo666 28/05
fez um pouco mais de teste, parece que a ordem do desenho é importante (desenhar frente-para-trás faz com que o teste de profundidade funcione corretamente e a mistura só acontece se as faces são equiplanares, a frente-para-trás faz tudo se misturar). Existe uma maneira de fazer isso sem classificar tudo?
Woojoo666 28/05
2
@ woojoo666 Aha, parece que você resolveu sozinho. Sim, você deve aplicar profundidade em um passe opaco antes de poder usar qualquer tipo de mistura. Pode ser um pré-z com as gravações coloridas desativadas ou outra maneira comum é fazer a luz ambiente / direcional em uma primeira passagem sem mistura e, em seguida, adicionar luzes de ponto / ponto nas passagens posteriores com a mistura.
Nathan Reed
2

Para o meu renderizador diferido, agrego todas as luzes em um alvo de renderização de luz usando as informações do buffer g e, em seguida, mostro a amostra que renderiza o alvo para a intensidade da luz enquanto cria minha imagem final de backbuffer.

Então, basicamente, eu corro toda a minha geometria do jogo através do meu passe de geometria para criar os g-buffers. A partir daí, alimento os buffers G ao meu shader de passagem de luz. Cada luz é percorrida no passe usando um quad em tela cheia. Dessa forma, meu pixel shader pode calcular a intensidade da luz para todas as superfícies visíveis do buffer g e adicioná-las ao alvo de renderização da luz. Você simplesmente adiciona a intensidade da luz de cada luz ao buffer de luz, mas certifique-se de fixar a intensidade de 0 a 1.

Tudo o que você precisa fazer para lidar com diferentes tipos de luzes (ponto, foco, paralelo) é tornar a luz mais robusta, possivelmente usando um buffer constante para designar quais procedimentos de iluminação executar.

KlashnikovKid
fonte
Sim, e a pergunta é: como você adiciona ao alvo de renderização da luz? Usando a mistura alfa como sugerido por Nathan Reed? Porque, tanto quanto eu sei, você não pode ler e escrever no mesmo buffer de saída (que é o buffer leve neste caso).
JBeurer
Opa, sim. Deixei a fusão de saída lidar com isso com a mistura aditiva. Quando amostrar para a imagem final é quando você deseja fixar o valor em um valor que funcione para mim como a máxima intensidade de luz possível que uma superfície pode receber. A partir daí, você pode escalar suas luzes conforme necessário.
KlashnikovKid
Como você lida com casos em que há luz atrás de uma parede e não deve acender coisas do outro lado da parede?
Jjxtra # 11/13
@ PsychoDad Esse é o domínio das sombras, que é ... um tópico mais complicado. :)
Nathan Reed
0

Provavelmente, existe uma resposta melhor do que essa, mas eu sei que, se no seu sombreador você repetir o código necessário para fazer uma segunda luz, poderá processar duas luzes em um único objeto em vez de um. Exige muito código para a segunda luz e parece um pouco redundante, mas sei que funciona. No entanto, acredito que, como alguém espera apontar para você, pode haver uma solução mais elegante.

CodeNeko
fonte
Não, isso não funciona dessa maneira. Eu desenho uma esfera para cada ponto de luz. A menos que a luz do segundo ponto esteja dentro da esfera de influência da primeira luz, a segunda luz simplesmente não será atraída. Seu método funcionaria se eu desenhar um quadrilátero em tela cheia para todos os focos, no entanto, essa não é a abordagem correta, porque quadriláteros em tela cheia são usados ​​para iluminação global. Digamos que eu tenha 16 pequenas luzes pontuais, o que me forçaria a examiná-las para cada pixel, mesmo que o pixel não seja iluminado por ele. E geralmente eu diria que cada pixel é iluminado por uma ou duas luzes. E se eu tiver 100 luzes? NO
JBeurer 12/12/12
A principal razão pela qual afirmei isso é que, se você estiver usando apenas duas ou algumas luzes, isso pode ajudar. Especialmente se você estiver renderizando muitos objetos, usar uma mistura significa que você precisa redesenhar a cena para cada luz; portanto, se você tiver muitas formas, digamos um milhão ou dez milhões ou bilhão, cada sorteio custará muito mais . Fazer isso no shader causa problemas se você deseja muitas luzes, mas a mistura causa problemas se você deseja muitas formas. Se você tiver muitos dos dois, precisará encontrar um meio termo, mas geralmente você tem algumas luzes e muitos objetos nos jogos.
CodeNeko
Não, o sombreamento adiado não funciona dessa maneira. Eu tenho que desenhar a cena apenas uma vez e armazenar informações relevantes no G-Buffer. Em seguida, uma esfera de influência para cada luz e misture-a com o buffer de luz. E, finalmente, combinando o buffer leve com o buffer de cores, recebo o buffer de cores sombreado final. A quantidade de cálculos de iluminação não depende da complexidade da cena. Essa é a principal vantagem do sombreamento diferido em primeiro lugar.
JBeurer
Ah, isso faz muito mais sentido e seria consideravelmente melhor.
CodeNeko