Ondrej Paska Blog

Unity Transition Effects

Advertisements

In a gamejam game I worked on recently, I wanted to create a nice transition effect between two different “worlds”.

This is what it ended up like:

In this blog post I want to show you how it works and how to create even better effects.

The two worlds in my case were two different Game Objects each with many children objects. For each world there is a separate camera. To make the camera only render the corresponding object, you need to assign each object to a different layer (check apply to children as well). Then set the camera culling mask to that layer only.

For a refresher on multiple cameras, check out this excellent blog post.

In this case we have root2 on top of root1 (the order in which cameras render is determined by their “depth”).

We need a way to mask everything in the top layer. We can write a shader that only renders in the depth buffer and blocks everything else from rendering: 

 Shader "Custom/DepthMask"
 {
     SubShader
     {
         Tags {"Queue" = "Geometry-1" }
         Lighting Off
         Pass
         {
             ZWrite On
             ZTest LEqual
             ColorMask 0     
         }
     }
 }

For more info on how that works, check out this wiki page.

Now when we create a quad and assign a material with this shader, we can use it to hide parts of the layer. In the sample code, I added this to root2 and will use it show/hide this layer. You can also have a unique quad like this (I call it a “wiper”) in each layer.

The following script does some of the setup for the effect.

        public GameObject Root1;
	public GameObject Root2;

	public GameObject Wiper;
	
	public Camera Camera1;
	public Camera Camera2;

	private void Awake()
	{
		SetupCameras();
		
		Root1.SetActive(true);
		Root2.SetActive(false);
	}

	private void SetupCameras()
	{
		Camera1.clearFlags = CameraClearFlags.SolidColor;
		Camera1.depth = 0;
		Camera1.cullingMask = 1 << Root1.layer;
		
		Camera2.clearFlags = CameraClearFlags.Nothing;
		Camera2.depth = 1;
		Camera2.cullingMask = 1 << Root2.layer;
	}

 

The clearFlags are importing, because without them, Camera2 would render a solid color or skybox underneath our content, which would not be masked by the shader.

Next let’s animate things with DOTween, which makes it really easy to move stuff around without messing with unity animation system.

We start with the wiper fully masking the contents of Root2 and then move it aside. On subsequent transitions we always flip this tween.

	private bool _toggled;
	private bool _transitionActive;
	
	private void Update()
	{
	  if (!_transitionActive && Input.GetKeyDown(KeyCode.Space))
	  {
	    ToggleTransition();
	  }
	}

	private void ToggleTransition()
	{
	  _toggled = !_toggled;	
		
	  Root1.SetActive(true);
	  Root2.SetActive(true);

	  Wiper.transform.position = new Vector3(_toggled ? 0 : -31, 0, -9f);
	  Wiper.transform.DOMoveX(_toggled ? -31 : 0, 1.5f).OnComplete(OnTransitionFinished);
		
	  _transitionActive = true;
	}

	private void OnTransitionFinished()
	{
	  _transitionActive = false;
	  Root1.SetActive(!_toggled);
	  Root2.SetActive(_toggled);
	}

 

You can see that both “worlds” are only active during the transition. That’s useful when you want to stop any simulation or user interaction on the occluded layer.

If, instead of a quad, you use a circle mesh, you get this cool effect:

In 2D you can get similar effects with unity 2D mask, but this method works for any content 2D or 3D. You can also use it for two different scenes, loaded additively.

Full code as usual on github.com/randalfien/unity-transition-effect

You can also try the game (in browser!) on itchio

Advertisements

Advertisements