martes, 15 de julio de 2014

Embellece tu juego 2D - Bloom

El efecto bloom queda genial en escenas de alto contraste de colores; y nuestro juego seguro que tiene una preciosa paleta de colores a la que le quedaría de maravilla.

Ejemplo de bloom:


La técnica implica varios pasos a seguir:

1) Obtener en una textura únicamente los pixeles más luminosos de la imagen.
2) Aplicarle un desenfoque gausiano (vertical y horizontal)
3) Combinar el resultado de la imagen desenfocada con la imagen original usando additive blending.

Todo esto lo realizamos con una resolución pequeña para mejorar el rendimiento puesto que no nos hace falta tanta precisión.


Partimos de la imagen original de los anteriores posts:


El shader para obtener los pixeles más luminosos de la imagen es una simple fórmula que resulta en retornar el color en caso de que sea mayor que un valor de corte:

//valor de corte
static const float fCutoff = 0.5f; 
// Obtenemos el color del pixel de la imagen original. 
float4 color = tex2D(ColorMapSampler, Tex); 
// Sólo lo mantenemos si es mayor que el punto de corte
return saturate((color - fCutoff ) / (1 - fCutoff )); 

Y este sería el resultado cuando se vuelve a escalar a la resolución original:

Después de obtener los pixeles más brillantes aplicamos un desenfoque gausiano tanto vertical como horizontal un par de veces. El shader tiene esta pinta:

static const int g_cKernelSize = 13;

//pontencia del desenfoque con respecto al pixel central
static const float BlurWeights[g_cKernelSize] = 
{
    0.002216,
    0.008764,
    0.026995,
    0.064759,
    0.120985,
    0.176033,
    0.199471,
    0.176033,
    0.120985,
    0.064759,
    0.026995,
    0.008764,
    0.002216,
};

//distancia del desefoque horizontal
float2 PixelKernelH[g_cKernelSize] =
{
    { -0.03, 0 },
    { -0.025, 0 },
    { -0.02, 0 },
    { -0.015, 0 },
    { -0.01, 0 },
    { -0.005, 0 },
    { 0,  0 },
    { 0.005,  0 },
    { 0.01,  0 },
    { 0.015,  0 },
    { 0.02,  0 },
    { 0.025,  0 },
    { 0.03,  0 },
};

//distancia del desefoque vertical
float2 PixelKernelV[g_cKernelSize] =
{
    {0, -0.03},
    {0, -0.025},
    {0, -0.02},
    {0, -0.015},
    {0, -0.01},
    {0, -0.005},
    {0, 0},
    {0, 0.005},
    {0, 0.01},
    {0, 0.015},
    {0, 0.02},
    {0, 0.025},
    {0, 0.03},
};

sampler ColorMapSampler : register(s0);

//Desenfoque horizontal
float4 BlurH( in float2 Tex : TEXCOORD0 ) : COLOR0
{

    float4 Color = 0;
    //Cogemos el pixel actual y lo mezclamos con el color de los pixeles vecinos atenuado
    //por la potencia de desenfoque (mas lejos, mas atenuacion)
    for (int i = 0; i < g_cKernelSize; i++)
    {    
        Color += tex2D( ColorMapSampler, Tex + PixelKernelH[i].xy) * BlurWeights[i];
    }
    
   return Color;
 
}
//Desenfoque vertical
float4 BlurV( in float2 Tex : TEXCOORD0 ) : COLOR0
{
   float4 Color = 0;

    for (int i = 0; i < g_cKernelSize; i++)
    {    
        Color += tex2D( ColorMapSampler, Tex + PixelKernelV[i].xy) * BlurWeights[i];
    }
    
   return Color;
 
}

Y como resultado queda esto:

Ahora sólo nos resta combinar la imagen original con la desenfocada usando additive blending:

// Our bloom texture
sampler BloomSampler : register(s1);

// Our original SceneTexture
sampler TextureSampler : register(s0);

float4 PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
      // Get our bloom pixel from bloom texture
      float4 bloomColor = tex2D(BloomSampler, texCoord);


      // Get our original pixel from ColorMap
        float4 originalColor = tex2D(TextureSampler, texCoord);
        
    // Combine the two images.
  //  return originalColor + bloomColor;
  return originalColor + bloomColor;
}

Y el resultado final es el siguiente:

Se puede observar, sobre todo en la columna de la izquierda y en el pelo de la cabeza de león, como la luz "quema" la cámara y como "emite" un halo a su alrededor.

No hay comentarios:

Publicar un comentario