Há um grande número de maneiras de fazer isso. Isso exigirá o uso de um sombreador e presumo que você já esteja iluminando por pixel. A seguir estão algumas sugestões, no entanto, encontrar a técnica certa para você pode levar muito mais pesquisa.
Rapido e sujo
Você pode especificar caixas delimitadoras que definem áreas internas. Se a luz estiver fora das caixas, mas a geometria (que não está na sombra) estiver dentro da caixa, a luz deverá ter sido afetada pela passagem por uma janela (isso também é verdade se a geometria estiver fora da caixa e a luz está dentro). O único problema aqui é como passar as informações da caixa para o shader e como declarar o efeito na luz.
Outra opção é especificar janelas como objetos em planos. Primeiro teste para ver se a geometria e a luz estão em lados opostos do plano e, em seguida, se o caminho entre elas cruza o plano em um ponto dentro dos limites da janela. Isso seria mais preciso que o primeiro método e seria mais fácil ter janelas nos mesmos interiores com cores diferentes de vidro.
Continue ficando mais detalhado com a representação geométrica das janelas e você obterá resultados mais precisos, mas o cálculo também ficará mais pesado.
Essas técnicas funcionariam razoavelmente bem para um atirador de corredor, mas não tão bem para um mundo dinâmico ou aberto quanto provavelmente seriam necessários muitos ajustes para fazer com que parecesse certo sem muitos artefatos. Além disso, essas técnicas podem rapidamente se tornar um pouco intensas; portanto, é recomendável mudar para um pipeline de sombreamento diferido.
Mapas Sombra
Outra opção é fazer algo semelhante ao mapeamento de sombras.
No mapeamento de sombra, você gera uma imagem de bitmap do mundo afetado por uma luz. Cada pixel, embora ainda seja uma cor, é na verdade a distância da parte mais próxima da geometria não transparente (você usa os quatro bytes para 1 flutuação em vez de 4 cores). Se você calcular a distância da luz a um pedaço de geometria e for maior que o valor correspondente no mapa de sombras, seu pedaço de geometria estará na sombra (você geralmente usa o raio entre a geometria e a luz para indexar o mapa).
Se você aplicar essa idéia ao seu problema, o que você faria é armazenar um mapa da distância da luz da peça mais próxima da geometria transparente e também fazer um segundo mapa da cor da luz depois de passar por essa geometria ( simplesmente a cor da geometria se a luz for branca).
Se o seu pedaço de geometria estiver mais distante do que a distância neste mapa, use a cor do mapa; caso contrário, use a cor clara original.
A função para calcular a cor de cada pixel no mapa deve ser aproximadamente; lightColor - invertedWindowColor. Assim, para uma luz branca pura e uma janela vermelha pura que não absorve o espectro vermelho que temos; (255.255.255) - (0,255.255) = (255,0,0). Portanto, a cor da luz do outro lado é vermelho puro. Para um objeto transparente mais complexo, como uma janela de vitral, convém fazer uma pesquisa de textura para obter a cor do material.
Se você está procurando algo semelhante, consulte Mapas de sombras reflexivas .
Essa técnica oferece uma grande fidelidade e possivelmente seria a melhor se você desejar usar geometria transparente complexa, como vitrais.
Tentativa de uma solução geral
Recentemente, tornou-se popular codificar informações de iluminação em uma representação em voxel (elas não são apenas para geometria). O mais recente mecanismo crytek usa esse tipo de estratégia para iluminação avançada ( volumes de propagação de luz ).
Aqui está a ideia geral:
- Crie um mapa de cubos uniformemente espaçados que abranja sua cena (considere o uso de curvas de ordem z ).
- Encontre uma maneira de armazenar informações de iluminação incidente para cada voxel (as representações harmônicas esféricas são úteis aqui).
- Encontre o voxel que contém uma luz e represente essa luz no voxel.
- Propague a luz para fora através dos voxels adjacentes (como água minecraft)
- Calcule como a geometria em cada voxel afetará a luz que passa por ele (absorver, refletir, transmitir)
- repita até a luz desaparecer
Existem várias maneiras de criar essas informações de voxel, mas a lista acima fornece uma idéia geral. Por exemplo; você pode começar gerando mapas / volumes de sombra e projetando essas informações no mapa voxel para poder criar rapidamente o mapa de iluminação direta. Então você inicia a propagação a partir dos voxels ao longo da borda da área afetada. Lembre-se de que, nesse caso, você desejará ignorar se a geometria é transparente ou não ao gerar o mapa / volume de sombras.
Na passagem final de um renderizador diferido, ao calcular a iluminação de um ponto da geometria, você simplesmente usa a posição da geometria para indexar seu mapa voxel e descobrir como é a iluminação incidente naquele ponto do espaço. Em seguida, você pode criar um mapa de tela do lado da CPU com iluminação incidente ou, possivelmente, fazer isso com o cuda.