Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Iluminación Global: Mapa De Fotones

Iniciado por Ruben, 15 de Mayo de 2006, 06:18:15 PM

« anterior - próximo »

Ruben

 Hi,
estos meses, desde marzo mas o menos, he estado currando en un proyecto avanzado de la asignatura de graficos de la carrera de informatica de la uam.

Normalmente se suelen hacer unas practicas por cada asignatura, pero en algunas te dan la posibilidad de hacer un proyecto, si te ves con las suficientes ganas. Asi que como yo habia estado toqueteando desde hacia un tiempo con el tema de graficos, se lo comente a mi profesor y me emplazo a presentarle una serie de propuestas.

En un primer momento me dijo que lo que normalmente se hacia es el tipico ray tracer, pero como me parecia demasiado tipico le propuse un mapa de fotones. Me dijo que mucho animo y nada, me puse manos a la obra.

El mapa de fotones es un algoritmo de iluminación global de dos pases. Un primer pase consiste en crear el mapa de fotones, es decir, vas lanzando fotones de los focos de luz y por medio de algun tipo de metodo como la ruleta rusa, vas haciendo que reboten/reflejen/refracten/absorban.En un segundo pase, usas back ray tracing para saber el color de cada pixel. Pero en vez de hacer el calculo que se haria en un ray tracer, usas el mapa de fotones para saber la contribución de los fotones mas cercanos a ese punto.

Bueno, mas o menos y simplificando muchiiiiiisimo es eso. Normalmente el mapa de fotones se usa en conjunto con el monte carlo ray tracing. Es decir, el mapa de fotones se usa para iluminacion indirecta y causticas. El resto se usa el ray tracing.

Os voy a poner un render que he tirado justo despues de arreglar los fallos en el codigo de refraccion y reflexion. Ahora mismo estoy tirando mas renders para poner, y en cuanto arregle un par de fallos, subire los binarios para que destripeis la aplicacion sin piedad!!  (uoh)



En el render se ve una esfera totalmente transparente pero no refleja, un cubo rosa detras y un cubo azul como suelo, ambos totalmente difusos y opacos.

De todas formas, le faltan un monton de cosas y detalles (texturas, eficiencia, mejorar la interface de escena, etc...) aunque en 3 meses escasos no me ha dado tiempo a mas, teniendo en cuenta que trabajo y no solo tengo esta asignatura de practicas.

Aqui os dejo una captura del interface de configuracion de escena que he hecho. He reusado la gui que te viene en el sdk de directx.



Un saludo,
Rubén

Lord Trancos 2

 La unica pega que le veo es que parece que tiene bastante aliasing... el resto...  (genial)  muy chulo.
on los años y mucho esfuerzo he llegado a atesorar una ignorancia total sobre casi todas las cosas.
Gate to Avalon (mi Blog)

Ruben

 
Cita de: "Lord Trancos 2"La unica pega que le veo es que parece que tiene bastante aliasing... el resto...  (genial)  muy chulo.
te refieres por la ¿"esfera" ? Realmente el objeto no es una esfera perfecta. He usado la primitiva de directx para crear la malla de la esfera con 32 cortes(tanto slices y stacks). Una de las mejoras sería usar mis propias primitivas para las mallas.

De todas formas, si os fiajis en el "suelo" hay determinadas transiciones de colores que son muy bruscas. Esto es debido a los parametros de configuracion de escena: numero de fotones y radio de busqueda de foton vecino.

Este render creo que tiene solo 150k fotones y un radio de busqueda de 0.4. Cuantos mas fotones lances menor radio podras poner y mayor precisión tendras.


Haddd


ethernet

 Se ve muy bien. No controlo mucho del tema, pero no encuentro mucha diferencia entre lo que has contado y el rayracing. En el raytracing se lanzan rayos y en función de donde colisionen se reflejan/refractan/etc. que es lo mismo que has dicho con fotones. Podrías explicar las diferencias?

Ruben

 Hi,
voy a explicarlo algo por encima, asi que la gente que sepa por favor no me deis mucha caña.... :P

El trazado de fotones es exactamente igual al trazado de rayos excepto que el foton propaga el flujo de energia y un rayo recoge la "brillantez"("radiance"). Como supongo que no ha quedado nada claro, voy a explicar los dos algoritmos por encima. El trazado de rayos, lo paso muy por encima, ya que no lo he implementado aun (aunque planeo hacerlo :P ).

Mapa de fotones:
Un foton es un punto en el espacio con una energía determinada. La estructura es tal que asi: posicion, direccion, normal y energia. Este atributo nos dira la energia/intensidad que tiene cada foton del mapa de fotones. Normalmente se codifica como una terna de floats (r, g, b ).

Un objeto tiene estas propiedades:
-Factor difuso
-Factor especular
-Factor de opacidad
-Indice de refraccion

El mapa de fotones es el conjunto de fotones de la escena, que ya han sido lanzados y procesados.Ahora explicare en que consiste este proceso. Este mapa de fotones normalmente es una estructura espacial que nos permita una busqueda muy rapida: kdtree, por ejemplo.

El algoritmo de iluminación global por mapa de fotones consiste en dos pases:
1) Trazado de fotones:
Para cada foco de luz, se emiten(lanzan) una cantidad de fotones a la escena. Se pueden elegir entre multitud de formas de distribución, la más comun es la de Monte Carlo. Cada uno de estos fotones tendran una energia inicial inversamente proporcional al numero de fotones que se van a lanzar. Esto nos asegura que la energia es igualmente distribuida a lo largo de la escena.

Ahora, cuando hemos lanzado nuestro foton pueden pasar dos cosas: o bien que no encuentre ningun objeto en la escena, por lo que ese foton se perdera, o bien (y lo mas interesante :P ) que interseccione con algun objeto. Cuando intersecciona un objeto tenemos varias posibilidades, dependiendo de las propiedades del objeto. El fotón puede ser reflejado, transmitido o absorbido. Esto se decide de una forma probabilistica segun el metodo de la ruleta rusa. Es decir, se elige un numero aleatorio entre 0 y 1:

a ) Si el numero es menor que el factor difuso del objeto, estamos en el caso de una reflexion difusa. Por lo tanto el foton se almacena en el mapa de fotones con la posicion siendo la interseccion y la energia siendo el color de la luz que lo ha emitido por el factor de opacidad. Además se emite un foton nuevo, que simulara la transmision de color entre objetos, con direccion una aleatoria (teniendo cuidado que no apunte al interior del objeto) y energia la del foton absorbido multiplicada por el color del objeto y su factor difuso. Para este foton nuevo se repite el proceso de trazado (recursivamente o por iteraciones).

b ) Si el numero esta dentro del intervalo del factor difuso y especular, estaremos ante una reflexion o refraccion, dependiendo del factor de opacidad. Si el foton es reflejado, no se guarda en el mapa de fotones, y se lanza de nuevo con una direccion calculada por la tipica formula de reflexion fisica(si la quereis me lo decis que ahora no me acuerdo) y con la energia multiplicada por el color del objeto y su factor especular. Y lo mismo pasa si es refractado, exceptuando que hay que lanzarlo a traves del objeto, teniendo en cuenta indices de refraccion tanto para la entrada como para la salida. Igualmente no se guarda en el mapa de fotones. Estos fotones serviran para visualizar las causticas.

c ) Si el numero es mayor que el factor difuso mas el factor especular, el foton es "asesinado" :P, vamos que se absorbe en esa posicion, con la energia multiplicada por el factor de opacidad de ese objeto, si el objeto es (algo) opaco o (algo) difuso.

Como veras el foton lleva una energia inicial y la va propagando a traves de la escena. Mientras que, como luego explicare, el rayo va ganandola.

2) Visualizacion del mapa de fotones:
Ahora que tenemos un mapa de fotones con sus energias y posiciones, llega la hora de usarlo para renderizar la imagen. Lo que se usa es algo parecido al back ray tracing. Se lanza un rayo por cada uno de los pixeles de la "pantalla" y se comprueba la interseccion con los objetos de la escena. Si ese rayo no intersecciona a un objeto, el color del pixel sera negro. En el caso de que interseccione se estima la densidad en ese punto. Esto se lleva acabo, encontrando los fotones mas proximos al punto con una cierta distancia  y/o numero de fotones encontrados de limite. Luego se calcula la contribucion energetica de cada uno de estos fotones y ya tenemos el color del pixel.

Este es el algoritmo en su forma mas simple. Luego Henrik Jensen, el autor de este algoritmo, nos explica que para sacarle el maximo provecho se debe de implementar una solucion mezclando mapa de fotones y ray tracing, ademas de usar filtros, formulas de distribucion de fotones mas eficientes, etc...

Realmente lo bueno que tiene el mapa de fotones es que para las causticas y la iluminacion indirecta es mucho mejor que el ray tracing. De hecho con apenas 20k fotones tienes unas causticas muy reales.

Ray tracing:
Basicamente lo que hace el trazado de rayos, es lanzar un haz de rayos por cada pixel de la "pantalla". Cuando un rayo intersecciona a un objeto difuso se calcula en ese punto un factor de iluminacion que coloreara al pixel. Este factor de iluminacion vendra dado por cada luz de la escena y el color del objeto. Si el objeto es especular o transparente, el rayo se refleja o refracta y se vuelve a hacer lo mismo. Ademas, existen otro tipo de rayos para calcular las sombras, aunque por lo que he visto se han de usar un monton de rayos para conseguir un resultado decente.

De momento eso es lo que os puedo decir, sin miedo a equivocarme mucho del ray tracing. Si quereis mas info buscarla aqui. Es un tutorial de como hacer un ray tracer.

Espero que te haya aclarado algo ethernet, si tienes mas dudas pregunta! :D ya sabes que cuando alguien ha hecho algo esta encantado de explicarlo hasta la extenuacion... :P

Un saludo,
Rubén

PD: aqui teneis el render que os habia dicho antes, acaba de terminar ahora. :P Me estoy fijando y no tiene causticas... habre configurado mal las propiedades de la esfera. Voy a ver si tiro un render con causticas, que quedan muy chulas :D


Marci

 Muy chulo. Cuanto puede tardar el render de una escena como las que estas mostrando?

Ruben

 
Cita de: "Marci"Muy chulo. Cuanto puede tardar el render de una escena como las que estas mostrando?
Pues exactamente no te se decir, pero para el render del primer post unos 30 minutos. Para el segundo unas 2 o 3 horas.

De todas formas, no esta para nada optimizado. Habría que mejorar el sistema de intersecciones (he usado la funcion de D3DX de interseccion), creando yo mismo las funciones de interseccion con las primitivas. Teoricamente, no es para nada complicado y deberia mejorar bastante el tiempo.

Tampoco me ha dado tiempo a mas, la verdad. Ahora hay un monton de cosas por mejorar y hacer. Por ejemplo, las refracciones no son del todo fisicamente correctas, ya que no he tenido en cuenta la Ley de Beer para la transmision de luz... o meterle texturas... o mejorar la primitiva de esfera y que sea realmente una esfera...

Por cierto, aparte de por el proyecto en si, estoy bastante orgulloso por que este es el primer proyecto "complejo" que acabo y mi segundo en esto de los graficos.  :)  

ethernet

 Muy interesante la explicación, tengo que masticarla :)

Marci

 [OFFTOPIC]
Creeis que algún dia sera posible ray tracer o fotones por GPU en tiempo real? (uoh)
[/OFFTOPIC]

Ruben

 
Cita de: "Marci"[OFFTOPIC]
Creeis que algún dia sera posible ray tracer o fotones por GPU en tiempo real? (uoh)
[/OFFTOPIC]
Hay cantidad de ray tracers implementados integramente en la GPU y renderizan en tiempo real.

En cuanto a mapa de fotones, aun estan sacando papers que explican como hacerlo en tiempo mas o menos real, aunque se acercan un monton les queda bastante. Si te interesa, busca algun paper de Purcell.


Ruben

 Hi,
he mejorado algunas cosillas y arreglado otras.

Lo mas destacable es que las esferas ahora, son perfectas. Esto se podia conseguir de dos formas, o bien interpolando las normales de los vertices de la malla de la esfera para obtener la normal en el punto de interseccion. O usar un par de calculos vectoriales para obtener el punto de interseccion y la normal. La primera opcion la implementaba con una funcion de intersecion de d3dx, por lo que con tantas caras relentizaba muchisimo. En cambio, con la segunda opcion, va m�s rapido y los resultados son iguales.

Además, he usado interpolacion lineal para sacar la normal en el punto de interseccion para objetos que usen el metodo de interseccion de d3dx. Basicamente, tengo una clase cModelo3d que implementa un metodo virtual getInterseccion(), implementado con D3DXIntersect(...). Luego tengo clases que heredan de esta clase como cEsfera, cTetera, ... Para primitivas, sobreescribo el metodo y para el resto uso el heredado. Esto implica que ahora los objetos "complejos", como la tetera, tendran un aspecto suavizado y no con "caras visibles" como se puede apreciar en las esferas y teteras de los renders que puse al principio.

Aqui teneis algunas imagenes en donde se pueden apreciar, por ejemplo, las causticas que producen objetos transparentes y reflexivos.








Este fin de semana intentare retocar las ultimas cosillas, y poner aqui el binario para que lo probeis y me digais que os parece. Por cierto, ¿donde podría subir un zip con el binario?

Un saludo,
Rubén

Marci

 
CitarEste fin de semana intentare retocar las ultimas cosillas, y poner aqui el binario para que lo probeis y me digais que os parece. Por cierto, ¿donde podría subir un zip con el binario?
Yo tengo sitio libre. Si quieres me lo mandas y lo cuelgo.

Ruben

Cita de: "Marci"
Yo tengo sitio libre. Si quieres me lo mandas y lo cuelgo.
Muchas gracias! :D

En cuanto le de un par de retoques mas, te lo mando.


tamat

 Me ha hecho ilusion ver este thread. Primero de todo felicitarte por tu trabajo, tiene un acabado perfecto.

Yo tambien programé un sistema de fotones para mi raytracer (screenshot). Veo que has usado kdtrees, yo al final dudé y lo hice mediante lighmaps para almacenarlos y el resultado era sensiblemente inferior.
Uno de los ejemplos en los que se ve la potencia del algoritmo era haciendo causticos sobre agua, basta con que lances los fotones contra una superficie que los perturba en función de un perlin noise o una sinusoidal y la escena queda muy chula.

Te recomiendo que uses la clasica cornellbox para las pruebas, suele quedar muy bien y es un momento.

Por cierto, una pregunta, tú como resuelves el tema de la luz especular?

Un saludo.
Por un stratos menos tenso






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.