Film Vignette Effect in Unity

Sample of a flickering (film) vignette effect for Unity.

The complete code and assets for this example can be found at https://github.com/cmroche/UnityVignetteShader

The process to doing this is fairly simple, first we create a texture and import it to unity as an Alpha 8 type texture. The alpha channel will be opaque on the outer edges and transparent on the inner area. Use this material on a quad in your camera’s view frustum and select the vignette shader.

The idea behind producing the flicker is fairly straight forward. Select a random value in a range, apply a slight bias, and blend from the current value to the next value. Once we reach our target choose a new random value and repeat the process. To make the shader look like the vignette is moving in and out of the edges of the frame we want to select intensity values that completely saturate part of the texture’s alpha.

There are a few tuneable variables we’ll use for polishing the effect:

public float IntensityBias = 0.6f;
public float MinimumIntensity = 1.0f;
public float MaximumIntensity = 1.4f;
public float BlendSpeed = 1.0f;

If you want a linear range of intensity values, set your IntensityBias to 0.5, if you would like to bias towards a more opaque frame move your IntensityBias upwards, values between 0.6 and 0.8 seem to work well.

A simple coroutine to select intensity values and blend continuously:

IEnumerator DoBlending()
{
   while (true)
   {
      float rate = 1f / BlendSpeed * BlendUpdateRate;

      if (currentValue == targetValue)
      {
         targetValue = Random.Range(MinimumIntensity, MaximumIntensity);
      }
      else
      {
         float dir = Mathf.Sign(targetValue - currentValue);
         currentValue += dir * rate;

         if (dir != Mathf.Sign(targetValue - currentValue))
         {
            currentValue = targetValue;
         }

         float intensity = Bias(IntensityBias, currentValue);
         Shader.SetGlobalFloat("_Intensity", intensity);
         //UnityEngine.Debug.Log("Current intensity " + intensity.ToString() + " target intensity " + targetValue.ToString());
      }

      yield return new WaitForSeconds(BlendUpdateRate);
   }
}

The vignette shader to apply the effect, the 0.8f here is the saturation point of the alpha channel this way we can still see through the frame at the highest intensity. You can obviously change this to your needs.

half4 frag(v2f i) : COLOR
{
   half4 c = i.color;
   c.a = clamp(tex2D(_MainTex, i.uv).a * _Intensity, 0f, 0.8f);
   return c; 
}

All the code and assets in this example are public domain. You may freely reuse or modify in any way and for any purpose (even commercial) without the need to attribute or notify me. Of course if you would like to credit me this simple work, I certainly won’t complain.

A Much Simpler UIToolkit Shader (Unity)

A much simpler, even slightly more efficient, shader that works with Prime31’s UIToolkit (for Unity). This shaders removes the alpha test (an expensive operation on iDevices), replaces tint colour with a simple main colour (allows you to control a sprite’s alpha), and uses premultiplied alpha in the source texture. Premultiplied alpha’s help to reduce colour bleeding giving you a better visual result, are slightly less computationally expensive, and are supported by TexturePacker.

You may reuse or distribute this code in any way without either notification or credit.

Shader "Custom/UI Premultiplied Alpha"
{
	Properties
	{
		_Color( "Main Color", Color ) = ( 1, 1, 1, 1 )
		_MainTex( "UI Texture", 2D ) = "white" {}
	}

	Category
	{
		Tags { "Queue" = "Transparent" }
		Blend One OneMinusSrcAlpha
		ColorMask RGB
		Cull Off
		Lighting Off
		ZWrite On

		BindChannels
		{
			Bind "Vertex", vertex
			Bind "TexCoord", texcoord
		}

		SubShader
		{
			Pass
			{
				SetTexture[_MainTex]
				{
					combine texture * constant ConstantColor[_Color]
				}
			}
		}
	}
}