How to create masked and unmasked animated backgrounds with Unity3D

Verónica Valls
Game & Frontend Development Stuff
4 min readApr 19, 2016
The background grid and the map grid move along X axis

I’d like to share my know-how and problems that I stumbled across when I was trying to create an animated background using Unity’s UI Masks.

The main problem is that currently I haven’t found a way to create masked animated backgrounds using UI Masks due to an existent bug in Unity as I read on this post: http://forum.unity3d.com/threads/trying-to-animate-an-image-component-material-shader.265023/

A ticket had been sent, and it seemed like the bug was corrected, but in Unity 5.3.3 I’m still facing the same problems that are explained in the above post, so I made a roundabout to avoid UI Masks and created the animated backgrounds using appropiated shaders.

Step 1: Unmasked grid and masked grid, two different how-to

In this example scene, we have two grids to animate, one without mask (the background one) and the other one masked (the map one), this is the UI structure I used:

Panel (Background): A panel with an image component with dark yellow color used as background.
Cuadricula (Background grid): Another image component which contains the brown grid.
MapCuadricula (Map grid): The image that contains the map+yellow grid+brown background combined.

Step 2: Preparing the background grid (unmasked animation)

Let’s focus on the Background grid, in this case on the image component I created a Material which uses a shader I called UIMaskShader:

In this shader you can put a texture to color the material and the alpha is the form of the material, in this case the grid. Here is the code of the shader:

Shader “Custom/UIMaskShader” 
{
Properties
{
_MainTex (“Base (RGB)”, 2D) = “white” {}
_Alpha (“Alpha (A)”, 2D) = “white” {}
}

SubShader
{
Tags { “RenderType” = “Transparent” “Queue” = “Transparent”}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

Pass
{
SetTexture[_MainTex]
{
Combine texture
}
SetTexture[_Alpha]
{
Combine previous, texture
}
}
}
}

This way our background grid is ready to be animated, in order to animate it we need to increase the X axis alpha offset to create an horizontal movement, why the alpha offset? Because it’s the one that contains the form of the material, you may need to increase the main texture offset if you also want to animate the design of the material and it isn’t a flat color (of course, feel free to move along Y, or along both axis, that depends on your needs ;) ):

 float vel=0.01f;
public Material materialGrid;

void Start()
{
//Initialising the alpha offset position from the background grid
materialGrid.SetTextureOffset(“_Alpha”, new Vector2(0f, 0f));
}

void Update ()
{
//Creating movement along x axis increasing the background grid alpha’s offset
materialGrid.SetTextureOffset(“_Alpha”,
new Vector2(materialGrid.GetTextureOffset(“_Alpha”).x+vel,
materialGrid.GetTextureOffset(“_Alpha”).y));
}

Step 3: Preparing the map grid (masked animation)

Now comes the interesting case, I created a new Material to use in the map grid image component:

This shader uses a main texture as the image or design we need to apply and a culling mask of the shape we need. The texture of the culling mask in Import Settings will have checked Alpha from Grayscale and the Format will be Alpha 8. The shader code looks like the following:

Shader “Custom/UIMaskAnimatedShader”
{
Properties
{
_MainTex (“Base (RGB)”, 2D) = “white” {}
_Mask (“Culling Mask”, 2D) = “white” {}
}
SubShader
{
Tags {“Queue”=”Transparent”}
Lighting Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
AlphaTest GEqual [_Cutoff]
Pass
{
SetTexture [_Mask] {combine texture}
SetTexture [_MainTex] {combine texture, previous}
}
}
}

In this case, we’ll animate the offset from the main texture:

 float vel=0.01f;
public Material materialMap;

void Start()
{
//Initialising the map texture offset position
materialMap.mainTextureOffset=new Vector2(0f, 0f);
}

void Update ()
{
//Creating movement along x axis increasing the map texture’s offset
materialMap.mainTextureOffset=
new Vector2(materialMap.mainTextureOffset.x+vel,
materialMap.mainTextureOffset.y);
}

And that’s it! Now we have plenty of animated backgrounds with or without masks. If you need to implement something similar to this using masked animations and UIMasks still has problems, this is an alternative to apply the same feature :)

--

--

Verónica Valls
Game & Frontend Development Stuff

Mobile & frontend developer for real world projects. Game designer/developer for my mind’s delirium ideas. Cats & dogs dietetical and nutritional advisor.