Técnicas comuns para melhorar os mapas de profundidade de sombra
Os mapas de sombras, introduzidos pela primeira vez em 1978, são uma técnica comum para adicionar sombras aos jogos. Três décadas depois, apesar dos avanços em hardware e software, os artefatos de sombreamento - ou seja, bordas cintilantes, aliasing de perspectiva e outros problemas de precisão - persistem.
Este artigo técnico fornece uma visão geral de alguns algoritmos comuns de mapa de profundidade de sombra e artefatos comuns e explica várias técnicas - variando em dificuldade de básica a intermediária - que podem ser usadas para aumentar a qualidade dos mapas de sombra padrão. Adicionar mapas de sombra básicos a um título normalmente é simples, mas entender as nuances dos artefatos de sombra pode ser um desafio. Este artigo técnico foi escrito para o desenvolvedor gráfico intermediário que implementou sombras, mas não entende completamente por que artefatos específicos aparecem e não tem certeza de como contorná-los.
Selecionar as técnicas corretas para mitigar artefatos específicos não é trivial. Quando as deficiências do mapa de sombra são abordadas, a diferença de qualidade pode ser impressionante (Figura 1). A implementação correta dessas técnicas melhora drasticamente as sombras padrão. As técnicas explicadas neste artigo são implementadas no exemplo CascadedShadowMaps11 no SDK do DirectX.
Figura 1. Sombras com artefatos graves (à esquerda) e sombras após a implementação das técnicas descritas neste artigo (à direita)
Revisão de mapas de profundidade de sombra
O algoritmo do mapa de profundidade de sombra é um algoritmo de duas passagens. A primeira passagem gera um mapa de profundidade no espaço de luz. Na segunda passagem, esse mapa é usado para comparar a profundidade de cada pixel no espaço de luz com sua profundidade correspondente no mapa de profundidade do espaço de luz.
Figura 2. Partes principais de uma cena de sombra
Passe 1
A cena é mostrada na Figura 2. Na primeira passagem (Figura 3), a geometria é renderizada em um buffer de profundidade do ponto de vista da luz. Mais especificamente, o sombreador de vértice transforma a geometria em espaço de exibição de luz.
O resultado final dessa primeira passagem é um buffer de profundidade contendo as informações de profundidade da cena do ponto de vista da luz. Isso agora pode ser usado na passagem 2 para determinar quais pixels estão ocluídos da luz.
Figura 3. Primeira passagem do mapeamento de sombra básico
Passe 2
Na segunda passagem (Figura 4), o sombreador de vértice transforma cada vértice duas vezes. Cada vértice é transformado no espaço de exibição da câmera e passado para o sombreador de pixel como a posição. Cada vértice também é transformado pela matriz de exibição-projeção-textura da luz e passado para o sombreador de pixel como uma coordenada de textura. A matriz view-projection-texture é a mesma matriz usada para renderizar a cena na passagem 1 com uma transformação adicional. É uma transformação que dimensiona e traduz os pontos do espaço de exibição (–1 a 1 em X e Y) para o espaço de textura (0 a 1 em X e 1 a 0 em Y).
O sombreador de pixel recebe a posição interpolada e as coordenadas de textura interpoladas. Tudo o que é necessário para realizar o teste de profundidade agora está nesta coordenada de textura. O teste de profundidade agora pode ser executado indexando o buffer de profundidade da primeira passagem com as coordenadas de textura X e Y e comparando o valor de profundidade resultante com a coordenada de textura Z.
Figura 4. Segunda passagem do mapeamento de sombra básico
Artefatos do Mapa das Sombras
O algoritmo de mapa de profundidade de sombra é o algoritmo de sombreamento em tempo real mais amplamente usado, mas ainda produz vários artefatos que requerem mitigação. Os tipos de artefatos que podem ocorrer são resumidos a seguir.
Aliasing de perspectiva
O aliasing de perspectiva, um artefato comum, é mostrado na Figura 5. Ele ocorre quando o mapeamento de pixels no espaço de exibição para texels no mapa de sombra não é uma proporção de um para um. Isso ocorre porque os pixels próximos ao plano próximo estão mais próximos e exigem uma resolução de mapa de sombra mais alta.
A Figura 6 mostra um mapa de sombras e um tronco de exibição. Perto do olho, os pixels estão mais próximos e muitos pixels são mapeados para os mesmos texels de sombra. Os pixels do plano distante são espalhados, reduzindo assim o aliasing de perspectiva.
Figura 5. Aliasing de alta perspectiva (esquerda) vs. aliasing de baixa perspectiva (direita)
Para a imagem à esquerda, o aliasing de perspectiva é maior; Muitos pixels de espaço de olho são mapeados para os mesmos texels de mapa de sombra. Na imagem à direita, o aliasing de perspectiva é baixo porque há um mapeamento 1:1 entre os pixels do espaço do olho e os texels do mapa de sombra.
Figura 6. Visualize o tronco com mapa de sombras
Os pixels claros no plano distante representam o aliasing de baixa perspectiva e os pixels escuros no plano próximo representam o aliasing de alta perspectiva.
A resolução do mapa de sombras também pode ser muito alta. Embora uma resolução mais alta seja menos perceptível, ela pode resultar em pequenos objetos, como fios telefônicos, que não projetam sombras. Além disso, ter uma resolução muito alta pode causar sérios problemas de desempenho devido aos padrões de acesso à textura.
Os mapas de sombra de perspectiva (PSMs) e os mapas de sombra de perspectiva de espaço de luz (LSPSMs) tentam abordar o aliasing de perspectiva distorcendo a matriz de projeção da luz para colocar mais texels perto do olho onde eles são necessários. Infelizmente, nenhuma das técnicas é capaz de resolver o aliasing de perspectiva. A parametrização da transformação necessária para mapear pixels de espaço ocular para texels no mapa de sombra não pode ser associada por uma distorção linear. É necessária uma parametrização logarítmica. Os PSMs colocam muitos detalhes perto do olho, fazendo com que as sombras distantes sejam de baixa qualidade ou até desapareçam. Os LSPSMs fazem um trabalho melhor em encontrar um meio-termo entre aumentar a resolução perto do olho e deixar detalhes suficientes para objetos distantes. Ambas as técnicas degeneram em sombras ortogonais em algumas configurações de cena. Essa degeneração pode ser neutralizada renderizando um mapa de sombra separado para cada face do tronco da vista, embora isso seja caro. Os mapas de sombra de perspectiva logarítmica (LogPSMs) também renderizam um mapa separado por face do tronco de exibição. Essa técnica usa rasterização não linear para colocar mais texels perto do olho. O hardware das classes D3D10 e D3D11 não dá suporte à rasterização não linear. Para obter mais informações sobre essas técnicas e algoritmos, consulte a seção Referências.
Os mapas de sombra em cascata (CSMs) são a técnica mais popular para lidar com o aliasing de perspectiva. Embora os CSMs possam ser combinados com PSMs e LSPSMs, isso é desnecessário. O uso de CSMs para corrigir erros de aliasing de perspectiva é abordado no artigo complementar, Mapas de sombra em cascata.
Aliasing projetivo
O aliasing projetivo é mais difícil de mostrar do que o aliasing de perspectiva. As sombras distendidas destacadas na Figura 7 demonstram erros de aliasing projetivo. O aliasing projetivo ocorre quando o mapeamento entre texels no espaço da câmera para texels no espaço de luz não é uma proporção de um para um; Isso ocorre devido à orientação da geometria em relação à câmera de luz. O aliasing projetivo ocorre quando o plano tangente da geometria se torna paralelo aos raios de luz.
Figura 7. Aliss de alta projeção vs. aliasing de baixa projeção
As técnicas usadas para aliviar erros de aliasing de perspectiva também atenuam o aliasing projetivo. O aliasing projetivo ocorre quando a normal da superfície é ortogonal à luz; Essas superfícies devem receber menos luz com base em equações de iluminação difusa.
Acne de sombra e auto-sombreamento errôneo
A acne de sombra (Figura 8), um termo sinônimo de auto-sombreamento errôneo, ocorre quando o mapa de sombra quantifica a profundidade em um texel inteiro. Quando o sombreador compara uma profundidade real com esse valor, é tão provável que ele seja sombreado automaticamente quanto não sombreado.
Outro motivo para a acne de sombra é que o texel no espaço de luz está tão próximo da profundidade do texel correspondente no mapa de profundidade que erros de precisão fazem com que o teste de profundidade falhe erroneamente. Um motivo para essa diferença de precisão é que o mapa de profundidade foi calculado pelo hardware de rasterização de função fixa, enquanto a profundidade que está sendo comparada foi calculada pelo sombreador. O aliasing projetivo também pode causar acne de sombra.
Figura 8. Artefato de acne de sombra
Como mostrado na imagem à esquerda, alguns dos pixels falharam no teste de profundidade e criaram artefatos salpicados e padrões moiré. Para reduzir o auto-sombreamento errôneo, os limites no plano próximo e no plano distante para o tronco de visão do espaço de luz devem ser calculados o mais firmemente possível. O viés de profundidade baseado em escala de inclinação e outros tipos de viés são outras soluções usadas para mitigar a acne das sombras.
Peter Panning
O termo Peter Panning deriva seu nome de um personagem de livro infantil cuja sombra se desprendeu e que podia voar. Esse artefato faz com que objetos com sombras ausentes pareçam estar destacados e flutuar acima da superfície (Figura 9).
Figura 9. Artefato Peter Panning
Na imagem à esquerda, a sombra é destacada do objeto, criando um efeito flutuante.
Uma técnica para remover a acne superficial é agregar algum valor à posição do pixel no espaço da luz; Isso é chamado de adicionar um deslocamento de profundidade. Peter Panning ocorre quando o deslocamento de profundidade usado é muito grande. Nesse caso, o deslocamento de profundidade faz com que o teste de profundidade seja aprovado erroneamente. Como a acne das sombras, Peter Panning é agravado quando não há precisão suficiente no buffer de profundidade. Calcular planos próximos e planos distantes também ajuda a evitar Peter Panning.
Técnicas para melhorar os mapas de sombra
Adicionar sombras a um título é um processo. O primeiro passo é fazer com que os mapas de sombras básicos funcionem. A segunda é garantir que todos os cálculos básicos sejam feitos de maneira ideal: frusta se encaixa o mais firmemente possível, planos próximos/distantes se encaixam perfeitamente, viés em escala de inclinação é usado e assim por diante. Depois que as sombras básicas são ativadas e têm a melhor aparência possível, o desenvolvedor tem uma ideia melhor de quais algoritmos são necessários para obter fidelidade suficiente das sombras. Dicas básicas que podem ser necessárias para obter mapas de sombras básicos com a melhor aparência possível são fornecidas nesta seção.
Inclinação
Como mencionado anteriormente, o auto-sombreamento pode levar à acne da sombra. Adicionar muito viés pode resultar em Peter Panning. Além disso, polígonos com declives acentuados (em relação à luz) sofrem mais com o aliasing projetivo do que polígonos com declives rasos (em relação à luz). Por causa disso, cada valor do mapa de profundidade pode precisar de um deslocamento diferente, dependendo da inclinação do polígono em relação à luz.
O hardware do Direct3D 10 tem a capacidade de direcionar um polígono com base em sua inclinação em relação à direção da exibição. Isso tem o efeito de aplicar um desvio grande a um polígono que é visto de lado na direção da luz, mas não aplicar nenhum desvio a um polígono voltado diretamente para a luz. A Figura 10 ilustra como dois pixels vizinhos podem alternar entre sombreado e não sombreado ao testar a mesma inclinação não enviesada.
Figura 10. Inclinação dimensionada
Calculando uma projeção apertada
Ajustar firmemente a projeção da luz ao tronco de visualização aumenta a cobertura do mapa de sombras. A Figura 11 ilustra que o uso de uma projeção arbitrária ou o ajuste da projeção aos limites da cena resulta em um aliasing de perspectiva mais alto.
Figura 11. Tronco de sombra arbitrário e tronco de sombra adequados à cena
A visão é do ponto de vista da luz. O trapézio representa o tronco da câmera de visualização. A grade desenhada sobre a imagem representa o mapa de sombra. A imagem à direita mostra que o mesmo mapa de sombra de resolução cria mais cobertura de texel quando ele se ajusta mais firmemente à cena.
A Figura 12 ilustra os troncos que estão corretamente ajustados. Para calcular a projeção, os oito pontos que compõem o tronco da vista são transformados em espaço de luz. Em seguida, os valores mínimo e máximo em X e Y são encontrados. Esses valores compõem os limites de uma projeção ortográfica.
Figura 12. Projeção de sombra ajustada para visualizar tronco
Também é possível cortar o tronco na cena AABB para obter um limite mais apertado. Isso não é recomendado em todos os casos, pois pode alterar o tamanho da projeção da câmera de luz de quadro para quadro. Muitas técnicas, como as descritas na seção Movendo os incrementos de tamanho de texel de luz, fornecem melhores resultados quando o tamanho da projeção da luz permanece constante em cada quadro.
Calculando o plano próximo e o plano distante
O plano próximo e o plano distante são as peças finais necessárias para calcular a matriz de projeção. Quanto mais próximos os planos estiverem, mais precisos serão os valores no buffer de profundidade.
O buffer de profundidade pode ser de 16 bits, 24 bits ou 32 bits, com valores entre 0 e 1. Geralmente, os buffers de profundidade são de ponto fixo, com os valores próximos ao plano próximo agrupados mais próximos do que os valores próximos ao plano distante. O grau de precisão disponível para o buffer de profundidade é determinado pela razão entre o plano próximo e o plano distante. Usar o plano próximo/distante mais apertado possível pode permitir o uso de um buffer de profundidade de 16 bits. Um buffer de profundidade de 16 bits pode reduzir o uso de memória e aumentar a velocidade de processamento.
Plano próximo e plano distante baseados em AABB
Uma maneira fácil e ingênua de calcular o plano próximo e o plano distante é transformar o volume delimitador da cena em espaço de luz. O menor valor da coordenada Z é o plano próximo e o maior valor da coordenada Z é o plano distante. Para muitas configurações da cena e da luz, essa abordagem é suficiente. O pior cenário, no entanto, pode resultar em uma perda significativa de precisão no buffer de profundidade; A Figura 13 mostra esse cenário. Aqui, o alcance do plano próximo ao plano distante é quatro vezes maior do que o necessário.
O tronco de visão na Figura 13 foi propositadamente escolhido para ser pequeno. Um pequeno tronco de visão é mostrado em uma cena muito grande que consiste em pilares que se estendem para fora da câmera de visão. Usar o Scene AABB para os planos próximos e distantes não é o ideal. O algoritmo CSM descrito no artigo técnico Cascaded Shadow Maps deve calcular planos próximos e distantes para troncos muito pequenos.
Figura 13. Planos próximos e distantes baseados no Scene AABB
Plano próximo e plano distante baseados em tronco
Outra técnica para calcular os planos próximo e distante é transformar o tronco em espaço claro e usar os valores mínimo e máximo em Z como os planos próximo e distante, respectivamente. A Figura 14 ilustra os dois problemas com essa abordagem. Primeiro, o cálculo é muito conservador, como mostrado quando o tronco se estende além da geometria da cena. Em segundo lugar, o plano próximo pode ser muito apertado, fazendo com que os lançadores de sombras sejam cortados.
Figura 14. Planos próximos e distantes baseados apenas no tronco de visualização
Tronco de luz interceptado com a cena para calcular planos próximos e distantes
A maneira correta de calcular os planos próximos e distantes é mostrada na Figura 15. Quatro dos planos do tronco de luz ortogonal foram calculados usando o mínimo e o máximo das coordenadas X e Y do tronco de visão no espaço de luz. Os dois últimos planos do tronco da vista ortogonal são os planos próximo e distante. Para encontrar esses planos, os limites da cena são cortados contra os quatro planos de tronco de luz conhecidos. Os menores e maiores valores Z do limite recém-recortado representam o plano próximo e o plano distante, respectivamente.
O código que executa essa operação está localizado no exemplo CascadedShadowMaps11. Os oito pontos que compõem o AABB do mundo são transformados em espaço de luz. Transformar os pontos em espaço de luz simplifica os testes de recorte. Os quatro planos conhecidos do tronco de luz agora podem ser representados como linhas. As cenas que delimitam o volume no espaço de luz podem ser representadas como seis quadriláteros. Esses 6 quadriláteros podem então ser transformados em 12 triângulos para recorte baseado em triângulo. Os triângulos são recortados contra os planos conhecidos do tronco da vista (estas são linhas horizontais e verticais em X e Y no espaço claro). Quando um ponto de interseção é encontrado em X e Y, o triângulo 3D é recortado nesse ponto. Os valores Z mínimo e máximo de todos os triângulos recortados são o plano próximo e o plano distante. O exemplo CascadedShadowMaps11 mostra como executar esse recorte na função ComputeNearAndFar .
Existem mais duas técnicas que podem ser usadas para calcular os planos próximos e distantes mais apertados possíveis. Essas técnicas não são mostradas no exemplo CascadedShadowMaps.
Planos próximos e distantes ainda mais estreitos podem ser calculados cruzando uma hierarquia de uma cena ou objetos individuais em uma cena contra o tronco de luz. Isso seria computacionalmente mais complexo. Embora não seja ilustrado no exemplo CascadedShadowMaps11, essa pode ser uma técnica válida para alguns blocos.
O plano distante pode ser calculado tomando o mínimo de:
- A maior profundidade do tronco de visão no espaço claro.
- A maior profundidade da interseção do tronco de visão e da cena AABB.
Essa abordagem pode ser problemática quando usada com mapas de sombra em cascata, onde é possível indexar fora de um tronco de exibição. Nesse caso, o mapa de sombra pode estar faltando geometria.
Figura 15. Planos próximos e distantes com base na interseção dos quatro planos calculados do tronco de luz e na geometria delimitadora da cena
Movendo a luz em incrementos de tamanho texel
Um artefato comum em mapas de sombra é o efeito de borda cintilante. À medida que a câmera se move, os pixels ao longo das bordas das sombras ficam mais claros e escurecem. Isso não pode ser visto em imagens estáticas, mas é muito perceptível e distrai em tempo real. A Figura 16 destaca esse problema e a Figura 17 mostra como as bordas de sombra devem ficar.
O erro de borda cintilante ocorre porque a matriz de projeção de luz está sendo recalculada toda vez que a câmera se move. Isso cria diferenças sutis nos mapas de sombra gerados. Todos os fatores a seguir podem influenciar a matriz criada para delimitar a cena.
- Tamanho do tronco da vista
- Orientação do tronco de visualização
- Localização da luz
- Localização da câmera
Toda vez que essa matriz muda, as bordas das sombras podem mudar.
Figura 16. Bordas de sombra cintilantes
Os pixels ao longo da borda da sombra entram e saem da sombra à medida que a câmera se move da esquerda para a direita.
Figura 17. Sombras sem bordas cintilantes
As bordas das sombras permanecem constantes à medida que a câmera se move da esquerda para a direita.
Para luzes direcionais, a solução para esse problema é arredondar o valor mínimo/máximo em X e Y (que compõem os limites de projeção ortográfica) para incrementos de tamanho de pixel. Isso pode ser feito com uma operação de divisão, uma operação de piso e uma multiplicação.
vLightCameraOrthographicMin /= vWorldUnitsPerTexel;
vLightCameraOrthographicMin = XMVectorFloor( vLightCameraOrthographicMin );
vLightCameraOrthographicMin *= vWorldUnitsPerTexel;
vLightCameraOrthographicMax /= vWorldUnitsPerTexel;
vLightCameraOrthographicMax = XMVectorFloor( vLightCameraOrthographicMax );
vLightCameraOrthographicMax *= vWorldUnitsPerTexel;
O valor vWorldUnitsPerTexel é calculado usando um limite do tronco de exibição e dividindo pelo tamanho do buffer.
FLOAT fWorldUnitsPerTexel = fCascadeBound /
(float)m_CopyOfCascadeConfig.m_iBufferSize;
vWorldUnitsPerTexel = XMVectorSet( fWorldUnitsPerTexel, fWorldUnitsPerTexel, 0.0f, 0.0f );
Delimitar o tamanho máximo do tronco da vista resulta em um ajuste mais flexível para a projeção ortogonal.
É importante observar que a textura é 1 pixel maior em largura e altura ao usar esta técnica. Isso impede que as coordenadas de sombra sejam indexadas fora do mapa de sombra.
Face traseira e face frontal
Os mapas de sombra devem ser renderizados com o abate de back-face padrão, um processo que ignora a rasterização de objetos que o visualizador não pode ver e acelera a renderização da cena. Outra opção comum é renderizar mapas de sombra com o abate frontal ativado, o que significa que os objetos voltados para o visualizador são eliminados. O argumento para isso é que ajuda no auto-sombreamento, pois a geometria que compõe a parte de trás dos objetos é ligeiramente deslocada. Existem dois problemas com essa ideia.
- Qualquer objeto com geometria inadequada da face frontal ou traseira causa artefatos no mapa de sombra. No entanto, ter uma geometria incorreta da face frontal ou traseira causará outros problemas, portanto, pode ser seguro assumir que a geometria da face frontal e traseira é feita corretamente. Pode ser impraticável criar faces posteriores para geometria baseada em sprite, como folhagem.
- Peter Panning e lacunas de sombra perto da base de objetos, como paredes, são mais prováveis de ocorrer porque a disparidade de profundidade de sombra é muito pequena.
Geometria amigável ao mapa de sombras
Criar uma geometria que funcione bem em mapas de sombras permite mais flexibilidade ao combater artefatos como Peter Panning e acne de sombra.
Bordas duras são problemáticas para o auto-sombreamento. A disparidade de profundidade perto da ponta da borda é muito pequena. Mesmo um pequeno deslocamento pode fazer com que os objetos percam suas sombras (Figura 18).
Figura 18. Bordas afiadas causam artefatos decorrentes de disparidade de baixa profundidade com deslocamentos
Objetos estreitos, como paredes, devem ter costas, mesmo que nunca sejam visíveis. Isso aumentará a disparidade de profundidade.
Também é importante certificar-se de que a direção para a qual a geometria está voltada esteja correta; ou seja, a parte externa de um objeto deve estar voltada para trás e a parte interna de um objeto deve estar voltada para a frente. Isso é importante para renderizar com o abate de face traseira habilitado, bem como para combater os efeitos do viés de profundidade.
Mapas de sombra em cascata
Consulte também Mapas de sombra em cascata e o aplicativo de exemplo CascadedShadowMaps11. O exemplo demonstra o algoritmo CSM (mapa de sombra em cascata), bem como várias técnicas que podem ser usadas para fazer uso eficiente do mapa de sombra.
Você pode encontrar o exemplo no SDK (Software Development Kit) do DirectX. Ou você pode realizar uma pesquisa na web para encontrá-lo no GitHub.
Resumo
As técnicas descritas neste artigo podem ser usadas para aumentar a qualidade dos mapas de sombra padrão. O próximo passo é examinar as técnicas que podem funcionar bem com mapas de sombra padrão. Os CSMs são recomendados como uma técnica superior para combater o aliasing de perspectiva. A filtragem de porcentagem mais próxima ou os mapas de sombra de variância podem ser usados para suavizar as bordas de sombra. Consulte o artigo técnico Mapas de sombra em cascata para obter mais informações.
Donnelly, W., e Lauritzen, A. Mapas de Sombra de Variância. Simpósio de Gráficos 3D Interativos, Anais do Simpósio de 2006 sobre Gráficos e Jogos 3D Interativos. 2006, pp. 161–165.
Engel, Woflgang F. Seção 4. Mapas de Sombras em Cascata. ShaderX5, Técnicas Avançadas de Renderização, Wolfgang F. Engel, Ed. Charles River Media, Boston, Massachusetts. 2006. pp. 197–206.
Stamminger, Marc e Drettakis, George. Mapas de sombra em perspectiva. Conferência Internacional sobre Computação Gráfica e Técnicas Interativas, Anais da 29ª Conferência Anual sobre Computação Gráfica e Técnicas Interativas. 2002, pp 557–562.
Wimmer, M., Scherzer, D. e Purgathofer, W. Mapas de sombra de perspectiva de espaço de luz. Simpósio Eurographics de Renderização. 2004. Revisado em 10 de junho de 2005. Technische Universität Wien.