Ray Tracing (Whitted Ray Tracing)

El Ray Tracing no es un solo algoritmo sino que hay varios, siendo el más simple el llamado Whitted Ray Tracing del que derivan el resto que son mejoras de este.  El Whitted Ray Tracing traza los rayos a la inversa, es decir, desde el ojo hasta la fuente deluz. Para generar la proyección bidimensional del plano de la imagen solo nos interesan los rayos que terminan o en el ojo o en una fuente de luz y por tanto tiene todo el sentido empezar en el ojo y trazar los rayos hacía la escena. Una visualización de como funciona el algoritmo lo podéis ver en la siguiente imagen:

WhittedRT.PNG

El proceso se puede almacenar en forma de arbol, donde cada nodo es el punto de intersección del rayo con una superficie. El tipo de arbol generado es un KD-Tree que es un tipo de estructura de datos espacial como el Octree pero mucho más precisa.

kdtree

kDtree2

Aquí no hemos voxelizado una escena anterior ni nada por el estilo, pero nos ayuda a entender el porque de la voxelixación y los Octree. Es decir, en vez de aplicar el rayo en cada uno de los pixeles lo que haces es aplicarlo en cada uno de los nodos del Octree y es obvió que la precision es mucho más baja pero ese metodo de iluminación era el SVOGI que he comentado antes, dicho de otra manera el llamado Cone Tracing es una versión muy simplificada del Ray Tracing y mucho menos precisa. El motivo de la simplificación es que la GPU recorriendo un montón de KD-Tree estaría hasta el día del juicio final.

Ahora bien, Si nos fijamos en este tipo de Raytracing por cada impacto sobre una superficie se generan dos rayos distintos como consecuencia, una es la luz transmitida por el propio objeto al ser iluminado (indirecta) y la otra es el desvió del rayo de luz al impactar sobre la superficie, lo cual es un modelo limitado que solo tiene en cuenta la iluminación especular e ignora por completo la iluminación difusa de la escena.

Lambert2.gif

La iluminación difusa es necesaria para la representacion de objetos del tipo Glossy y precisamente en las demostraciones que hemos visto de la pasada GDC sobre el tema abusan continuamente de ese tipo de reflejos en las demostraciones técnicas.

gdc-epic-games-nvidia-ray-tracing-demo-slim_1200x500

dxr-seed-800x450

Por lo que el Whitted Ray Tracing no puede ser lo que han utilizando para generar estas escenas sino un tipo de Raytracing más complejo. Pero la pregunta que nadie se hace es… ¿Vamos a ser esto lo que veamos a corto plazo? Las demostraciones de las dos imagenes se ejecutaban en configuraciones de varias GPUs y no de gama baja precisamente, sino en sistemas con 4 Nvidia Tesla V100 y hay que tener en cuenta que cada una de ellas tiene una potencia de 14 TFLOPS. Pero lo mejor viene ahora:

La demo Reflections se ejecuta a 1080P y 24 fotogramas por segundo en el Unreal Engine.

¡En un hardware de 56 TFLOPS! Por lo que lo lógico es pensar que al menos la demostración del Unreal Engine no utiliza el Whitted Raytracing sino un tipo de Raytracing más complejo que permite la implementación de luz difusa. ¿Pero es malo el Whitted Ray Tracing? En absoluto, resuelve sin problemas el transporte de la luz pero solo con la iluminación especular, pero para explicarlo permitid que haga un pequeño inciso para explicar lo del transporte de la luz.

Transporte de la Luz

En una escena en 3D tenemos tres tipos de luces.

iluminación2

Voy a ignorar la la luz ambiente porque es la menos compleja y se basa en la simple combinación de un color con el color final de la textura sin tener en cuenta cual es la posición, ni la trayectoria de la luz. La luz ambiente suelen ser los puntos de partida de las fuentes de luz.

Sin entrar en consideraciones del algoritmo de renderizado, en una escena en 3D sumamente simple tenemos:

492002-doom-playstation-screenshot-the-psx-release-adds-colored-lights

  • Fuente de Luz → Cámara (Ojo)

Este era el tipo de iluminación más simple y es el que se utilizo en los primeros juegos en 3D.  La cosa evoluciono con el tiempo a un modelo de iluminación más compleja que es lo que hoy llamamos iluminación directa.

unreal

  • Fuente de Luz → Superficie Difusa → Cámara (Ojo)
  • Fuente de Luz → Superficie Especular (mapa de entorno) → Cámara (Ojo)

Pero si queremos ir más allá necesitamos calcular la iluminación que es generada indirectamente por una superficie al impactar una fuente de luz sobre ella. A la hora de transmitir la luz de una superficie a otra tenemos cuatro escenarios distintos posibles:

LightTransport.PNG

Por lo que añadiendo un solo nivel adicional de indireccion tenemos.

  • Fuente de Luz → Superficie Difusa → Superficie Difusa → Cámara (Ojo)
  • Fuente de Luz → Superficie Especular → Superficie Difusa → Cámara (Ojo)
  • Fuente de Luz → Superficie Difusa → Superficie Especular → Cámara (Ojo)
  • Fuente de Luz → Superficie Especular → Superficie Especular → Cámara (Ojo)

Tenemos 4 metodos de transporte de la luz diferenciados entre superficies que son:

  • (a) Difusa a Difusa: Es posible calcularla utilizando Radiosidad.
  • (b) Especular a Difusa: Se necesita una combinación entre el Raytracing y la Radiosidad.
  • (c) Difusa a Especular: Mismo caso que (b)
  • (d) Especular a Especular: Es posible calcularla con Raytracing.

Ahora muchos os estaréis rascando la cabeza… Y preguntandose…

Radiosidad 

En los gráficos en 3D por ordenador, la radiosidad es un método para resolver la ecuación de renderizado en escenas con superficies que reflejan la luz de manera difusa.

La Radiosidad se basa en los algoritmos en la física del mundo real de la transmisión de calor/energía pero en este caso para simular lo que es la distibución difusa de la luz por toda la escena. El algoritmo divide cada superficie en la escena en una serie de elementos llamados «patches» y un conjunto de ecuaciones basadas en la conservación de la luz son ejecutados en cada «patch» que combina la escena. La ecuación más común es la ley del coseno de Lambert establece que la máxima intensidad de la irradiación, sobre una superficie, se obtiene cuando el haz incide perpendicularmente sobre esta. Si la incidencia no es perpendicular, por el fenómeno de reflexión, se “pierde” parte de la radiación y por tanto, disminuye la intensidad.

Ahora bien, hay una particularidad respecto a la iluminación especular y es que no se necesita almacenar la trayectoria de la luz en todo el entorno en forma de estructura de datos espacial, esto hace que en un algoritmo basado en OpenGL como puede ser el Direct3D se pueda representar en teoría pero tenemos una limitación muy grande y es que la tasa de relleno y por tanto la cantidad de operaciones por pixel aumenta a niveles estratosféricos, no olvidemos que el algoritmo general para la rasterización es:

Por cada fragmento 
{
 Por cada pixel del objeto proyectado a la pantalla. 
 { 
 Sí Z del Pixel es más cercano que el valor existente en el Z-Buffer
 {
 Actualiza el Color Buffer con el color resultante
 del shader resultante del objeto sobre el pixel. 
 Actualiza el Z-Buffer
}
 }
}

No en vano con tal de simular montones de fuentes de luz difusas en el rasterizados  se acabo optando por el renderizado en diferido en la rasterización y es uno de los motivos por los cuales pienso que vamos a ver una combinación de Deferred+Whitted Raytracing en que la iluminación difusa continuara estando simulada y solo sera iluminación indirecta real la especular. ¿Es este modelo el que hemos visto en las demos de la GDC pasada? No, no lo es y aún nos falta explicar el último punto.

La Ecuación de Renderizado y Path Tracing

Tanto la ecuación de renderizado como el Path Tracing fueron introducidos en 1986 por James Kaiya. Encapsula la iluminación global producida describiendo lo que ocurre en un punto de una superficie en forma de declaración matemática, en concreto unificado en una sola ecuación, la cual es:

RenderingEquation.PNG

El tipo de escena tridimensional a la que hace referencia la ecuación de renderizado es un hemisferio.

fig2 (1).gif

La ecuación se desglosa de la siguiente siguiente manera:

  • l(x, x’) es el transporte de la intesidad o la intensidad de la luz del punto x al punto x’.
  • g(x, x’) es la visibilidad entre los puntos x y x’. Si no existe visibilidad entre x y x’ entonces la viosibilidad es 0.
  • ε(x, x’) es la transferencia de emisión desde x’ a x y esta asociado a la intensidad de cualquier luz auto-emitida por x’ que vaya en dirección de x.
  • p(x, x’, x») hace referencia a la energía dispersada por x en una superficie de x’ que llega de un punto de x». .

No vamos a entrar en matemáticas complejas pero esto es para que veáis que el Path Tracing lo que hace es simple y llanamente unir los dos tipos de iluminacion indirecta y hacerlas interaccionar entre si. Esto permite la representación completa del comportamiento de la luz en cada material dado que todo material refleja la luz de manera especular y/o difusa en diferentes grados. ¿El problema con el Path Tracing? Bueno, tiene dos problemas, el primero de ellos es que necesita una cantidad de muestras por pixel enorme para eliminar la enorme cantidad de ruido que se genera en la escena, esto significa tener que calcular el color de cada pixel de la escena varias veces lo cual es mortal para el algoritmo Z-Buffer. El otro elemento es que esto rompe por completo el renderizado en diferido debido a que necesitamos hacer que la luz difusa interactue con la luz especular aumentando una orden de magnitud la potencia necesaria para generar una escena con el Path Tracing y siendo una solucion que no vamos a ver ni a corto ni a medio plazo en los juegos.

Y con esto terminamos, espero que os haya sido didáctico.