1. O documento descreve a implementação de uma estrutura de dados Kd-Tree em um algoritmo de Ray Tracing para acelerar o processo de detecção de interseções.
2. Uma Kd-Tree é construída de forma recursiva usando o algoritmo OSAH para determinar a melhor posição dos planos de divisão, visando minimizar o custo computacional.
3. A busca na Kd-Tree para encontrar as interseções de um raio é semelhante à busca binária, testando em qual subespaço está o ponto de origem do ra
1. Aplicac¸˜ao de uma Kd-Tree em um algoritmo de Ray Tracing
Hudo Cim Assenc¸o1
1
Engenharia de Computac¸˜ao - Universidade Tecnol´ogica Federal do Paran´a (UTFPR)
CEP 80230 - Curitiba - PR - Brasil
hudo.assenco@gmail.com
Resumo. Este relat´orio tem como objetivo apresentar ao leitor as atividades e
avanc¸os que o aluno Hudo Cim Assenc¸o realizou durante o programa Jovens
Talentos para Ciˆencia sob a orientac¸˜ao do Profo
Rafael Barreto. O projeto em
quest˜ao consiste na construc¸˜ao e aplicac¸˜ao de uma estrutura de dados de par-
ticionamento tridimensional, a Kd-Tree, em uma implementac¸˜ao do algoritmo
Ray Tracing.
Sum´ario
1 Introduc¸˜ao 1
2 Kd-Tree 2
2.1 OSAH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Construc¸˜ao da Kd-Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Busca sobre a ´arvore . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Ray Tracing 5
3.1 Iluminac¸˜ao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Whitted Ray Tracing (Ray Tracing Recursivo) . . . . . . . . . . . . . . . 8
3.2.1 Raios de Whitted . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4 M´etodos 12
4.1 Implementac¸˜ao Kd-Tree . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.2 Implementac¸˜ao Ray Tracing . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3 Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4 Conclus˜ao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1. Introduc¸˜ao
A maioria dos algoritmos de computac¸˜ao gr´afica atuam em um dom´ınio de 3 dimens˜oes
e ent˜ao mapeiam para um display de duas dimens˜oes. Tais algoritmos foram desenvol-
vidos no final da d´ecada de 60, motivados pelo avanc¸o tecnol´ogico do hardware e pela
popularizac¸˜ao de dispositivos gr´aficos que s˜ao amplamente utilizados at´e hoje [10].
2. A partir desta d´ecada o Ray Tracing ou tamb´em Ray Casting ficou conhecido pela
sua simplicidade e tamb´em pela qualidade dos resultados obtidos, sua aplicac¸˜ao varia
desde simulac¸˜oes f´ısicas at´e softwares CAD/CAM, sendo o seu ponto mais forte o foto-
realismo.
Apesar de seu custo computacional elevado comparado com m´etodos atuais o Ray
Tracing ´e amplamente utilizado e v´arias implementac¸˜oes foram propostas demonstrando
o seu grande potencial. Em sua forma mais simples, o conceito Ray Tracing consiste
de raios que partem de um ponto em comum e s˜ao projetados em um plano. Cada raio
representa um pixel na tela, e a intersecc¸˜ao desse raio com os objetos na cena definem a
cor do pixel [9].
Com intuito de acelerar o algoritmo, estudou-se a utilizac¸˜ao da estrutura de dados
Kd-Tree. O termo Kd-Tree ´e uma abreviac¸˜ao de K-Dimensional Tree, uma estrutura de
dados do tipo ´arvore bin´aria para particionamento de espac¸os em k dimens˜oes.
Figura 1. Representac¸ ˜ao de uma kd-tree.
Para determinar as posic¸˜oes dos planos observados na figura 1, utilizou-se do
m´etodo OSAH (Ordinary Surface Area Heuristic), este m´etodo otimiza a posic¸˜ao dos
plano com base na quantidade de objetos e a ´area total da regi˜ao sendo dividida.
2. Kd-Tree
A estrutura Kd-Tree ´e uma especializac¸˜ao de uma ´arvore BSP (Binary Space Partitio-
ning). A diferenc¸a entre as duas estruturas ´e pouca. Muitos autores se referem a ´arvore
BSP como uma ´arvore que divide um subespac¸o por planos de orientac¸˜oes e posic¸˜oes ar-
bitr´arias, outros autores a definem como uma ´arvore que divide um subespac¸o por planos
alinhados aos eixos do plano e posicionados no ponto m´edio do espac¸o [3].
Neste relat´orio ser´a seguido a definic¸˜ao usada em [3], onde ´arvores BSP dividem
o espac¸o atrav´es de planos alinhados e posicionados no meio, enquanto que as KdTrees
possuem planos tamb´em alinhados mas posicionados de forma arbitr´aria.
3. Figura 2. Exemplo da divis˜ao de um espac¸o realizado pelo algoritmo OSAH.
2.1. OSAH
O algoritmo OSAH calcula o custo da divis˜ao de um espac¸o em dois atrav´es da proba-
bilidade de um raio interseccionar com cada subespac¸o. Para um melhor entendimento
observe a figura 2, nela ´e poss´ıvel observar um cubo A sendo dividido em dois subespac¸os
B e C atrav´es de um plano. Para calcular o custo desta operac¸˜ao, ´e preciso determinar a
´area da superf´ıcie de cada subespac¸o, resentado aqui pela func¸˜ao AS(B) e AS(C) (´area
de superf´ıcie) [3].
O custo da divis˜ao do cubo da figura 2 pode ser representado pela f´ormula 1
c(B, C) = tpercurso + PB
NB
i=1
tinters(bi) + PC
NC
i=1
tinters(ci), (1)
onde tpercurso representa o tempo necess´ario para percorrer o n´o em busca das
intersec¸˜oes, PB e PC s˜ao as probabilidades de um raio interseccionar os subespac¸os e s˜ao
definidos por AS(B)/AS(A) e AS(C)/AS(A) respectivamente. NB e NC representam
o n´umero de objetos que interseccionam cada subespac¸o e tinters ´e tempo necess´ario para
o teste de intersec¸˜ao [6].
Considerando que o custo do teste de intersec¸˜ao dos objetos ´e constante, pode-se
simplificar multiplicando apenas pelo n´umero de objetos em cada subespac¸o incluindo os
objetos que intersectam o plano de divis˜ao. O tempo necess´ario para percorrer a ´arvore
´e dependente de implementac¸˜ao e determinado de forma imp´ırica, o valor 1/80 foi o
utilizado. Caso o custo m´ınimo encontrado seja menor que o custo da criac¸˜ao de um
´unico n´o, ent˜ao o espac¸o ´e dividido em dois e o algoritimo ´e aplicado recusrivamente em
cada subespac¸o. Caso o custo seja maior, ent˜ao o espac¸o n˜ao ´e divido. Como o custo
de intersec¸˜ao de um objeto foi determinado como constante, o custo de um ´unico n´o ´e
definido pelo n´umero de objetos que interseccionam o n´o.
Para simplificar a aplicac¸˜ao, o cen´ario utilizado foi composto apenas por esferas
de raio unit´ario posicionados de forma pseudo-randˆomica, entretanto, o algoritmo pode
ser expandido sem muitas dificuldades para outras formas geom´etricas.
2.2. Construc¸˜ao da Kd-Tree
A construc¸˜ao da Kd-Tree ´e da forma recursiva e de cima para baixo. Para a definic¸˜ao da
posic¸˜ao do plano que divide o espac¸o, ´e necess´ario determinar o custo m´ınimo de todas as
4. Figura 3. O valor da func¸ ˜ao custo para objetos ao longo de um eixo, retirado de
[3].
posic¸˜oes poss´ıveis a partir da f´omula 1. A func¸˜ao custo possui descontinuidades apenas
nos limites das primitivas geom´etricas, como mostrado na figura 3.
Logo, ´e necess´ario encontrar o custo m´ınimo apenas nos limites das primitivas em
relac¸˜ao a cada eixo. Utilizando-se da mesma decis˜ao realizada em [3], o custo m´ınimo ´e
encontrado apenas para um eixo, sendo este variando de forma ciclica a cada recurs˜ao do
algoritmo da criac¸˜ao da ´arvore.
2.3. Busca sobre a ´arvore
A busca sobre a ´arvore ´e muito pr´oximo a de uma busca bin´aria. Para encontrar um n´o
folha que contenha um determinado ponto, basta verificar a posic¸˜ao do ponto em relac¸˜ao
ao plano de divis˜ao dos n´os at´e encontrar um n´o folha. Por exemplo, se o ponto est´a a
esquerda do plano de um n´o X, ent˜ao o mesmo teste ´e feito mas com o filho esquerdo de
X, at´e que o n´o n˜ao tenha filhos.
Listing 1. Pseudo c´odigo da busca de um ponto na ´arvore.
1 KdTreeNode∗ l o c a t e L e a f ( Ponto ponto ) {
2 noAtual = r a i z ;
3 i f ( ! noAtual−>caixa . contem ( ponto ) )
4 r e t u r n NULL:
5
6 while ( noAtual p o s s u i r f i l h o s )
7 {
8 i f ( ponto a esquerda de currentNode )
9 noAtual = noAtual−>f i l h o E s q u e r d o ;
10 e l s e i f ( ponto a d i r e i t a de currentNode )
11 noAtual = noAtual−>f i l h o D i r e i t o ;
12 e l s e / / ponto p e r t e n c e ao plano
13 r e t u r n noAtual
14 }
15
16 r e t u r n noAtual ;
17 }
5. Figura 4. Os n´os em verde s˜ao os n´os de interesse, a origem do raio ´e atualizada
com o ponto de intersec¸ ˜ao com os limites de cada n´o.
Para realizar uma busca a partir de um raio n˜ao ´e diferente. O n´o folha inicial ´e
determinado pela origem do raio (caso ele pertenc¸a ao n´o raiz) ou pelo ponto de intersec¸˜ao
do raio com a caixa delimitadora da raiz (caso contr´ario). A origem do raio recebe o ponto
de intersec¸˜ao com a caixa e o processo se repete para os n´os folhas subsequentes. A figura
4 exemplifica o processo.
Perceba que para cada intersec¸˜ao, o n´o folha ´e determinado aplicando-se o algo-
ritmo descrito em listing 1, realizando uma busca a partir da raiz. Para acelerar o processo,
cada n´o folha cont´em um ponteiro para cada n´o vizinho, ou seja, um ponteiro para cada
n´o cuja a face do n´o folha esteja inteiramente contida. Al´em do ponto de intersec¸˜ao do
raio com o n´o, ´e determinado tamb´em a face em que ocorre a intersec¸˜ao. Esta informac¸˜ao
´e passada para o locateLeaf, restringindo a busca.
3. Ray Tracing
A t´ecnica de Ray Tracing, inicialmente proposta por Appel [1], consiste em raios proje-
tados a partir do observador em direc¸˜ao ao ambiente, onde os objetos s˜ao definidos. A
Figura 5 ilustra um exemplo, no qual observa-se a intersec¸˜ao dos raios com os objetos.
Diferentemente do que ocorre no Ray Tracing, no modelo proposto pela f´ısica,
in´umeros raios s˜ao projetados a partir de uma fonte de luz em direc¸˜ao a um determinado
objeto e depois s˜ao refletidos ao olho formando a imagem vista pelo observador. Con-
tudo, a maior parte destes raios n˜ao chegam ao olho, n˜ao influenciando na percepc¸˜ao do
observador, tornando desnecess´ario o c´alculo de todos os raios emitidos pela fonte de luz
[8].
Apesar de descartar todos os raios emitidos pela fonte que n˜ao alcanc¸am o ob-
servador, o Ray Tracing ´e ainda considerado uma t´ecnica de forc¸a bruta, pois para cada
pixel na tela o algoritmo calcula intersec¸˜oes para todos os objetos na cena, o que acaba
tornando este processo computacionalmente ineficiente.
A seguir ´e apresentado em pseudo-c´odigo um algoritmo para o Ray Tracing.
6. Figura 5. Ray Tracing em perspectiva [8].
Listing 2. Pseudo c´odigo de Ray-Tracing adaptado de [2]
1 Main{
2 f o r cada p i x e l ( x , y ) do
3 r a i o = (O, ( x , y ) ) ;
4 iluminacao ( x , y ) = Trace ( r a i o ) ;
5 w r i t e ( iluminacao ( x , y ) ) ;
6 end f o r
7 }
8
9 Trace ( r a i o ) {
10 Calcula i n t e r s e c a o P de r a i o com o b j e t o mais proximo ;
11 Determina o t i p o de ” m a t e r i a l ” no o b j e t o de
i n t e r s e c a o ;
12 Return Shade ( raio , P , m a t e r i a l ) ;
13 }
14
15 Shade ( raio , P , m a t e r i a l ) {
16 cor = 0;
17 i f luz v i s i v e l then
18 Calcula iluminacao em P ;
19 cor = iluminacao em P ;
20 e l s e
21 cor = iluminacao ambiente em P ;
22 end i f
23 Return cor ;
24 }
3.1. Iluminac¸˜ao
A func¸˜ao apresentada na linha 15 do pseudo-c´odigo consiste na aplicac¸˜ao de um modelo
de iluminac¸˜ao. Dentre os v´arios modelos de iluminac¸˜ao existentes, destaca-se o modelo
proposto por Phong [7], por sua simplicidade e qualidade dos resultados. O modelo divide
7. a iluminac¸˜ao em trˆes componentes (Figura 6): ambiente, difusa e especular. A compo-
nente ambiente ´e constante em toda a cena e representa a a luz dispersa pelo ambiente. A
difusa ´e definida pela lei de Lambert e representa o efeito da luz incidente em func¸˜ao do
ˆangulo de incidˆencia e a componente especular representa as ´areas realc¸adas de um objeto
pela reflex˜ao da luz na direc¸˜ao do observador.
Figura 6. As componentes do m´etodo de iluminac¸ ˜ao proposto por Phong.
A equac¸˜ao que define a iluminac¸˜ao ambiente ´e:
Ia = KaLa, (2)
em que:
• Ka ´e o coeficiente de reflex˜ao de luz ambiente.
• La ´e a intensidade da luz ambiente da fonte.
• Ia ´e a contribuic¸˜ao da iluminac¸˜ao ambiente.
A equac¸˜ao que determina a contribuic¸˜ao da iluminac¸˜ao difusa ´e dada pela lei de
Lambert:
Id = LdKdcosθ, (3)
em que:
• θ ´e o angulo entre a direc¸˜ao da luz incidente e a normal `a superf´ıcie (0 ≤ θ ≤ π/2).
• kd ´e o coeficiente de reflex˜ao difusa (varia para cada material).
• Ld ´e a intensidade de luz difusa da fonte.
• Id ´e a contribuic¸˜ao da iluminac¸˜ao difusa.
A ´ultima componente ´e a especular, definida por:
Is = KsLs(cosβ)n
, (4)
em que:
• β ´e o angulo entre a direc¸˜ao da luz refletida e a direc¸˜ao do observador.
• n ´e o expoente respons´avel pela forma do reflexo no material (Figura 7), quanto
maior o n, menor ´e a ´area de reflex˜ao(varia para cada material).
• Ks ´e o coeficiente de reflex˜ao especular (varia para cada material).
• Ls ´e a intensidade de luz especular da fonte.
• Is ´e a contribuic¸˜ao da iluminac¸˜ao especular.
8. Figura 7. Representac¸ ˜ao dos valores de (cosβ)n
para diferentes valores de n
Utilizando a notac¸˜ao de vetores (Figura 8), podemos escrever a equac¸˜ao res-
pons´avel pela intensidade de luz em um ponto de um objeto somando as trˆes equac¸˜oes
apresentadas anteriormente, obtendo:
I = Ia + Id + Is (5)
I = LaKa + LdKd
ˆL · ˆN + LsKs( ˆR · ˆE)n
(6)
Figura 8. Modelo de iluminac¸ ˜ao de Phong representado por vetores [7].
A Figura 9 demonstra o resultado obtido por Phong.
Figura 9. Resultado demonstrado por Phong [7].
3.2. Whitted Ray Tracing (Ray Tracing Recursivo)
No modelo de Phong cada fonte de iluminac¸˜ao ´e localizado em um ponto infinitamente
distante dos objetos da cena e ignora os objetos como poss´ıveis fontes de iluminac¸˜ao,
9. afetando consideravelmente a qualidade da reflex˜ao especular [11].
Para corrigir este problema, em 1980 Whitted, baseado no modelo de Phong, in-
troduziu a ideia de 3 novos raios para cada intersec¸˜ao: sombra, reflex˜ao e refrac¸˜ao. Ope-
rando recursivamente, cada intersec¸˜ao lanc¸a novos raios que buscam novas intersec¸˜oes,
para possibilitar a utilizac¸˜ao das informac¸˜oes de iluminac¸˜oes globais da cena.
A seguir a modificac¸˜ao da func¸˜ao Shade do algoritmo anterior para Ray Tracing
Recursivo:
Listing 3. Pseudo c´odigo adaptado de [2]
1 Shade ( raio , P , m a t e r i a l )
2 {
3 iluminacao = 0;
4 i f L v i s i v e l then
5 Calcula iluminacao em P ;
6 iluminacao = iluminacao + iluminacao em P ;
7 e l s e
8 iluminacao = iluminacao + iluminacao ambiente em P
;
9 end i f
10
11 i f m a t e r i a l = e s p e c u l a r then
12 r a i o = Raio r e f l e t i d o ;
13 iluminacao = iluminacao + Trace ( r a i o ) ;
14 end i f
15 i f m a t e r i a l = t r a n s l u c i d o then
16 r a i o = Raio r e f r a t a d o ;
17 iluminacao = iluminacao + Trace ( r a i o ) ;
18 end i f
19
20 Return ( iluminacao ) ;
21 }
Houve alterac¸˜oes na obtenc¸˜ao do valor da cor, linha 6 e 7, para que seja somado
os valores de iluminac¸˜ao de todos os raios projetados recursivamente, pois as intersec¸˜oes
geram novas intersec¸˜oes, como mostrado na Figura 10.
10. Figura 10. Lei de refrac¸ ˜ao, adaptado de [4].
Foram tamb´em adicionados linhas para identificar o tipo de material do objeto que
pode ser especular ou translucido que geram raios de reflex˜ao e de refrac¸˜ao respectiva-
mente. A chamada da func¸˜ao Trace nas linhas 13 e 17 garantem a recurs˜ao que ser´a exe-
cutada at´e que todas as intersec¸˜oes poss´ıveis sejam encontradas ou at´e que seja alcanc¸ado
um limite que pode ser definido antes da execuc¸˜ao do algoritmo.
3.2.1. Raios de Whitted
A representac¸˜ao resumida da func¸˜ao da equac¸˜ao de intensidade de Whitted ´e dada por:
I(P0, d) = Iphong + Ireflexao + Irefracao, (7)
em que:
• P0 ´e o ponto de observac¸˜ao
• d a direc¸˜ao do raio.
• Iphong ´e o resultado da equac¸˜ao da reflex˜ao difusa de Phong.
• Ireflexao a equac¸˜ao da reflex˜ao, dada por KsI(Q,S).
• Irefracao a equac¸˜ao da refrac¸˜ao, dada por KtI(Q,T).
Em que Q ´e o novo ponto de origem dos novos raios criados na intersec¸˜ao do raio
anterior (d).
Figura 11. Raio da sombra, adaptado de [4].
Para cada intersec¸˜ao ´e lanc¸ado um raio, cujo a origem ´e o ponto de intersec¸˜ao e
tem como direc¸˜ao a fonte de luz. Este raio ´e denominado sombra e pode ser observado
11. na Figura 11 como sendo o raio AB. Caso o raio intersecte algum objeto opaco a compo-
nente da iluminac¸˜ao determinada pelo modelo Phong ´e definida apenas pela iluminac¸˜ao
ambiente, caso o objeto seja transparente deve-se levar em conta o fator de transparˆencia
pois apenas uma parcela de luz atravessa o objeto [9].
Figura 12. Raio de reflex˜ao, adaptado de [4].
Para cada intersec¸˜ao, caso o material seja especular, ´e criado um raio de reflex˜ao
utilizando a lei da reflex˜ao, figura 13, em que o ˆangulo de incidˆencia ´e igual ao ˆangulo de
reflex˜ao, como observado na Figura 12.
Figura 13. Lei de reflex˜ao [5].
O vetor de reflex˜ao ´e calculado a partir da equac¸˜ao [5]:
R = 2(V · N)N − V . (8)
Figura 14. Raio de refrac¸ ˜ao, adaptado de [4].
Para cada intersec¸˜ao, caso o material seja translucido, ´e criado um raio da refrac¸˜ao,
utilizando a lei da refrac¸˜ao de Snell, figura 15, observado na figura 14.
12. Figura 15. Lei de refrac¸ ˜ao [5].
O vetor de refrac¸˜ao ´e calculado a partir da equac¸˜ao [5]:
c1
c2
=
sin(θ1)
sin(θ2)
, (9)
R =
2
c2
1 − c2
2(1 − (V · N)2)
1
c1
(−N)
c2
c1
((V · N)N − V ). (10)
4. M´etodos
Para a implementac¸˜ao do algoritmo de construc¸˜ao da Kd-Tree foi utilizado a linguagem
C++ em conjunto com as bibliotecas OpenGL e SDL2 para gerar a representac¸˜ao gr´afica
que pode ser observada na figura 1.
4.1. Implementac¸˜ao Kd-Tree
Para a representac¸˜ao de um n´o da ´arvore foi utilizada a classe KdTreeNode.
Listing 4. Declarac¸ ˜ao da classe KdTreeNode.
1 c l a s s KdTreeNode
2 {
3 p u b l i c :
4 / / C o n s t r u t o r e s e d e s t r u t o r e s omitidos .
5
6 / / Profundidade do n ´o
7 unsigned char depth ;
8 / / Eixo d i v i d i d o pelo n ´o
9 unsigned char a x i s ;
10 / / A posic¸ ˜ao no eixo em que o plano d i v i d e
11 f l o a t s p l i t P o s ;
12 / / Uma caixa que d e l i m i t a o espac¸ o que compreende o n ´o
13 BoundingBox box ;
14 / / Filho esquerdo
15 KdTreeNode∗ l c h i l d ;
16 / / Filho d i r e i t o
17 KdTreeNode∗ r c h i l d ;
13. 18 / / Array de l i n k s para n ´os a d j a c e n t e s
19 KdTreeNode∗∗ l i n k s ;
20
21 / / L i s t a de o b j e t o s que i n t e r s e c i o n a m o n ´o
22 s t d : : vector <Geometric∗> p r i m i t i v e s ;
23 };
Enquanto que para a representac¸˜ao da ´arvore foi utilizada a classe KdTree.
Listing 5. Declarac¸ ˜ao da classe KdTree.
1 c l a s s KdTree
2 {
3 p u b l i c :
4 / / C o n s t r u t o r e s e d e s t r u t o r e s omitidos .
5 KdTreeNode∗ r o o t ;
6
7 void b u i l d ( const Scene& scene ) ;
8 const KdTreeNode∗ l o c a t e L e a f ( const Point& point , const
KdTreeNode∗ node ) const ;
9 p r i v a t e :
10 void s u b d i v i d e ( KdTreeNode ∗ const parent , unsigned char
currentAxis , S p l i t P o s ∗ s p l i t P o s L i s t ) ;
11 void buildKdTreeLinks ( KdTreeNode ∗ const node ) ;
12 KdTreeNode∗ getNeighbor ( const KdTreeNode ∗ const node ,
Faces face ) const ;
13 };
O m´etodo build ´e o utilizado para construir a ´arvore a partir de um Scene. Um
Scene ´e basicamente uma classe que cont´em uma lista de primitivas geom´etricas, uma
camera e uma caixa que delimita o cen´ario.
Listing 6. Definic¸ ˜ao do m´etodo KdTree::build.
1 void KdTree : : b u i l d ( const Scene& scene )
2 {
3 r o o t = new KdTreeNode ;
4 root −>depth = 0;
5 root −>p r i m i t i v e s = scene . m objects ;
6 root −>box = scene . m box ;
7
8 S p l i t P o s ∗ s p l i t P o s L i s t = new S p l i t P o s [ root −>p r i m i t i v e s .
s i z e ( ) ∗ 2 ] ;
9
10 s u b d i v i d e ( root , 0 , s p l i t P o s L i s t ) ;
11
12 d e l e t e [ ] s p l i t P o s L i s t ;
13
14 buildKdTreeLinks ( r o o t ) ;
15 }
14. O m´etodo subdivide ´e um m´etodo recursivo, que calcula a func¸˜ao custo para cada
posic¸˜ao do n´o e constroi os n´os filhos.
Listing 7. Definic¸ ˜ao do m´etodo KdTree::subdivide.
1 void KdTree : : s u b d i v i d e ( KdTreeNode ∗ const parent , unsigned
char c u r r e n t A x i s )
2 {
3 parent −>l c h i l d = NULL;
4 parent −>r c h i l d = NULL;
5 parent −>l i n k s = NULL;
6
7 / / C r i t ´e r i o de parada
8 i f ( ( parent −>depth >= MAXDEPTH) | | ( parent −>p r i m i t i v e s .
s i z e ( ) <= MINOBJECTS) )
9 r e t u r n ;
10
11 g e t A l l S p l i t P o s i t i o n s ( s p l i t P o s L i s t , parent −>p r i m i t i v e s ,
c u r r e n t A x i s ) ;
12
13 BoundingBox bestRightBox , bestLeftBox ;
14 f l o a t minCost , b e s t S p l i t P o s ;
15
16 b e s t S p l i t P o s = g e t B e s t S p l i t P o s i t i o n ( s p l i t P o s L i s t ,
parent , currentAxis ,
17 &minCost , &bestLeftBox , &bestRightBox ) ;
18
19 / / Se o custo f o r maior que o t e s t e de i n t e r s e c¸ ˜a o de
todos os o b j e t o s n˜ao vale a pena c r i a r o n´o
20 i f ( minCost > parent −>p r i m i t i v e s . s i z e ( ) )
21 {
22 r e t u r n ;
23 }
24
25 buildNode ( parent , b e s t S p l i t P o s , currentAxis ,
bestLeftBox , bestRightBox ) ;
26
27 / / Ordem c i c l i c a dos eixos de d i v i s ˜a o
28 i f ( c u r r e n t A x i s >= 2)
29 c u r r e n t A x i s = 0;
30 e l s e
31 c u r r e n t A x i s ++;
32
33 s u b d i v i d e ( parent −>l c h i l d , c u r r e n t A x i s ) ;
34 s u b d i v i d e ( parent −>r c h i l d , c u r r e n t A x i s ) ;
35 }
15. A estrutura SplitPos ´e uma estrutura simples que possui apenas um float represen-
tando a posic¸˜ao e dois inteiros representando o n´umero de primitivas a esquerda e a direita.
A func¸˜ao getAllSplitPositions apenas percorre todos as primitivas e para cada primitiva
determina as duas posic¸˜oes de limites em relac¸˜ao ao eixo atual. Com as duas posic¸˜oes de-
terminadas a func¸˜ao percorre novamente pelas primitivas para determinar quantas est˜ao a
esquerda e quantas a direita, populando o vetor de SplitPos.
A func¸˜ao getBestSplitPosition aplica a func¸˜ao custo para cada posic¸˜ao e retorna a
melhor posic¸˜ao, o menor custo e as caixas delimitadoras de cada subespac¸o.
Listing 8. Definic¸ ˜ao do m´etodo getBestSplitPosition.
1 i n l i n e f l o a t g e t B e s t S p l i t P o s i t i o n ( S p l i t P o s ∗ s p l i t P o s L i s t ,
const KdTreeNode ∗ const parent ,
2 unsigned char currentAxis , f l o a t ∗ f i n a l C o s t , BoundingBox
∗ bestLeftBox ,
3 BoundingBox ∗ bestRightBox )
4 {
5 f l o a t minCost = 100000;
6 i n t b e s t I d x = 0;
7 f l o a t c o s t = 0;
8 f l o a t invParentNodeArea = 1 / parent −>box .
getSurfaceArea ( ) ;
9
10 BoundingBox leftBox = parent −>box ;
11 BoundingBox rightBox = parent −>box ;
12
13 ∗ bestLeftBox = parent −>box ;
14 ∗ bestRightBox = parent −>box ;
15
16 f l o a t l e f t A r e a = 0 , r i g h t A r e a = 0;
17 f o r ( unsigned i n t i =0; i < parent −>p r i m i t i v e s . s i z e ( ) ∗2;
i ++)
18 {
19 / / Ajusta a caixa d e l i m i t a d o r a do n ´o da esquerda em
r e l a c¸ ˜a o a posic¸ ˜ao a t u a l .
20 rightBox . pos . m data [ c u r r e n t A x i s ] = s p l i t P o s L i s t [ i ] .
pos ;
21 rightBox . s i z e . m data [ c u r r e n t A x i s ] = parent −>box .
s i z e . m data [ c u r r e n t A x i s ] − ( s p l i t P o s L i s t [ i ] . pos
− parent −>box . pos . m data [ c u r r e n t A x i s ] ) ;
22
23 / / Ajusta a caixa d e l i m i t a d o r a do n ´o da d i r e i t a em
r e l a c¸ ˜a o a posic¸ ˜ao a t u a l .
24 leftBox . s i z e . m data [ c u r r e n t A x i s ] = s p l i t P o s L i s t [ i ] .
pos − parent −>box . pos . m data [ c u r r e n t A x i s ] ;
25
26 / / Calculo do custo , i n c l u i n d o o custo de p e sq u is a
na ´avore
16. 27 c o s t = 0.0125 f + ( leftBox . getSurfaceArea ( ) ∗
s p l i t P o s L i s t [ i ] . lnum + rightBox . getSurfaceArea ( )
∗ s p l i t P o s L i s t [ i ] . rnum ) ∗ invParentNodeArea ;
28 i f ( c o s t < minCost )
29 {
30 minCost = c o s t ;
31 b e s t I d x = i ;
32 ∗ bestLeftBox = leftBox ;
33 ∗ bestRightBox = rightBox ;
34 }
35 }
36
37 ∗ f i n a l C o s t = minCost ;
38
39 r e t u r n s p l i t P o s L i s t [ b e s t I d x ] . pos ;
40 }
A func¸˜ao buildNode, simplesmente constroi cada n´o filho e monta a lista de pri-
mitivas em cada, de acordo com a divis˜ao do espac¸o.
Listing 9. Definic¸ ˜ao do m´etodo buildNode.
1 i n l i n e void buildNode ( KdTreeNode ∗ const parent , f l o a t
b e s t S p l i t P o s , unsigned char currentAxis ,
2 BoundingBox bestLeftBox , BoundingBox bestRightBox )
3 {
4 KdTreeNode∗ l e f t c h i l d = new KdTreeNode ;
5 l e f t c h i l d −>depth = parent −>depth +1;
6 KdTreeNode∗ r i g h t c h i l d = new KdTreeNode ;
7 r i g h t c h i l d −>depth = parent −>depth +1;
8
9 l e f t c h i l d −>box = bestLeftBox ;
10 r i g h t c h i l d −>box = bestRightBox ;
11
12 parent −>l c h i l d = l e f t c h i l d ;
13 parent −>r c h i l d = r i g h t c h i l d ;
14 parent −>a x i s = c u r r e n t A x i s ;
15 parent −>s p l i t P o s = b e s t S p l i t P o s ;
16
17 / / Co n st ro i a l i s t a de o b j e t o s em cada n ´o
18 f o r ( s t d : : vector <Geometric ∗ >:: i t e r a t o r o b j e c t I t = parent
−>p r i m i t i v e s . begin ( ) ; o b j e c t I t != parent −>p r i m i t i v e s
. end ( ) ; o b j e c t I t ++)
19 {
20 f l o a t p1 , p2 ;
21 (∗ o b j e c t I t )−>getRange(&p1 ,&p2 , c u r r e n t A x i s ) ;
22 i f ( p1 < parent −>s p l i t P o s )
23 l e f t c h i l d −>p r i m i t i v e s . push back (∗ o b j e c t I t ) ;
17. 24 i f ( p1 >= parent −>s p l i t P o s | | p2 > parent −>s p l i t P o s )
25 r i g h t c h i l d −>p r i m i t i v e s . push back (∗ o b j e c t I t ) ;
26 }
27 }
Para finalizar a construc¸˜ao da ´arvore, basta apenas construir os links entre os n´os
vizinhos para obter uma melhor performance durante a pesquisa na ´avore. Os links s˜ao
construidos a partir da caixa delimitadora de um n´o folha, realizando uma busca na ´arvore
´e poss´ıvel achar um n´o adjacente ao n´o folha em quest˜ao por uma determinada face.
Listing 10. Definic¸ ˜ao do m´etodo KdTree::buildKdTreeLinks.
1 void KdTree : : buildKdTreeLinks ( KdTreeNode ∗ const node )
2 {
3 / / Se o n ´o n˜ao f o r uma f o l h a
4 i f ( node−>l c h i l d != NULL | | node−>r c h i l d != NULL)
5 {
6 buildKdTreeLinks ( node−>l c h i l d ) ;
7 buildKdTreeLinks ( node−>r c h i l d ) ;
8 }
9
10 node−>l i n k s = new KdTreeNode ∗ [ 6 ] ;
11 / / Para cada uma das 6 f a c e s de um cubo .
12 f o r ( i n t i =0; i <6; i ++)
13 {
14 Faces face = s t a t i c c a s t <Faces >( i ) ;
15 / / Se a face f o r c o p la n a r com a face da caixa que
d e l i m i t a toda a cena , nenhum n´o vizinho ´e
p o s s´ı v e l .
16 i f ( node−>box . getFacePos ( face ) == root −>box .
getFacePos ( face ) )
17 node−>l i n k s [ i ] = NULL;
18 e l s e
19 node−>l i n k s [ i ] = getNeighbor ( node , face ) ;
20 }
21
22 }
A func¸˜ao getNeighbor realiza uma busca bin´aria encontrando o menor n´o em que
a face deste contenha a face do n´o passado por argumento. A func¸˜ao parallel ´e uma func¸˜ao
simples que determina apenas se o plano de divis˜ao de um determinado n´o ´e paralelo `a
face passada pelo argumento.
Listing 11. Definic¸ ˜ao do m´etodo KdTree::getNeighbor.
1 KdTreeNode∗ KdTree : : getNeighbor ( const KdTreeNode ∗ const
node , Faces face ) const
2 {
3 KdTreeNode∗ currentNode = r o o t ;
4
18. 5 / / Se o currentNode n˜ao f o r uma f o l h a
6 while ( currentNode −>l c h i l d != NULL && currentNode −>
r c h i l d != NULL)
7 {
8 i f ( p a r a l l e l ( face , currentNode −>a x i s ) )
9 {
10 / / Se face a d i r e i t a do plano do n ´o
11 i f ( node−>box . getFacePos ( face ) > currentNode −>
s p l i t P o s + EPSILON)
12 currentNode = currentNode −>r c h i l d ;
13 e l s e i f ( node−>box . getFacePos ( face ) <
currentNode −>s p l i t P o s − EPSILON)
14 currentNode = currentNode −>l c h i l d ;
15 / / Se face c o p la n a r com o plano de currentNode ,
e face f o r uma das d e l i m i t a d o r a s a esquerda .
16 e l s e i f ( face == LEFT | | face == BOTTOM | | face
== BACK)
17 currentNode = currentNode −>l c h i l d ;
18 e l s e
19 currentNode = currentNode −>r c h i l d ;
20 }
21 e l s e
22 {
23 i f ( node−>box . pos . m data [ currentNode −>a x i s ] >=
currentNode −>s p l i t P o s )
24 currentNode = currentNode −>r c h i l d ;
25 e l s e i f ( node−>box . pos . m data [ currentNode −>a x i s ]
+ node−>box . s i z e . m data [ currentNode −>a x i s ]
<= currentNode −>s p l i t P o s )
26 currentNode = currentNode −>l c h i l d ;
27 e l s e
28 r e t u r n currentNode ;
29 }
30 }
31
32 r e t u r n currentNode ;
33 }
4.2. Implementac¸˜ao Ray Tracing
O algoritmo Ray Tracing implementado ´e b´asico, possui suporte para apenas uma fonte de
luz pontual e raios de reflex˜ao, n˜ao possui objetos transl´ucidos. Foi implementado apenas
para o estudo do comportamento entre a eficiˆencia da utilizac¸˜ao da ´arvore comparada a
t´ecnica de forc¸a bruta.
A func¸˜ao render ´e a respons´avel pela formac¸˜ao dos raios e a escrita das cores
obtidas atrav´es da interac¸˜ao dos raios com a cena. Primeiramente ´e calculado a posic¸˜ao do
pixel utilizando como base o sistema de coordenadas da camera, em seguida essa posic¸˜ao
19. ´e transformada para o sistema de coordendas globais e o raio ´e formado pela origem da
camera e o vetor da origem at´e a posic¸˜ao do pixel normalizado. Os parametros m tMax e
m tMin s˜ao as distˆancias m´axima e m´ınima respectivamente.
Listing 12. Definic¸ ˜ao do m´etodo render.
1 void render ( const Scene & scene , const KdTree & tree ,
unsigned char ∗ p i x e l s , i n t width , i n t h e i g h t )
2 {
3 f l o a t a s p e c t R a t i o = ( f l o a t ) width / h e i g h t ;
4 f l o a t angle = tan ( scene . m camera . m fov ∗ 0.5 ∗ PIdiv180
) ;
5
6 const Point & o r i g i n = scene . m camera . g e t O r i g i n ( ) ;
7
8 f o r ( i n t y =0; y<h e i g h t ; y++)
9 {
10 i n t i = 0;
11 f o r ( i n t x =0; x<width ; x++)
12 {
13 / / Posic¸ ˜ao do p i x e l no sistema de coordenadas da
camera .
14 const f l o a t camX = (2 ∗ ( x + 0 . 5 ) / width − 1)
∗ a s p e c t R a t i o ∗ angle ;
15 const f l o a t camY = (1 − 2 ∗ ( y + 0 . 5 ) / h e i g h t )
∗ angle ;
16 const Point p (camX , camY , −1) ;
17 / / Posic¸ ˜ao do p i x e l no sistema de coordenadas
g l o b a l .
18 const Point aux = scene . m camera . getTransform ( )
. t r a n s f o r m ( p ) ;
19
20 const Ray r ( o r i g i n , aux . s u b t r a c t ( o r i g i n ) .
normalize ( ) ) ;
21 r . m tMin = 0;
22 r . m tMax = 1e4 ;
23
24 const Color c o l o r = traceRay ( r , scene , tree , 0)
;
25
26 p i x e l s [ x + y ∗ ( width ∗3) + i ] = c o l o r . r ;
27 p i x e l s [ x + y ∗ ( width ∗3) + i + 1] = c o l o r . g ;
28 p i x e l s [ x + y ∗ ( width ∗3) + i + 2] = c o l o r . b ;
29
30 i +=2;
31 }
32 }
33 }
20. A func¸˜ao traceRay determina a cor em cada pixel utilizando o m´etodo proposto
por Phong.
Listing 13. Definic¸ ˜ao do m´etodo traceRay.
1 Color traceRay ( const Ray & r , const Scene& scene , const
KdTree& tr ee , i n t r e c u r s i o n L e v e l )
2 {
3 i f ( r e c u r s i o n L e v e l >= MAX RECURSION)
4 {
5 r e t u r n Color ( 0 , 0 , 0 ) ;
6 }
7
8 Color r e f l e c t i o n C o l o r ;
9 Color d i f u s e C o l o r ;
10
11 f l o a t d i f u s e = 0 , s p e c u l a r = 0;
12
13 I n t e r s e c t i o n i n t e r s e c t i o n ;
14
15 i f ( ! f i n d N e a r e s t I n t e r s e c t i o n ( r , scene , tree , &
i n t e r s e c t i o n ) )
16 {
17 r e t u r n Color ( 0 , 0 , 0 ) ;
18 }
19
20 const Vector l i g h t D i r e c t i o n = scene . m lightSource .
g e t O r i g i n ( ) . s u b t r a c t ( i n t e r s e c t i o n . m i n t e r s e c t i o n ) .
normalize ( ) ; / / l i g h t O r i g i n − i n t e r s e c t i o n P o i n t (
normalized )
21
22 const Ray shadowRay ( i n t e r s e c t i o n . m i n t e r s e c t i o n ,
l i g h t D i r e c t i o n ) ;
23
24 const M a t e r i a l & m a t e r i a l = i n t e r s e c t i o n . m object −>
g e t M a t e r i a l ( ) ;
25
26 f l o a t cosDifuseAngle = l i g h t D i r e c t i o n . dotProduct (
i n t e r s e c t i o n . m normal ) ;
27
28 Vector r e f l e c t e d = 2 ∗ fabs ( cosDifuseAngle ) ∗
i n t e r s e c t i o n . m normal ;
29 r e f l e c t e d −= l i g h t D i r e c t i o n ;
30
31 i f ( cosDifuseAngle >0)
32 {
33 i f ( ! shadowRayTrace ( shadowRay , scene , tree ,
i n t e r s e c t i o n . m object ) )
21. 34 {
35 d i f u s e = cosDifuseAngle ∗ m a t e r i a l . m difuse ;
36 }
37 e l s e
38 {
39 d i f u s e = 0;
40 }
41
42 i f ( m a t e r i a l . m specular )
43 {
44 f l o a t cosSpecularAngle = r e f l e c t e d . dotProduct ( r
. m d i r e c t i o n . g e t I n v e r s e ( ) ) ;
45 i f ( cosSpecularAngle >0)
46 {
47 s p e c u l a r = m a t e r i a l . m specular ∗ pow (
cosSpecularAngle , m a t e r i a l .
m specularPower ) ;
48 }
49 e l s e
50 {
51 s p e c u l a r = 0;
52 }
53 }
54 }
55
56 d i f u s e C o l o r = m a t e r i a l . m color ∗ scene . m lightSource .
m i n t e n s i t y ∗
57 ( m a t e r i a l . m ambient + d i f u s e + s p e c u l a r ) ;
58
59 i f ( m a t e r i a l . m r e f l e c t i v e n e s s )
60 {
61 const Ray r e f l e c t e d R a y ( i n t e r s e c t i o n . m i n t e r s e c t i o n ,
r e f l e c t e d ) ;
62
63 r e f l e c t i o n C o l o r = m a t e r i a l . m r e f l e c t i v e n e s s ∗
traceRay ( reflectedRay , scene , tree ,
r e c u r s i o n L e v e l + 1) ;
64 }
65
66 r e t u r n d i f u s e C o l o r + r e f l e c t i o n C o l o r ;
67 }
4.3. Resultados
A figura 16 demonstra o resultado obtido com o algoritmo Ray Tracing implementado.
A figura 17 mostra o tempo de renderizac¸˜ao para ambos m´etodos, n˜ao ´e considerado o
tempo para a construc¸˜ao da ´arvore. Como o esperado, o m´etodo por forc¸a bruta apre-
sentou um comportamento O(n), enquanto que com a utilizac¸˜ao da ´arvore apresentou um
22. Figura 16. Imagem formada utilizando o algoritmo Ray Tracing descrito neste
relat´orio.
comportamento O(log(n)). Isso se deve ao fato de por forc¸a bruta, ´e necess´ario testar to-
das as primitivas em uma cena para cada raio lanc¸ado e com a utilizac¸˜ao da ´arvore ´e feito
uma busca bin´aria no espac¸o.
4.4. Conclus˜ao
O trabalho apresentado n˜ao possui nenhuma inovac¸˜ao ou brilhantismo, apenas uma
implementac¸˜ao de uma Kd-Tree para um o algoritmo de Ray-Tracing e um estudo simples
sobre sua eficiˆencia. Apesar de o trabalho estar longe do estado da arte sobre o assunto e
n˜ao ter muito valor para a comunidade ciet´ıfica, tendo em vista uma perspectiva pessoal,
foi de grande utilidade pois proporcionou experiˆencias em desenvolvimento de sistemas
mais complexos e tamb´em conhecimentos sobre computac¸˜ao gr´afica.
As dificuldades e obst´aculos encontrados foram grandes e a superac¸˜ao destes ser-
viram de motivac¸˜ao para a continuac¸˜ao do trabalho, onde ser´a estudado abordagens mais
eficientes e a utilizac¸˜ao de bibliotecas GPGPU para obter uma melhor performance.
24. Referˆencias
[1] Arthur Appel. Some techniques for shading machine renderings of solids. 1968.
[2] Jonas Gomes and Luiz Velho. Fundamentos da Computac¸˜ao Gr´afica. IMPA, Rio De
Janeiro, 2004.
[3] Vlastimil Havran. Heuristic Ray Shooting Algorithms. Ph.d. thesis, Department of Com-
puter Science and Engineering, Faculty of Electrical Engineering, Czech Technical
University in Prague, November 2000.
[4] Yan Liu. Raytrace. http://www.siggraph.org/education/materials/
HyperGraph/raytrace/rt_java/raytrace.html.
[5] Joaquim Madeira. Ray-tracing. http://sweet.ua.pt/bss/aulas/Ray_
Tracing_Nov07_JM.pdf, November 2007.
[6] Matt Pharr and Greg Humphreys. Physically Based Rendering, Second Edition: From
Theory To Implementation. Morgan Kaufmann Publishers Inc., San Francisco, CA,
USA, 2nd edition, 2010.
[7] Bui Tuong Phong. Illumination for computer generated pictures. Commun. ACM,
18(6):311–317, June 1975.
[8] David F. Rogers. Procedural elements for computer graphics. WCB/McGraw-Hill, Bos-
ton, Mass, 2nd ed edition, 1998.
[9] F. W. Silva. Introduc¸˜ao ao Ray Tracing. Universidade Federal do Rio de Janeiro (UFRJ).
[10] Alan H. Watt. 3D computer graphics. Addison-Wesley, Harlow, England ; Reading,
Mass, 3rd ed edition, 2000.
[11] Turner Whitted. An improved illumination model for shaded display. Commun. ACM,
23(6):343–349, June 1980.