martes, 8 de julio de 2014

Embellece tu juego 2D - Specular Highlight

Specular Highlight es el brillo que aparecen en los objetos cuando la luz incidente es reflejada directamente hacia nuestros ojos.

La propuesta, a bote pronto, es sencilla: Calcular el vector de "rebote" de la luz y hacer el dot product con el vector de la vista; mientras menor sea el ángulo entre estos 2 vectores, más brillo vamos a apreciar.


L es el vector de dirección de la luz (invertido), N es el vector normal del pixel (sacado del normal map), V es la vista (o cámara), H es el Half Vectror que yo no voy a usar porque es más preciso utilizar el vector de la luz reflejado (R).



Los cambios del shader creado en los post anteriores serían los siguientes:

//Calculamos el "rebote" de la luz según su dirección y hacia donde "mira el pixel"
float3 R = normalize(reflect(LightDirectionN, normal));
//realizamos el dot product con el vector de vista y nos cuidamos que el valor quede ente 0 y 1
float3 S = saturate(dot(R, V));
//al color final se le agregan los brillos especulares
tex.rbg *= ((AmbientLight * AmbientLightColor) + (A * ( S + (D * LightColor))));

Y ya tenemos una versión rústica y un poco bruta.

Pasamos de esto:


A esto:


Ahora tenemos que conseguir refinar esto puesto que sumar S al color final no es del todo preciso y, además, diferentes materiales tienen diferente propiedades de reflexión de la luz. Para especificar el nivel de dispersión del brillo del material elevamos S a una potencia que suele estar entre 5 y 50, lo que nos dará brillos más finos o dispersos:

float S = (pow( saturate(dot(R, V)), 50));

Con potencia 5 se puede apreciar que los brillos son dispersos:



Con potencia 50 se aprecian brillos más finos:



Aún con todo esto, todavía podemos mejorar la cosa. Los materiales, además, reflejan más o menos luz, o pueden tener una estructura granulada donde algunos puntos reflejan y otros no, independientemente de que la luz reflejada llegue a nuestros ojos. Para simular esto podemos utilizar un mapa especular, que es una textura con un solo canal en blanco y negro (y gris) donde se representa la intensidad de la luz especular en cada pixel.

Mapa especular representando microfacetas granuladas:

Para utilizar el mapa especular le pasamos al shader esta textura:

sampler SpecularSampler : register(s2);

Y la utilizamos para modular la intensidad de los brillos:

 float3 SpecularIntensity= tex2D(SpecularSampler, texCoord);
 S *= SpecularIntensity.r; //sólo un canal porque lo estoy haciendo a lo bruto y no optimizo

El resultado final es este:

Se puede observar claramente las microfacetas del material reflejando o no los brillos.

Disclaimer: La calidad de las texturas influye mucho en el resultado final. Yo estoy usando un mapa especular con ruido aleatorio que no tiene coherencia con respecto a la textura a mostrar y el resultado no es muy preciso.

No hay comentarios:

Publicar un comentario