domingo, 20 de junio de 2010

Real Time Radiosity - Problemas y Soluciones

Algunos Problemas y como se fueron resolviendo.

Anti-Aliasing del Shadow Map.
Si acercamos la vista a la sombra de una de las piedras, vemos que la se puede notar un efecto "serrucho". Sin embargo este error no es introducido por el shadow map (cosa que se puede comprobar agrandando o achicando el tamaño del mapa sin ningun efecto en el mismo), si no que esta producido por el tesselado.




Para resolverlo seguimos 2 caminos.

- Primero cuanto mas tesselado este la escena menos visible sera el error. Pero como estamos muy limitados con la cantidad de poligonos y pacthes a evaluar, no es una buena solucion. La disposición del tesselado tambien repercute senciblemente en el error:




El tesselado de la izquierda es muy superior a la de la derecha, es preferible tener menos cantidad de polígonos totales pero distribuidos centralmente como en la izquierda, que un tessellado mas fino, pero con una distribución como el de la derecha. Con esa distribución si la linea de sombras fuera dialogonal en menos 45 grados, el efecto del error sería muy visible.

De contar con un el un object shader (directx10) se podria resolver el problema directamente en el shader generando un tesselado en el momento, de acuerdo a si hay diferencias de iluminacion marcadas entre los 3 vertices.

- Aplicar un algoritmo de anti-aliasing modificado:

// anti-aliasing del shadowmap
// I = intensidad de luz
float I2 = 0;
float r = 1;
float FP = 2;
for(int i=-r;i<=r;++i)
for(int j=-r;j<=r;++j)
I2 += (tex2Dlod( g_samShadow,
float4(auxCoord + float2((float)(i*FP)/SHADOWMAP_SIZE, (float)(j*FP)/SHADOWMAP_SIZE),0,0) )
+ EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;

I2 /= (2*r+1)*(2*r+1);
I = I*0.2 + I2*0.8;

El algoritmo toma un cierto radio r alreder del punto i,j del shadow map para promediar los distintos valores (que pueden ser cero o 1 si esta o no en la sombra). Sin embargo, como estamos trabajando con polígonos y no con pixels, hay que introducir un factor, (lo llamamos factor de penumbra = FP), que permite alejarse mas del punto inicial del shadow map. De no introducir este factor, habria que tomar un radio enorme para obtener algun efecto. El un gran factor FP produce un efecto de penumbra. De todas formas en algoritmo de radiosity usualmente no nos preocupamos por este error del shadow map, porque la sombra se va a suavizar por si sola, en la medida que sigamos evaluando mas rayos, y como consecuencia todas las sombras tienden a ser suaves en cualquier solución de radiosity. Sin embargo, como en nuestro algoritmo estamos tomando muy pocos rayos, se logra un buen efecto haciendo un anti-aliasing SOLO del primer rayo:




En estos ejemplos solo se toma el primer rayo para ver bien el efecto del anti-aliasing. En la práctica con todos los rebotes se llega a un buen balance con r = 1, y FP=2.
Ejemplo con r = 1, y evaluando todos los rayos, el error original ademas se ve suavizado con tonalidades rojizas que provienen de la pared.




- Intensidad de la luz en cada Rebote.

Si el algoritmo fuese físicamente correcto no habría ningun problema con la intensidad de luz. Pero al simplificar las ecuaciones, y evaluar solo cierto rayos etc etc, el algoritmo esta precisa ciertos valores que se introducen artificialmente y que si no estan corrrectos pueden producir errores extraños.
La fuente de luz inicial parte con una intensidad i0, los rebotes primarios i1, y los secundarios i2. Tiene que haber un balance entre la cantidad de rayos totales y las intensidades relativas.




Afortundamente estos valores se pueden aproximar ya que son directamente proporcionales a la cantidad de rayos. Y luego se pueden ajustar por cuestiones estéticas o subjetivas.

Velocidad y Discontinuidad en el tiempo.

El algoritmo estandard funciona aproximadamente a 2fps usando 40 rebotes promedio, y menos de 1fps usando 60 rebotes promedio. Para mejorar la performance se usa la siguiente técnica: en lugar de usar un solo mapa de radiosity, se usan 3 mapas, uno para cada paso del algoritmo y se divide el algoritmo en 4 pasos de carga similar. En cada frame solo se calcula uno de los pasos:
paso 1: se procesa la 1er luz con el antialiasing del shadow map.
paso 2: se calculan las luces secundarias.
paso 3: se procesan las luces secundarias.
paso 4: se generan las luces terciarias y se procesan.
En cada paso se procesa el input y se dibuja la escena sumando los valores de los 3 mapas:

Diffuse = tex2Dlod( g_samRMap, float4(iId/MAP_SIZE,0,0))
+ tex2Dlod( g_samRMap2, float4(iId/MAP_SIZE,0,0))
+ tex2Dlod( g_samRMap3, float4(iId/MAP_SIZE,0,0));

Los primeros frames el algoritmo dibuja resultados parciales, pero una vez que llenaron todos los mapas, en cada paso dibuja una solución que es una mezcla de la solución actual + 2 soluciones anteriores.
Esto ademas resolvió otro problema que tiene que ver con una discontinuidad en el tiempo al mover las fuentes luminosas o los objetos de la escena. Una mínima diferencia en la fuente luminosa puede producir un bruzco cambio de toda la solución, al caer por ejemplo en otro patch diferente. De esta manera al promediar siempre 3 soluciones se minimiza ese efecto a la vez que se llega a velocidades de entre 6 y 10 fps.



Rebotes con color.

Uno de los efectos del radiosity es que la luz al rebotar contra un objeto, sale de un color preciso, con lo cual los objetos son bañados por diferentes colores provenientes del la escena y no solo por la luz blanca original.
En la implementacion el color de cada objeto esta previamente almacenado (no esta tomando el color exacto donde rebota, pero no seria un impedimento generarlo offline).
Para visualizarlo más graficamente se modificó el algoritmo para la primera luz sea roja pura, las luces secundarias sean verdes, y las terciarias azules:




Se ve claramente como la pared donde pega la primer luz se ve en un tono rojo intenso, luego rebota la luz de color verde, que llena la pared izquierda y el piso de un tono verde. El efecto de las luces terciarias es mucho mas leve, pero se puede notar en la base de las columnas y en el techo.

Ejemplo con 30 rayos entre 13 y 14 fps y el mismo ejemplo con 60 rayos aprox 6 fps:

1 comentario:

  1. Tal como los alumnos de Sábato, en esa clase, yo tampoco entiendo un carajo, pero sí sé que los dibujitos quedaron bárbaros!!!!!! Doy fé! jajajaja...
    Me encantá que estés publicando aunque sea una partecita de lo mucho que sabes! Sos un genio!
    :-P !!!!

    ResponderEliminar