Traçado de Raio (Ray Tracing)
Wallace Loos
DCA - FEEC - UNICAMP
Este é um trabalho sobre Traçado de Raio desenvolvido para a disciplina IA725 (Computação Gráfica) ministrada pela Profa. Wu, Shin-Ting no 1o semestre de 2011.

Conteúdo
1. Traçado de raio básico
voltarNa computação gráfica, a iluminação global é o termo dado para modelos que renderizam a visão de uma cena calculando a luz refletida, ou seja, não considera se somente a luz vindo diretamente da fonte, mas também aquelas que chegam indiretamente. Modelos de iluminação global estão relacionados ao realismo das cenas geradas sinteticamente. Dois algoritmos de iluminação global (parcial) são propostos, traçado de raio e radiosidade. A ideia do traçado de raio é a de traçar raios na cena, e para cada objeto em que o raio intercepte, seja calculada a intersecção, e para cada ponto interceptado seja gerado um raio refletido e outro refratado, dependendo da propriedade do material. Essa ideia simula como os raios luminosos viajam no ambiente.

A Fig. 1 mostra um raio que é lançado do observador. O raio intercepta uma superfície transparente gerando dois novos raios R1 e T1, que são respectivamente o raio refletido e o raio transmitido ou refratado. Da superfície é lançado um raio S2 chamado de raio de sombra, esse raio veri.fica a existência de sombra. A cada ponto atingido os mesmo cálculos são realizados, isso nos leva a uma simples implementação recursiva. O processo geralmente é visualizado como uma árvore onde cada nó é um ponto atingido da superfície. A recursão pode terminar de acordo com o núumero de critérios
- Termina quando intercepta uma superfície difusa.
- Termina quando atinge uma certa profundidade.
- Termina quando a energia do raio ficar abaixo de um limiar pré-denido.

1.1 Impacto do nível de profundidade
voltarPara ilustrar o impacto do nível de profundidade da árvore da Fig. 2 na geração das imagens, utilizamos o software POV-Ray (vide próxima seção) e geramos duas cenas variando este parâmetro. O objetivo é comparar tanto a qualidade da imagem quanto o tempo de processamento em função da profundidade. Uma das cenas escolhidas era mais complexa (mais elementos, texturas etc.), e a outra mais simples.
As imagens geradas para a cena mais simples variando a profundidade do traçado são mostradas na Fig. 3. Foram utilizados os níveis 2, 4, 6, 8, 10 e 16. Acima deste nível não havia mais interações entre os elementos da cena. Nota-se que há progressivamente mais detalhes sendo acrescentados às imagens à medida que a profundidade aumenta.






As imagens geradas para a cena mais complexa são mostradas na Fig. 4. Foram utilizados os níveis 2, 4 e 6. Acima deste nível não havia mais interações entre os elementos da cena. Apesar de a cena possuir mais objetos e estes serem texturizados, nenhum era transparente, diminuindo o número de interações geradas na cena. Acima da profundidade 6 não eram geradas mais interações. Nestas imagens é mais difícil notar a adição de detalhes de acordo com o aumento da recursão.



Verificamos que quando chegamos a uma determinada profundidade da árvore, a contribuição das interações entre os objetos da cena permanece a mesma (relativamente pequena), ou seja, a imagem permanece a mesma mesmo aumentando a profundidade da árvore.
O gráfico da Fig. 5 ilustra como variou o tempo de execução de cada cena de acordo com a profundidade do traçado de raio. A profundidade da árvore é usada como critério de parada para o algoritmo do traçado de raio. Quando aumentamos a profundidade da árvore, aumentamos o tempo de processamento. Porém, quando chegamos a um nível de profundidade em que a contribuição das interações entre os objetos são pequenas, o tempo permanece relativamente o mesmo, fato ilustrado pela saturação das curvas. A imagem mais complexa apresentou um tempo maior de processamento devido ao maior número de objetos (mais interseções) e à presença de texturas (mais cálculos para o mapeamento).

para as imagens das Figs. 3 e 4.
2. POV-Ray
voltarO POV-Ray (Persistence of Vision Ray Tracer) cria cenas foto realistas usando o traçado de raio. A partir de um arquivo texto que contém informações descrevendo os objetos e a iluminação na cena, é gerada a imagem a partir do campo de visão da câmera especi.cado no arquivo texto. Desenvolveremos a seguir um simples exemplo apresentado em seu tutorial. Primeiro devemos informar ao POV-Ray onde está nossa câmera e para onde ela está olhando. O sistema de coordenadas do POV-Ray possui o eixo y apontado para cima o eixo x para direita e o eixo z entrando na tela.
Adicionando uma Câmera
A declaração da câmera descreve sua posição e como a câmera irá ver a cena. Damos as três coordenadas para indicar sua posição e informamos para onde a câmera estará apontada.
Nós descrevemos as coordenadas usando um vetor com três componentes
camera { location <0, 2, -9> look_at <0, 1, 2> }
A parte da cena que a câmera vai ver é definido pelo comando look_at<0, 1, 2>. Esse comando aponta a câmera para as coordenadas (0, 1, 2).
Descrevendo um Objeto
As cenas no POV-Ray são descritas usando uma linguagem de texto especial chamada de "linguagem de descrição de cena". Um objeto é descrito em nossa cena da seguinte forma
sphere { <0, 1, 2>, 2 texture { pigment { color Yellow } } }
O primeiro vetor especifica o centro da esfera. Nesse exemplo a coordenada x = 0, y = 1 e z = 2. Logo em seguida de.nimos o raio, que nesse caso foi igual a 2.
Adicionando Textura
Depois que definimos a localização e o tamanho da esfera, precisamos descrever a aparência da superfície. A declaração da textura de.fine esses parâmetros. Texturas são blocos que descrevem a cor e as propriedades do objeto. Nesse exemplo iremos especi.car somente a cor. Muitos tipos de cores são obtidos usando a declaração pigment. A cor chave especifica que o objeto inteiro terá essa cor. Os valores das cores estão entre 0 e 1. Qualquer componente não especificada será considerada 0.
color rgb <1.0, 0.8, 0.8>
Definindo uma Fonte de Luz
Precisamos de mais um detalhe a mais em nossa cena, uma fonte de luz. Adicionamos uma fonte de luz usando
light_source { <3, 1, -5> color White}
especificamos as coordenadas da fonte de luz e sua cor. Agora nosso exemplo está completo.
#include "colors.inc" background { color White } camera { location <0, 2, -9> look_at <0, 1, 2> } sphere { <0, 1, 2>, 2 texture { pigment { color Blue } } } light_source { <3, 1, -5> color White}

3. Técnicas Avançadas
voltarAs técnicas básicas de traçado de raio podem ser estendidas com a finalidade de tratar problemas (e.g. aliasing, falta de eficiência) ou de adicionar efeitos (e.g., penumbras, gloss). A seguir são abordadas algumas dessas extensões.
3.1 Tratamento do Aliasing
voltarDeterminar a cor dos pixels traçando um raio através de cada um deles é considerado uma técnica de amostragem (Sampling na Wikipedia, em inglês). Em regiões com bordas ou transições abruptas, isso pode gerar um efeito conhecido como aliasing. Grosso modo, entre um raio e outro podem estar presentes vários elementos da imagem que não serão captados, gerando artefatos como na borda do círculo da Fig. 7.

A solução mais comum para esse tipo de problema é traçar mais de um raio por pixel e combiná-los para determinar a cor final. Isso é conhecido como superamostragem. Há, porém, várias maneiras de distribuir os raios dentro do pixel e de posteriormente combiná-los.
A maneira mais intuitiva é distribuí-los em uma grade uniforme e tirar a média aritmética das cores. A Fig. 8 exemplifica o processo. Na Fig. 8a pode-se ver um pixel dividido em uma grade uniforme 5x5. Na Fig. 8b a região correspondente ao pixel é sobreposta à grade. Nota-se que alguns raios retornarão amarelo e outros cinza. A Fig. 8c ilustra a média aritmética das cores de cada raio. Caso esta fosse a fronteira entre o círculo e o fundo na imagem anterior, pixels com níveis intermediários como esse ajudariam suavizar a borda.

Esta solução ainda não é ideal, pois ainda deixa alguns padrões na imagem. O ideal seria desorganizar um pouco as posições dos raios dentro do pixel. Caso as posições fossem totalmente aleatórias, elas poderiam se acumular e deixar regiões não cobertas, como na Fig. 9a. Uma solução de compromisso é continuar com a grade uniforme e randomizar a posição dos raios dentro de suas células, como na Fig. 9b. Esta técnica é conhecida como jitter.

A Fig. 10a ilustra uma cena gerada com apenas um raio por pixel no POV-Ray. Nota-se que há vários efeitos de serrilhado nas bordas e padrões indesejados no plano perto do horizonte. Na Fig. 10b é utilizada uma grade uniforme 2x2. Nota-se que as bordas são suavizadas mas ainda há padrões indesejados no plano. Na Fig. 10c foi usada uma grade 4x4, o que também não solucionou o problema. Nas Figs. 9d e 9e são usadas grades de 2x2 e 4x4 respectivamente, mas agora é utilizado o jitter. Nota-se que os padrões indesejados são gradualmente suavizados.





Finalmente, vale observar que traçar vários raios por pixel é uma solução fácil de ser codificada, porém altamente custosa computacionalmente. A Tabela 1 lista o tempo gasto na geração das imagens da Fig. 10. Nota-se que o jitte não impacta a performance em relação à grade uniforme.
Imagem | Técnica de AA | Tempo (seg) |
Fig. 10a | Nenhuma | 0.8 |
Fig. 10b | Uniforme (2x2) | 2.85 |
Fig. 10c | Uniforme (4x4) | 9.30 |
Fig. 10d | Jitter (2x2) | 2.95 |
Fig. 10e | Jitter (4x4) | 9.16 |
Os comandos no arquivo .ini (vide documentação) no POV-Ray utilizados para configurar as técnicas de anti-aliasing da imagem na Fig. 10d, por exemplo, foram:
Width=512 Height=384 Antialias=On Sampling_Method=1 Antialias_Depth=2 Jitter=On Jitter_Amount=1.0 Antialias_Threshold=0.0
Uma explicação detalhada dos parâmetros pode ser obtida nesta seção da documentação.
3.2 Traçado de Raio Distribuído (Distributive Ray Tracing)
voltarAs técnicas básicas de traçado de raio utilizam várias simplificações para modelar a interação dos raios com os objetos e o ambiente. Estas simplificações acarretam obviamente em perda de realismo nas imagens geradas, pois alguns fenômenos não podem ser levados em conta.
Uma técnica denominada traçado de raio distribuído (distributive ray tracing) procura tratar essa deficiência, e pode ser vista como uma extensão ao traçado de raio convencional. Também é chamada de traçado de raio estocástico (stochastic ray tracing).
Ela pode ser explicada, por exemplo, no contexto da reflexão de um raio. A Fig. 11a ilustra como a reflexão é tratada no traçado de raio convencional: um raio incidente em uma superfície gera um único raio refletido que faz o mesmo ângulo com a normal. Isso é conhecido como reflexão perfeita e é válido em geral para espelhos. Já no mundo real, para as demais superfícies, um raio incidente gera vários raios refletidos com intensidades e direções ligeiramente distintas, gerando um efeito especular mais borrado conhecido como gloss. Isso é ilustrado na Fig. 11b.


Uma maneira de simular esse efeito é, portanto, traçar vários raios para uma mesma reflexão, conforme a Fig. 11b. A distribuição destes raios deve ser aleatória para não introduzir nenhum viés na imagem, de maneira similar ao jitter discutido na seção anterior.
Vários efeitos podem ser gerados com essa mesma idéia:
- Distribuindo raios transmitidos (refratados) pode-se gerar translucidez (refração não-perfeita, análogo ao gloss).
- Distribuindo raios de sombra (shadow feelers) no ângulo sólido correspondente a uma fonte de luz não pontual pode-se gerar penumbras (soft shadows).
- Distribuindo as origens dos raios sobre uma área correspondente à de uma lente com espessura finita pode-se gerar o efeito de profundidade de campo.
- Distribuindo raios no tempo pode-se gerar desfoque de movimento (motion blur).
A título de exemplo, a Fig. 12 ilustra o efeito de penumbra em uma imagem gerada no POV-Ray. O código para gerar esta cena está disponibilizado no final da página. Esta é a mesma cena da Fig. 10a, com a diferença de que a fonte de luz não é mais pontual, mas sim uma área finita. Foi utilizado anti-aliasing 2x2 com jitter para gerar a Fig. 12.

Como discutido na seção sobre Tratamento de Aliasing, gerar mais raios é computacionalmente custoso, e isso pode ser visto na Tabela 3.
Imagem | Penumbra? | Técnica de AA | Tempo (seg) |
Fig. 10a | sem | Nenhuma | 0.8 |
- | com | Nenhuma | 1.98 |
Fig. 10c | sem | Jitter (2x2) | 2.95 |
Fig. 12 | com | Jitter (2x2) | 8.25 |
4. Implementação
voltarA fim de solidificar os conhecimentos adquiridos acerca do traçado de raio, foi desenvolvido um raytracer simples na plataforma MATLAB®. O intuito do programa é puramente educacional, recebendo o singelo nome de SloRay (Slow Raytracer), dada a sua ineficiência. O MATLAB® foi escolhido por ser um ambiente de desenvolvimento rápido e que possui a sintaxe vetorial embutida. O código pode ser acessado na seção seguinte.

O esqueleto do programa foi inspirado no código disponibilizado por Paul Heckbert no livro editado por Glassner [2]. O modelo de iluminação local e global está de acordo com Watt [5]. As funções de interseção e de texturização foram desenvolvidas de acordo com Suffern [4].
Algumas características do programa:
- Formas geométricas utilizadas: esfera e plano.
- O fenômeno de refração foi descartado dada a sua maior complexidade, sendo tratada apenas a reflexão.
- Não possui técnicas anti-aliasing (apenas um raio por pixel).
- Modelo de iluminação local de Phong.
Para fins de comparação, uma cena idêntica foi gerada no programa desenvolvido e no renderizador profissional POV-Ray. A descrição da cena para POV-Ray está disponível na próxima seção, e foi renderizada com a versão 3.6. As imagens geradas estão reproduzidas abaixo. As imagens são, de maneira geral, semelhantes, mas nota-se que, a menos da iluminação ambiente e do padrão quadriculado do plano, as sombras possuem um posicionamento distinto. Isso pode ser devido a diferenças na notação do posicionamento dos objetos, dos parâmetros da câmera, ou mesmo por algum erro na implementação de nosso algoritmo. A cena foi gerada pelo nosso algoritmo em 2min17seg, e pelo POV-Ray em 0,44seg.


5. Material disponibilizado
voltarMaterial gerado neste trabalho:
- Monografia: monografia.pdf (3,7 MB)
- Código do raytracer em MATLAB: visualizar | sloray.m
- Código da cena da Fig. 12 para POV-Ray: litedemo.pov
- Código da cena da Fig. 13 para POV-Ray: cena.pov
6. Bibliografia
voltar[1] The POV-Team. Pov Ray Tutorial and Reference Material. 2009.
[2] Andrew S. Glassner. An Introduction to Ray Tracing. 1989.
[3] Philippe Bekaert Philip Dutré, Kavita Bala. Advanced Global Illumination. 2a ed., 2006.
[4] Kevin Suffern. Ray Tracing from the Ground Up. 2007.
[5] Alan Watt. 3D Computer Graphics. 3a ed., 2000.