Práctica 2: Trazador de rayos clásico básico

Anuncio
MASTER EN INFORMÁTICA GRÁFICA, JUEGOS Y REALIDAD VIRTUAL
Técnicas Avanzadas de Gráficos 3D
Práctica 2:
Trazador de rayos clásico básico
Carlos Garre del Olmo
Álvaro Pérez Molero
Índice
1
2
3
4
5
6
7
8
Introducción.............................................................................................................. 3
Cámara...................................................................................................................... 3
2.1
Generación de rayos ......................................................................................... 3
2.2
Transformación de coordenadas de pantalla a coordenadas del mundo........... 3
Intersecciones ........................................................................................................... 4
3.1
Intersección rayo-esfera.................................................................................... 4
3.2
Intersección rayo-triángulo............................................................................... 5
Materiales ................................................................................................................. 6
4.1
Lambertian........................................................................................................ 6
4.2
Phong ................................................................................................................ 6
4.3
ShinyPhong....................................................................................................... 8
Luces......................................................................................................................... 8
Renderizado de la escena.......................................................................................... 8
Resultados................................................................................................................. 9
Bibliografía............................................................................................................. 11
1 Introducción
La práctica consiste en realizar un trazador de rayos clásico, de manera que se pongan
en práctica los conocimientos teóricos adquiridos en la asignatura.
Para ello, se ha proporcionado un esqueleto sobre el que hay que realizar todas las tareas
pedidas para lograr el objetivo de implementar dicho trazador de rayos.
Sobre el código proporcionado, hay que generar rayos desde el origen de la cámara, ver
cómo intersecan con los distintos objetos de la escena, calcular cómo se refleja la luz en
dichos objetos, dependiendo tanto de las fuentes de luz presentes en la escena como de
los materiales de los que están compuestos los objetos de la escena. Todo ello con el
objetivo final de calcular el color final de cada píxel, que será el que el usuario vea en la
imagen generada como imagen de salida del trazador de rayos.
2 Cámara
2.1 Generación de rayos
El primer paso es generar rayos desde el origen de la cámara hacia cada uno de los
píxeles de la imagen. En el caso de muestreo sencillo, se lanzará un solo rayo por cada
píxel de la imagen resultante, mientras que en el caso de súper muestreo, se lanzarán n2
rayos por cada píxel de la imagen, siendo n un parámetro configurable a la función de
render con súper muestreo. En nuestro caso, siempre hemos hecho el súper muestreo
con n = 3, por lo que hemos lanzado 9 rayos por cada píxel.
El proceso de generar un rayo desde el origen de la cámara hacia un determinado píxel
de la imagen, que viene dado por sus coordenadas de pantalla (u, v), consiste en:
-
El origen del rayo es el origen de la cámara en coordenadas del mundo
-
Calcular las coordenadas (x, y, z) del píxel hacia el que se lanza el rayo,
coordenadas del mundo, a partir de sus coordenadas de pantalla (u, v)
-
Calcular la dirección del rayo como la resta del punto (x, y, z) obtenido menos el
origen de la cámara en coordenadas del mundo, normalizando el resultado
2.2 Transformación de coordenadas de pantalla a
coordenadas del mundo
Para transformar las coordenadas de pantalla (u, v) en coordenadas del mundo (x, y, z)
se han realizado los siguientes pasos:
-
Se calcula la distancia de la cámara al plano de la imagen como:
d =
-
1 cos( yfov) 1
1
0 .5
= cot an( yfov) =
=
2 sin( yfov) 2
2 tan( yfov) tan( yfov)
Con esta distancia se obtiene en coordenadas del mundo el punto que está en el
centro de la imagen (este punto tiene como coordenadas de pantalla (0.5, 0.5), ya
que las coordenadas de la imagen están normalizadas entre 0 y 1), a partir del
origen de la cámara y el vector z de la misma, de la siguiente manera:
r
p _ screen _ center=origin − dz
-
A partir del punto central de la imagen en coordenadas del mundo, se obtiene la
esquina superior izquierda en coordenadas del mundo (este punto tiene como
coordenadas de pantalla (0.0, 0.0)), restando el vector x de la cámara (escalado
0.5 unidades) y restando el vector y de la cámara (escalado 0.5 unidades):
r
r
p _ screen _ origin= p _ screen _ center − 0.5 x − 0.5 y
-
El punto final se obtiene a partir de la esquina superior izquierda en coordenadas
del mundo, sumando los vectores x e y de la cámara, escalados por u y v,
respectivamente, como se muestra a continuación:
r r
p = p _ screen _ origin + ux + vy
3 Intersecciones
3.1 Intersección rayo-esfera
La primera intersección que se ha calculado ha sido entre un rayo y una esfera, para lo
que se ha consultado el libro de Matt Pharr, “Physical Based Rendering From Theory to
Implementation”.
Para calcular la intersección, se ha obtenido la ecuación del rayo en forma paramétrica:
p = ray.origin + t ·ray.direction
y se ha sustituido en la ecuación de la esfera:
( x − sphere. position.x) 2 + ( y − sphere. position. y ) 2 + ( z − sphere. position.z ) 2 = radius 2
de tal forma que se llega a la ecuación de segundo grado:
( p − sphere. position)T ( p − sphere. position) − radius 2 = 0
y resolviendo esta ecuación, se obtienen 0, 1 ó 2 soluciones de la misma. Interpretando
estas soluciones, se sabe si el rayo interseca la esfera en un punto (es tangente), en dos
puntos (corta a la esfera) o en ninguno (el rayo no interseca con la esfera). Además, nos
quedamos con la solución positiva que sea menor, para obtener el primer punto de
intersección del rayo con la esfera (la intersección en la parte frontal de la misma.
Por tanto, en caso de haberla, la intersección del rayo con la esfera se calcula evaluando
el rayo a la distancia t obtenida como solución de la ecuación de segundo grado
propuesta, la normal de la intersección es la normal de la esfera en ese punto, la
distancia es la solución obtenida t, y el material es el material de la esfera.
3.2 Intersección rayo-triángulo
Posteriormente, se ha calculado la intersección entre un rayo y un triángulo, consultando
también el libro de Matt Pharr, “Physical Based Rendering From Theory to
Implementation”.
En este caso, se han obtenido las coordenadas baricéntricas, de tal manera que un punto
p está dentro del triángulo si éstas están entre 0 y 1. Se han seguido los siguientes pasos:
1. Se obtienen las dos aristas del triangulo que inciden en v0: v1-v0 y v2-v0
2. Se calcula el producto vectorial entre la dirección del rayo y la segunda arista
3. A su vez, se calcula el producto escalar entre el producto vectorial que se acaba
de obtener en el punto 2, y la primera arista. Si el producto escalar es 0, el
triángulo es degenerado, por lo que no se produce intersección
4. En caso contrario, se obtiene el vector que va desde el origen del rayo hasta v0
5. Se calcula la primera coordenada baricéntrica como el producto escalar del
vector que se acaba de obtener en el punto 4, con el vector obtenido mediante el
producto vectorial descrito en el punto 2, todo ello dividido por el producto
escalar calculado en el punto 3
6. Si la coordenada baricéntrica es menor que 0, o es mayor que 1, el punto esta
fuera del triángulo y no se produce, por tanto, intersección
7. A continuación, se obtiene el producto vectorial del vector calculado en el punto
4 y la primera arista del triángulo
8. Se calcula la segunda coordenada baricéntrica como el producto escalar entre la
dirección del rayo y el vector obtenido mediante el producto vectorial descrito
en el punto 7, todo ello dividido por el producto escalar calculado en el punto 3
9. Si la coordenada baricéntrica es menor que 0, o la suma de las dos coordenadas
baricéntricas es mayor que 1, el punto esta fuera del triángulo y no se produce,
por tanto, intersección
10. Finalmente, se obtiene el punto de intersección t del rayo como el producto
escalar entre la segunda arista del triángulo y el vector obtenido mediante el
producto vectorial descrito en el punto 7
11. Se comprueba que el punto de intersección esta en los límites del rayo y se
calcula la intersección del rayo con el triángulo evaluando el rayo a la distancia t
obtenida como punto de intersección, la normal de la intersección es la normal
del triángulo, la distancia es la solución obtenida t, y el material es el material
del triángulo
4 Materiales
4.1 Lambertian
En el caso de los materiales lambertianos, se calcula únicamente la iluminación directa,
no habiendo en este caso reflexiones tipo espejo. La iluminación directa de los
materiales lambertianos no depende del punto vista, sino solamente del vector de
dirección de la luz y de la normal del punto al que llega dicha luz.
Fig. 1 – Iluminación difusa (Transparencias de TAG3D, curso 2007/2008)
Por tanto, la iluminación directa de este tipo de materiales se calcula como el producto
escalar del vector de dirección de la luz, L, y la normal del punto al que llega esta luz,
N, multiplicado por el color difuso del material.
4.2 Phong
En el caso de los materiales de tipo Phong, se calcula únicamente la iluminación directa,
no habiendo en este caso reflexiones tipo espejo. La iluminación directa de los
materiales de tipo Phong sí depende del punto vista, no solamente del vector de
dirección de la luz y de la normal del punto al que llega dicha luz.
Por tanto, la iluminación directa de este tipo de materiales se calcula como la suma de la
componente difusa (calculada como se acaba de explicar en apartado anterior) y la
componente especular.
Fig. 2 – Iluminación especular (Transparencias de TAG3D, curso 2007/2008)
Para calcular la componente especular, inicialmente se había calculado el vector
bisectriz H, calculado como la suma del vector de visualización V (este vector es igual,
pero de sentido contrario, que el vector de dirección de visualización I) y el vector de
dirección de la luz L, y normalizando el resultado. Después, se calculaba el término
especular como el producto escalar entre el vector normal del punto al que llega la luz,
N, y el vector bisectriz H, elevado al exponente especular, y multiplicado todo ello por
el color especular del material.
Fig. 3 – Iluminación especular (Enunciado de la práctica 2 de GPGPU, curso 2007/2008)
Sin embargo, haciendo los cálculos de esta manera, obteníamos resultados diferentes de
los proporcionados como material de apoyo a esta práctica, como se ve en la figura:
Fig. 4 – Resultados obtenidos inicialmente (izq) y resultados obtenidos finalmente (dcha)
Finalmente, se ha calculado la componente especular utilizando el vector de reflexión R,
calculado como R = 2(N·L)N – L, donde · denota el producto escalar. Después, se
calcula el término especular como el producto escalar entre el vector de reflexión R, y el
vector de visualización V, calculado negando el vector I, elevado al exponente
especular, y multiplicado todo ello por el color especular del material.
4.3 ShinyPhong
Puesto que la clase ShinyPhong es una clase que extiende la clase Phong, la iluminación
directa la obtiene de esta última clase.
En este caso, sí se produce reflexión, siendo ésta el atributo de color reflection de la
clase, definido en el fichero xml con la información del material correspondiente.
5 Luces
La dirección de la luz se calcula como el vector resultante de la resta entre la posición
de la luz y el punto de la superficie del objeto donde llega esta luz, y normalizando.
La intensidad de la luz viene dada por el atributo de color intensity de la clase Light.
La distancia de la sombra se calcula como la longitud del vector resultante de la resta
entre la posición de la luz y el punto de la superficie del objeto donde llega esta luz.
6 Renderizado de la escena
A la hora de renderizar la escena, en el caso de un rayo por cada píxel de la imagen, se
inicializa una imagen de la resolución especificada, y se recorren todos los píxeles
mediante dos bucles, generando un rayo por cada uno de estos píxeles, y calculando el
color final de dichos píxeles, dependiendo de los resultados devueltos al lanzar el rayo.
En el caso de súper muestreo, donde se lanzan n2 rayos por cada píxel de la imagen, se
inicializa una imagen de la resolución especificada, y se recorren todos los píxeles
mediante dos bucles y, a su vez, se recorren las n2 divisiones de cada píxel mediante
otros dos bucles, generando un rayo por cada una de estas divisiones, calculando y
acumulando el color final de dichas divisiones, dependiendo de los resultados devueltos
al lanzar el rayo. Finalmente, se hace la media del color acumulado de todas las
divisiones de un píxel, para obtener el color final de dicho píxel.
La forma de lanzar los rayos, tanto en el caso de un rayo por cada píxel de la imagen,
como en el caso de súper muestreo, se puede observar en la siguiente figura:
Fig. 5 – 1 rayo por píxel (izq), 22 rayos por píxel (centro) y 32 rayos por píxel (dcha)
Para comprobar si un rayo interseca un objeto de la escena (sea una esfera o un
triángulo), se ha implementado un bucle que recorre todas las superficies de la escena y,
en caso de que un rayo interseque con algún objeto de la misma, se queda con la
intersección de menor distancia.
Para calcular el color de un determinado píxel (o una determinada división de un píxel,
en el caso de súper muestreo) se utiliza la función computeColor. Primero se mira si el
rayo lanzado para ese píxel o para esa división de un píxel interseca con algún objeto de
la escena. Si no interseca, el color final es negro, mientras que si interseca hay que
comprobar, para cada luz de la escena, si el punto de intersección con un objeto está en
sombra con respecto a cada luz. Si está en sombra, no se suma nada al color final,
mientras que si no lo está, se va acumulando el color de la iluminación directa (difuso o
difuso + especular) obtenido en el punto de intersección entre el rayo lanzado y el
objeto con el que ha intersecado, multiplicado por la intensidad de la luz
correspondiente.
Además, hay que comprobar si el material tiene reflexiones (materiales ShinyPhong) y,
en caso afirmativo, generar un rayo (rayo reflejado) con origen el punto de la
intersección y dirección la dirección del rayo lanzado originalmente, reflejado a través
de su vector normal. En este caso, se suma la contribución de color de la reflexión entre
la normal de la intersección y la dirección del rayo original, multiplicado por el color
del rayo reflejado. El cálculo del color del rayo reflejado implica una llamada recursiva
a la función computeColor.
La función computeIllumination no se ha usado, puesto que se han realizado todos
los cálculos en la función computeColor.
Para saber si un punto está en sombra (no le llega ninguna fuente de luz), con respecto a
una determinada fuente de luz, se genera un rayo con origen en dicho punto y dirección
el vector de dirección de esa luz entre la posición de la luz y la posición del punto. Si el
rayo interseca con algún objeto de la escena, el punto está en sombra.
7 Resultados
En este apartado se muestran los resultados obtenidos con nuestro trazador de rayos
clásico implementado para esta práctica que, como se puede observar en las siguientes
figuras, se corresponden con los resultados proporcionados inicialmente como material
de base para la realización de esta práctica.
En las figuras que se muestran a continuación aparece a la izquierda el resultado
obtenido para cada escena lanzando un solo rayo por cada píxel de la imagen final, y a
la derecha el resultado obtenido para cada escena lanzando 9 rayos por cada píxel de la
imagen final.
Fig. 6 – Test01: Resultados obtenidos con 1 rayo por píxel (izq) y con 9 rayos por píxel (dcha)
Fig. 7 – Test02: Resultados obtenidos con 1 rayo por píxel (izq) y con 9 rayos por píxel (dcha)
Fig. 8 – Test03: Resultados obtenidos con 1 rayo por píxel (izq) y con 9 rayos por píxel (dcha)
Fig. 9 – Test04: Resultados obtenidos con 1 rayo por píxel (izq) y con 9 rayos por píxel (dcha)
8 Bibliografía
•
Wikipedia: http://en.wikipedia.org
•
Matt Pharr. Physical Based Rendering: From Theory to Implementation
•
http://www.dac.escet.urjc.es/rvmaster/asignaturas/TAG3D/08TAG3D%20RayTr
acing.pdf
•
http://www.dac.escet.urjc.es/rvmaster/asignaturas/GPGPU/PG_Practica02.pdf
•
http://www.realtimerendering.com/intersections.html
•
http://www.geometrictools.com/LibFoundation/Intersection/Intersection.html
Descargar