Generación de Imágenes Fotorealistas Utilizando Paralelismo Edgar BENAVIDES MURILLO, Carlos A. VARGAS-CASTILLO Escuela de Ciencias de la Computación e Informática, Universidad de Costa Rica (UCR) San José – Costa Rica [email protected], [email protected] RESUMEN Se propone la utilización de paralelismo, como mecanismo para lograr una reducción efectiva del tiempo requerido para generar imágenes sintéticas fotorealistas, en la implementación del algoritmo de mapeado de fotones, el cual se caracteriza por su capacidad para simular efectos especiales. En la implementación se reemplaza el KD-Tree, como estructura de almacenamiento de fotones, por una estructura de block-hash para organizar la información de la estimación de la radiancia, como mecanismo más apropiado para ejecución utilizando un cluster de computadoras. Además, se describen las bibliotecas externas utilizadas, las rutinas básicas necesarias para crear el algoritmo y las técnicas de paralelismo utilizadas. Palabras Claves: Gráficos por computadora, algoritmo, mapeado de fotones, paralelismo, iluminación global, imágenes fotorealistas. 1. INTRODUCCIÓN La generación de gráficos por computadora es un área de investigación cuyo objetivo es la creación de algoritmos y métodos que permitan generar una imagen sintetizada artificialmente en un computador. A esta generación de imágenes a partir de un modelo de iluminación global se le llama síntesis de imágenes [4]. El realismo en graficación por computadora es definido como la producción de una imagen indistinguible de una fotografía del correspondiente lugar. Para lograrlo, es necesario simular la interacción de la luz con las superficies de acuerdo con las leyes de la Física [12]. De esta manera, el fenómeno de la interacción de la luz en las superficies es simulado mediante un modelo matemático. Entre mayor sea la correspondencia del modelo con la teoría física, mayor será el realismo exhibido por la imagen generada en el computador. Investigaciones pioneras en modelos de iluminación global inician con los trabajos de Arthur Appel, quien ideó una técnica de rayos para determinar sombras y zonas ocultas de los objetos. También Goldstein y Nagel usaron una técnica similar derivada de la simulación de proyectiles balísticos y partículas atómicas [6]. Posteriormente se le denominó algoritmo clásico de raytracer a la propuesta de Ted Whitted [13], que consistía en usar una técnica recursiva para trazar el recorrido de los rayos de luz, y simular efectos como sombras, reflexión y refracción. Sin embargo, en un raytracer no se calculan las interreflexiones difusas de la luz entre superficies. Simplemente se le simula mediante un término constante, lo que constituye una limitación hacia el fotorealismo. El algoritmo Radiance supera esta limitación al reemplazar el término constante, por un complejo y costoso cálculo de inter-reflexiones [3], que se basa en la ecuación de rendering, propuesta por James Kajiya [10]. Mediante esta ecuación es posible comprender, a través de una formulación basada en las ecuaciones de Maxwell para electromagnetismo, la distribución de la luz en las superficies. Su importancia reside en que permite caracterizar el mecanismo de iluminación global desde el punto de vista de flujos de energía lumínica y de esta manera, unificar las diferentes formas de calcularla en torno al concepto de radiancia. Existen varios algoritmos que permiten calcular la iluminación global. Uno de estos se denomina Mapeado de Fotones [8], el cual permite modelar varios efectos especiales en la imagen generada, resaltándose los efectos cáusticos 1. Este algoritmo pertenece al grupo de métodos que resuelven el problema de la iluminación global en dos pasos y que incorporan de manera unificada los raytracer y la radiancia . La estructura habitualmente utilizada es el KD-Tree, que es un tipo de árbol para almacenamiento de datos multidimensionales [9]. En la implementación del prototipo, se reemplaza el KD-Tree por una estructura de block-hash [11], para organizar la información de la estimación de la radiancia, como mecanismo más apropiado para lograr una ejecución efectiva en paralelo, utilizando múltiples nodos de un cluster 2 de computadoras. Para construir la estructura de almacenamiento de fotones se utiliza una función de dispersión creada especialmente a partir de la curva de Hilbert 2]. La curva de Hilbert tiene como propiedad el ser una curva fractal, que posibilita llenar un espacio en tres dimensiones. Las curvas de Hilbert son utilizadas por su propiedad de preservación de la localidad, lo que permite el mapeado de datos multidimensionales a una sola dimensión. A nivel de hardware, en los últimos años se ha puesto un gran énfasis en la utilización de múltiples núcleos de procesamiento para mejorar el tiempo de ejecución de las mismas. Actualmente el uso de varios núcleos de ejecución, en una sola CPU, está presente incluso en computadores PC para el hogar. Mucho de este poder computacional apenas se está empezando a descubrir [1,7]. Uno de los retos que se presentan a la hora de incorporar estos modelos en un computador es la gran cantidad de cálculos necesarios para calcular la iluminación global. Esta es una de las razones por las cuales el objetivo de generar imágenes de manera eficiente se mantiene vigente [5]. Por tanto, 1 Los efectos cáusticos en óptica se refieren a la concentración en un punto de la refracción o reflejo de rayos a través de una superficie curva, como puede ser una copa de cristal conteniendo algún líquido. 2 El término cluster se refiere a un conglomerado de computadoras que se construye utilizando distintos componentes de hardware que permiten elaborar procesos de cálculo, generalmente complejos, considerando el conglomerado como una unidad computacional. el uso de paralelismo, permite solucionar estos problemas en un tiempo razonable [3]. 2. IMPLEMENTACIÓN DEL ALGORITMO. El algoritmo de mapeado de fotones pertenece a la categoría de algoritmos híbridos de dos pasos, los cuales hacen uso de varias técnicas para producir una imagen sintética foto-realista. Por ello, se requiere implementar dos procesos de trazado de rayos, en vez de solamente uno, como sucede con un raytracer clásico. El primer raytracer se utiliza para trazar la trayectoria de los fotones, emitidos desde una fuente de luz, para construir con la información generada un mapa de fotones. El segundo raytracer lleva a cabo el renderizado final, lo cual conlleva calcular la radiancia incidente en cada uno de los pixeles definidos en el plano de proyección, utilizando para ello el mapa de fotones previamente generado. Para almacenar en un archivo binario el resultado de la generación de la imagen se seleccionó TARGA2, el cual es un formato de archivo de imágenes comúnmente utilizado en varias plataformas. Se creo una biblioteca de funciones para manejar la lectura y escritura de archivos de imágenes en dicho formato. La implementación del prototipo se programó en lenguaje C++, debido a que la corrida del programa resulta más eficiente en comparación con lenguajes interpretados, al ser código binario. Además, C++ permite ligar el programa con las bibliotecas MPI3, de forma directa, tanto en sistemas operativos Windows como en Linux, lográndose así gran flexibilidad. Otro detalle importante es que se utilizan las funciones y estructuras estándar de C++, llamada STL (Standard Template Library). Este recurso, presente en casi todos los dialectos de C+ +, permite construir estructuras de datos personalizadas de una manera bastante eficiente. Se utilizó STL para construir el mapa de fotones usando “block- hashing”. 2.1 Descripción de la escena El algoritmo requiere una definición de escena como punto de partida para poder producir la imagen final. Esta definición es almacenada en un archivo de texto, siguiendo una sintaxis particular, desarrollada especialmente para este propósito, mediante la cuál se describe la geometría de los objetos, los materiales y texturas, y la ubicación de los mismos, así como la caracterización de los elementos especiales, tales como la cámara y las fuentes de luz. En este archivo se especifican: • materiales: el material es utilizado para definir el color y la textura de los objetos, y para compartir la información entre los objetos que conforman la escena • primitivas geométricas: definen la forma y la ubicación espacial del objeto, ya sea mediante una serie de puntos, o mallado, o una ecuación cuadrática, como en el caso de una esfera • fuentes de luz: se utiliza la definición de luz puntual, entendida como un punto en el espacio. • cámara: la especificación de la posición de la cámara, su tipo y los parámetros asociados a esta, también son incluidos en el archivo de definición de la escena. 3 Message Passing Interface, Interface para el envío de mensajes. Consiste en un mecanismo estándar creadopara el paso de mensajes entre procesos independientes de un cluster de computadoras. La especificación se encuentra en: http://www.mpi-forum.org/ Tanto los archivos de definición de la escena, así como la representación de esta almacenada en memoria, soportan la inclusión de una cantidad variable de materiales, de primitivas, y de fuentes de luz. La cámara permite situársele en cualquier lugar dentro del espacio virtual. El módulo que utiliza la estructura de datos que almacena la definición de la escena proveé funciones y métodos para iterar sobre las luces puntuales y sobre los objetos geométricos de la escena. Además, permite acceder la información de los materiales y de la cámara. El iterador de objetos geométricos es utilizado para recorrer cada uno de los objetos definidos y verificar si un rayo exploratorio, o un trazo de fotones, interseca una figura geométrica particular. El iterador de luces es importante para el cálculo de la iluminación directa, puesto que es aquí en donde hay que verificar las sombras y la cantidad de luz con la que contribuye cada una de las luces definidas en el modelo de la escena. La emisión de fotones y el trazado de la ruta de los mismos dentro de la escena es el primer paso del algoritmo. El resultado de esta primera fase es un mapa de fotones, que consiste en una estructura de datos que almacena información de cada fotón, conservándola para utilizarla posteriormente, durante la segunda fase del algoritmo. A continuación se describen los detalles más relevantes de la implementación de este algoritmo. 2.2 Primera fase: trazado de la trayectoria de fotones En el primer paso del algoritmo se emite una gran cantidad de fotones, desde las fuentes de luz, y se traza para cada uno de ellos la ruta a través de la escena. La información de cada intersección entre el rayo de la ruta y la superficie del objeto intersectado se almacena en una estructura de datos. Para decidir el primer trazo, se establece un rayo cuyo punto inicial está situado en el emisor de luz. La dirección del mismo se elige usando un método de búsqueda aleatoria. Esto se realiza usando un punto cualquiera en la esfera de radio uno, circundante al punto emisor de luz. En la figura 1, se muestra el mecanismo seguido por este primer paso del algoritmo. Este método de escogencia se conoce como método por rechazo, debido a que se elabora un ciclo que evalúa si el punto está dentro de la esfera. Si no se cumple, entonces se generan nuevos números aleatorios, hasta lograr construir otro vector de dirección que sí lo logre. emi t_photons_f rom_diffuse_point_light ( ) { emit = 0 whi l e ( no hay s u f i c i e n t e s f o t on e s ) { do { eps i lon_1 = número a l e a t o r i o ent r e 0 y 1 x = 2_ epi s i l on_1 - 1 eps i lon_2 = número a l e a t o r i o ent r e 0 y 1 y = 2* epi s i l on_2 - 1 eps i lon_3 = número a l e a t o r i o ent r e 0 y 1 z = 2* epi s i l on_3 - 1 } whi l e ( x^2 + y^2 + z^2 > 1 ) direccion=<x,y,z> p o s i c i o n = posicion de la fuente de luz emisora trazar fotones desde p o s i c i o n hacia d i r e c c i o n . emit = emit + 1; } escalar la potencia de los fotones almacenados por 1 / e m i t } Figura 1: Emisión de fotones. aleatoria de rayos de manera independiente. Esto significa que, el trazado del rayo de fotones elaborado por el proceso i es independiente del trazado de la ruta del proceso i+1. De esta manera, cada uno de los procesos traza un rayo en la dirección aleatoria de su elección, y cuando este termina, se comunica a los procesos coadyuvantes los datos que fueron calculados en el proceso de trazado. Los procesos reconocen en la cola de entrada aquellos datos provenientes de otros procesos, que ocupan incluir al mapa de fotones, y proceden a sacarlos de la cola de procesos. Se finaliza cuando se llena la tabla de fotones o no hay más fotones que trazar. Esta forma de proceder está acorde a un modelo de computación paralela del tipo híbrido [3]. El proceso, implícitamente, divide los datos homogéneamente entre los distintos procesadores participantes, lo que lo hace un mecanismo de computación paralela guiada por los datos. Esto es así aunque no se conoce a priori cuántos y cuáles fotones van a ser almacenados en la estructura de datos. Además, por las características del proceso, se trata de un algoritmo paralelo conducido por demanda: los fotones se van emitiendo conforme se tiene oportunidad de generarlos en el algoritmo, para así prevenir que un proceso se quede inactivo. Con esta estrategia, ningún procesador queda inactivo durante el trazado de los fotones. En la figura 2 se presenta el algoritmo paralelo que se sigue en el caso del trazado de fotones. Con este rayo se calcula la intersección del mismo con alguno de los objetos de la escena. Para todas las intersecciones del rayo con los objetos de la escena, obtenidas estas mediante el seguimiento de la ruta del fotón en la escena 3D, si el rayo interseca una superficie no especular, el algoritmo calcula y guarda en la estructura de fotones la información relativa a la intersección del rayo con la superficie. Esta información incluye datos como la dirección del fotón, la energía que transporta, y el punto de intersección. En el caso de que la intersección ocurra con un objeto que posea reflexión especular, la información no se almacena en el mapa de fotones. Esto debido a que este tipo de reflexiones son manejadas más eficientemente mediante el uso de la iluminación directa. Los trazos son iniciados en la fuente de luz, y, en donde ocurra una reflexión con una superficie difusa, se almacena la información de la intersección en el mapa de fotones. En el caso de ocurrir una intersección con una superficie de reflexión especular, solamente se computan los cálculos para rebotar el rayo hacia la dirección correcta. Para todo fotón es necesario calcular la siguiente dirección de rebote del fotón. El fotón puede seguir su travesía por tres caminos distintos: puede reflejarse, refractarse o ser absorbido por el material. Se utiliza un mecanismo basado en un método de escogencia aleatorio en donde se involucra el tipo de material subyacente a la intersección para decidir, cual función BRDF4 utilizar de acuerdo a un número aleatorio generado para tal decisión. El material es el objeto que contiene la información que define el tipo de reflectancia aplicable al punto de la superficie para calcular la siguiente ruta del fotón. Antes de proceder a calcular el tipo de reflectancia del nuevo trazo del fotón, conviene saber si el fotón es reflejado a una nueva dirección o si es absobido. Esto se realiza considerando el método de ruleta rusa, que consiste en determinar mediante una probabilidad y un número aleatorio si el fotón es absorbido, o no. Diversos tipos de funciones BRDF pueden ser definidas. Para este prototipo se usaron las reflexiones difusas, las especulares y la refracción o transmisión de la luz, en el caso de materiales transparentes. La refracción es importante en los objetos transparente para poder producir los efectos cáusticos que constituyen un elemento característico del algoritmo de mapeo de fotones. Para el cálculo de la dirección determinada por la reflexión difusa, la nueva dirección del fotón se calcula buscando un punto aleatorio en el hemisferio superior, centrado en el punto de intersección. En este caso, se asume que la reflexión difusa es aleatoria con distribución normal. En el caso de la reflexión especular, se utiliza el hecho de que la reflexión especular pura siempre refleja en una dirección específica, que está determinada por un ángulo de reflexión. Para los objetos transparentes, la nueva dirección del fotón se calcula usando la ley de Snell. t r a z a_f o t o n ( Rayo viewRay ) { level=0 photons = 0 do { h i t p o i n t = bus ca i n t e r s e c c i ó n d e l r a yo con o b j e t o en e s c ena . i f ( r u s s i a n_r o u l e t t e ( ) ) { absorb_photon ( ) exit loop } else{ f o t o n = c o n s t r u y e e l f o t o n con l o s da t o s de l a i n t e r s e c c i o n AddPhoton ( f o t o n ) // adiciona foton a la estructura i f ( no_caben_mas_fotones ( ) ) { exitloop } MPI . broadcastPhoton ( f o t o n ) // Colabora con los //demas procesos MPI . receiveCollaboration ( ) // Recibe la col aboracion // de otros procs . viewRay = nuevo rayo reflejado desde el pto de interseccion. } viewRay = Calcula nuevo rayo reflejado (segun BRDF) l e v e l = l e v e l +1 } wh i l e ( l e v e l < 10 ) } 2.3 Paralelización del trazado de fotones Figura 2: Algoritmo de trazado de fotones en paralelo. El primer paso para paralelizar el trazado de fotones consiste en replicar el mapa de fotones en cada uno de los procesadores asignados a una ejecución particular. El algoritmo inicia el trazado de la ruta tomando una dirección aleatoria en el hemisferio cuyo origen está centrado en la posición de la luz, suponiendo que todos los procesos elaboran una búsqueda 2.4 Segunda fase: renderizado. 4 Función bidireccional de distribución de la reflectancia La base fundamental para implementar un algoritmo de mapeo de fotones es disponer de la mecánica básica para el trazado de rayos. Para computar la imagen, es necesario atribuirle un valor a la radiancia Lpixel incidente sobre cada pixel de la imagen. El algoritmo inicia con un recorrido sobre todos los pixeles definidos para el plano de proyección en donde se visualizará la imagen final. La figura 3 muestra el procedimiento de dividir el plano de proyección usando una cuadricula de pixeles. El rayo exploratorio de la radiancia se traza en algún punto dentro de cada pixel y se busca la intersección con algún objeto en la escena. Figura 3: Pixeles definidos en un plano de proyección. La figura anterior muestra una ampliación del tamaño real de un pixel en pantalla. Por consistencia con el concepto matemático de punto, resulta adecuado para el modelo hacer pasar el rayo por el centro del pixel, esto es, dada la celda (x, y), el rayo pasará por el punto (x+0.5, y+0.5) Para obtener una estimación correcta de la radiancia, asociada a un pixel en particular, se utilizó la técnica del supermuestreo. En la figura 4, puede verse una división más fina del área de un pixel. En el primer caso, a la izquierda, se observa lo que constituye la muestra de la radiancia que pasa por el centro del pixel. Para computar la iluminación directa se trazan rayos desde el punto de intersección hasta las fuentes de luz. Si el rayo de prueba no interseca con ningún objeto opaco, entonces la luz ilumina directamente el punto de intersección. Estos rayos se conocen como rayos en sombra. computeImage ( ojo ) { LOOP para cada pixel { radiancia=0 obt ene r un conjunto de muestras aleatorias del pixel . para cada muestra { determinar e l punto p correspondiente a la muestra construir un rayo ray cuyo origen = ojo y direccion = p _ ojo r a d i a n c i a = r a d i a n c i a + rad ( ray ) } r a d i a n c i a = ( r a d i a n c i a ) / ( no . mues t ras ) } } rad ( ray ) { busque l a i n t e r s e c c i o n mas c e r cana de l rayo con l a e s c ena ( punto x ) computeRadiance ( x , ojo - x ) } Figura 5: Lanzamiento de rayos primarios. La figura 6, muestra un diagrama esquemático del cálculo de los rayos en sombra para tres fuentes de luz distintas representadas en la figura como estrellas amarillas. Para un punto de intersección cualquiera en la superficie de un objeto, se traza un rayo hacia la fuente de luz representadas en la figura por una estrella amarilla. El rayo sombra A logra encontrar una vía libre entre el punto de intersección y la fuente de luz, por tanto, su contribución es total. El rayo B, es obstruido por un objeto opaco y por tanto su contribución es nula. En el caso del rayo C, al igual que el A, también encuentra una vía libre hacia la tercera fuente de luz. Figura 4: Muestreo de un pixel (supersampling). Este tipo de muestreo no da un resultado lo suficientemente realista. El segundo caso resulta demasiado regular. Este tipo de muestreo, aunque es mejor que el del punto medio, no permite capturar cambios sutiles que pueden existir entre dos muestras distintas. En el tercer caso, la distribución de las muestras es aleatoria, lo cual permite una mejor aproximación a la radiancia del pixel. El siguiente algoritmo de la figura 5, permite generar los rayos primarios derivados del patrón de muestras definido, que parten desde el punto donde está localizada la cámara, hacia la escena, pasando por el plano de proyección. La computación de la radiancia se realiza sumando dos partes independientes: la iluminación directa y la iluminación indirecta. La iluminación directa se refiere a aquella iluminación que llega sin obstáculos desde la fuente de luz. Figura 6: Rayos en sombra. Si la sombra no existe, o si es atenuada por un objeto semitransparente, entonces la radiancia estimada se calcula como la radiancia equivalente a tomar la luz directa de la fuente de luz y multiplicarla por la función BRDF, asociada al objeto en donde se encuentra situado el punto de intersección. El algoritmo para ejecutar el cálculo es mostrado en la figura 7. El cálculo de la la luz indirecta resulta más complejo que el de la directa. La luz indirecta consiste en un estimado de todos los otros rayos de luz que no son directamente emitidos por alguna de las fuentes de luz, sino que son reflejados por otras superficies, ya sea por reflexión difusa o especular. En esta parte del algoritmo es en donde se utiliza el mapa de fotones, debido a que precisamente la luz indirecta es mejor calculada mediante una estimación de la radiancia incidente. direct Illumination ( x , the ta ) { estimatedRadiance = 0 LOOP sobre todas las fuentes de luz definidas { y = punto de ubicación de la luz shadow = opacidad existente entre el punto y y el punto x s i shadow > 0 { #samples++ es t imatedRadiance += Le (y , yx ) _ BRDF } } estimatedRadiance = estimatedRadiance / #samples } Figura 7: Cálculo de la iluminación directa. La ecuación de cálculo de la radiosidad en los pixeles del plano divide la radiancia en dos partes: la contribuida por la luz directa y la contribuida por la luz indirecta. Para lograr mejores resultados se divide la luz indirecta en tres categorías más: luz indirecta por reflexiones especulares, luz indirecta por cáustica, y otras contribuciones de la luz debidas a reflexiones difusas. i n d i r e c t I l l umi n a t i o n ( x , the ta ) { es t imatedRadiance = 0 s i ( no absorbe ) { determina l a r e f l e x i ó n debida a l ma t e r i a l s i r e f l e x i o n e s e sp e cu l a r o t r ansmi s i on { c a l c u l a nuevo rayo basado en la BRDF es t imatedRadiance = computeRadiance ( x , nuevaDir ) * BRDF } si reflexionescaústica{ est imatedRadiance = CausticsPhotonMap ( x ) } si reflexionesdifusa{ estimatedRadiance = GlobalPhotonMap ( x ) } } r e turn ( estimatedRadiance / (1 - prob . abs o r c i on ) } Figura 8: Cálculo de la iluminación indirecta El algoritmo propuesto requiere considerar el tipo de material del objeto en el que se encuentra el punto de intersección. Cuando el material es especular o transparente el rayo es entonces trazado de nuevo mediante el raytracer, con una dirección determinada, condicionada por el tipo del material. El algoritmo para el cálculo de la iluminación indirecta se illustra en la figura 8. 2.5 Paralelización de la fase de renderizado Para incorporar la ejecución paralela en la fase de renderizado, se utiliza la técnica de raytracer por demanda. Se establece un procesador como el maestro, el cual recibe peticiones de asignación de trabajo por parte de los procesos esclavos. Cuando el maestro recibe una petición, este envía una tarea para realizar cálculos. El proceso esclavo recibe la asignación de la tarea y comienza la generación de muestras para el pixel asignado. Al finalizar el muestreo, el proceso esclavo envía de vuelta al proceso maestro la computación de la radiancia del pixel en cuestión. El proceso maestro continúa asignando las tareas de computar la radiancia asociada a pixeles de la imagen, hasta que se agoten. En este momento, los esclavos reciben la notificación de detener la computación de la radiancia y el maestro entonces reasume los cálculos, almacenando el plano de proyección completo en un archivo binario de imagen, para su posterior lectura. En términos de MPI, el proceso número 0 se utiliza como maestro, encargado de coleccionar los datos que le envían los esclavos numerados de 1 a N. En la figura 9, se muestra el algoritmo de renderizado en paralelo con las diferentes tareas, tanto para el proceso maestro como para el proceso esclavo, las cuales se diferencian por el número del proceso. radiance_int e g r a t o r ( ) { i f ( rank i s master ) { f o r i = 1 to Máximo procesos loop coord = nuevas coordenadas de pixelacalcular envía a l proceso i las coordenadas iniciales coord end loop whi l e ( obt iene el resultado del esclavoi ) { i f ( hay nuevas coordenadas ) { obtiene nueva coordenada de p ixel envia al proceso que termino nuevas coordenadas coloca resultado en el plano de proyeccion resultante } else{ finalizaelesclavo i } } guarda imagen resultante } else { // esta parte es ejecutada por los procesos esclavos i f ( r e c ibeCoords ( coords ) ) { pixColor = Raytrace ( coords ) Envia pixColor al maestro como resultado } } } Figura 9: Algoritmo de renderizado en paralelo. En el algoritmo lo primero que se hace es enviar, a todos los procesos, los primeros cálculos que se tienen que realizar. Luego, el proceso maestro entra en modo de escucha, donde, por cada resultado que recibe de los esclavos, guarda el resultado en el plano de proyección y envía una nueva coordenada de trabajo. Si no tiene más coordenadas para trabajar, entonces el maestro le indica al i-ésimo proceso la finalización del trabajo. Cuando todos los procesos esclavos han finalizado, el maestro procede a guardar la imagen resultante y a finalizar todos los trabajos. 3. RESULTADOS DE LA EJECUCION En la figura 10, se aprecian cuatro efectos especiales en una imagen generada con el prototipo implementado. La esfera roja del fondo produce un efecto de sombra roja reflejada, producto de la transferencia de la radiancia con la que se cargan los fotones al rebotar en la superficie de la esfera. Por su parte, las paredes, al estar localizadas en la zona profunda de la escena, muestran un color difuminado, producto de la mayor incidencia de fotones cargados con energía lumínica, en las partes más cercanas a la luz. El algoritmo también produce las habituales sombras, derivadas de su herencia del raytracer. El efecto mas notorio es el de cáustica, mostrado en la esfera de cristal frontal. Figura 10: Comparación de dos muestras de fotones En la figura 10, también se muestra el resultado de la ejecución del algoritmo con dos escenarios de parámetros distintos, para una misma especificación de imagen. El gráfico de la izquierda se generó con 600.000 fotones, emitidos por dos fuentes de luz situadas en distintas posiciones. Mientras que el gráfico a la derecha fue creado con solamente 200.000 fotones. Fácilmente se aprecia la diferencia en la calidad de los dos gráficos. Entre mayor sea la cantidad de fotones utilizados en la escena, mayor la claridad y definición de la imagen. Además, en la imagen de la derecha los contornos de los objetos son menos claros y las sombras, al aparecer punteadas, producen un efecto menos realista. definidas por 32 posiciones aleatorias dentro del pixel. Entonces, cuando se le asigna a un procesador la tarea de calcular la radiancia del pixel, cada procesador debe ejecutar las 32 muestras antes de poder retornar el resultado. En el caso de los fotones, el cálculo es mucho más sencillo. No hay muestreo y el algoritmo solo se limita a trazar los fotones con las funciones de reflexión apropiadas. 4. CONCLUSIONES Y TRABAJO FUTURO La calidad de las imágenes generadas resultó satisfactoria. El algoritmo cumplió las expectativas al respecto. Por su parte, el haber comparado varias corridas para una misma geometría de la imagen, con distintos parámetros, produjo información valiosa acerca de la cantidad mínima de fotones requerida, tal que se produzca una imagen de buena calidad, sin incurrir en costos computacionales innecesarios. La evaluación de los tiempos de corrida en un cluster de computadoras generó datos importantes, los cuales permitieron conocer cual fase consume mayor tiempo, ayudando esta información a buscar optimizar del algoritmo, de manera más localizada. Algunas interrogantes que surgieron durante esta investigación facilitan orientar el trabajo futuro. Entre ellas se destacan: a) comparación de otras estructuras de datos para mapa de fotones; b) eliminación del proceso maestro en la etapa de renderizado; y, c) cambiar el concepto de tarea para que esta sea por ruta y no por pixel. 5. AGRADECIMIENTOS Se reconoce y agradece el apoyo a esta investigación brindado por el Programa de Posgrado en Ciencias de la Computación de la Universidad de Costa Rica; la Escuela de Ciencias de la Computación e Informática de la Universidad de Costa Rica; el Proyecto de Apoyo a la Investigación (No. 326-A8-726) y a la Universidad de Costa Rica. 6. REFERENCIAS BIBLIOGRÁFICAS Figura 11: Tiempos promedios. En relación con tiempos de ejecución, en la figura 11 se nota como la fase que requiere más tiempo es el renderizado. La tendencia parece mantenerse. El renderizado siempre será la fase que requiere más tiempo, sin importar el número de procesadores que se dispongan para ejecutar el algoritmo en su totalidad. La diferencia tan significativa entre el tiempo de la primera fase y de la segunda, se comprende por cuanto en esta última, el proceso que más requiere procesamiento es el muestreo de cada pixel. Por cada pixel, se necesitan 32 muestras, [1] Krste Asanovic and Rastislav Bodik. A view of the parallel computing landscape, Communications of the ACM (2009), 56-67. [2] A. R. Butz, Alternative algorithm for hilbert's space filling curve, IEEE Trans. Comp (1971), 424-426. [3] Alan Chalmers, Timothy Davis, and Erick Reinhard, Practical parallel rendering, A.K. Peters, 2002. [4] Michael Cohen and John Wallace, Radiosity and realistic image synthesis, Morgan Kaufmann, 1993. [5] Philip Dutre, Kavita Bala, and Philippe Bekaert, Advanced global illumination, A.K.Peters, 2006. [6] James Foley, Computer graphics, principles and practice in c., Addison-Wesley, 1997. [7] Cameron Hughes and Tracey Hughes, Professional multi-core programming, Wiley publishing, 2008. [8] Toshiya Hachisuka, Shinji Ogaki, and Henrik Wann-Jensen, Progressive photon mapping, ACM Transaction on Graphics 27 No. 5 (2008), 130:1-130:8. [9] Henrik Wann Jensen, Realistic image synthesis using photon mapping, 2001. [10] James Kajiya, The rendering equation, Proceedings of ACM SIGGRAPH 86 (1986), 143_150. [11] Vincent C.H. Ma and Michael. Low latency photon mapping using block hashing, The Eurographics Association (2002), 89-99. [12] Matt Pharr and Gregg Humphreys, Physically based rendering: from theory to implementation, Morgan Kau_man, 2004. [13] Ted Whitted, An improved illumination model for shaded display, Communications of the ACM 23 (1980), 343-349.