The following blog post, unless otherwise noted, was written by a member of Gamasutras community.

The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

Introduction

When we were developing Mimpi Dreams, we knew we wanted to make rich parallax layers for background and foreground. In Steam version, there are several layers to manage. So we came up with a technique that might not be unique, but I want to summarize it here.

There are many tutorials about setting up parallax layers in Unity using one orthographic camera and moving those layers with a script. There are also bits of advice about the use of perspective camera and z-depth of objects. If you do that, it is harder to setup proper sprite sorting, and you cannot use optimization techniques and other features of an orthographic camera we wanted to use in Mimpi Dreams. The original Mimpi was developed using the perspective camera only, and we had some problems with it. We used non-transparent objects to save fill rate, but they had to be placed with z-offset to prevent z-fight. Then, however, perspective was applied to them, so they moved in different speed.

The best way is to get the best of both. Setup perspective cameras to render parallax layers and use the orthographic camera to render main plan with character, platforms, puzzles, etc.

When using perspective cameras for parallax, it is much easier to set them up. In ortho parallax, you need to scale every object depending on camera distance, and properly position it. Lukáš Navrátil, creator of Toby: The Secret Mine, told me he spent maybe half of production time setting up ortho parallax layers. With our combined technique, he would be able to do it much faster.

We developed this technique together with my colleague Jaroslav Stehlík, our technical lead. Now let’s look how to set it up.

Camera and Scene Setup

The hierarchy is simple. You put the parallax cameras under the main camera, so they move together.

Main Camera

Clear Flags: Don’t clear

Culling Mask: everything except parallax layer

Projection: Orthographic

Depth: -1

Parallax Camera Near

Clear Flags: Depth only

Culling Mask: Parallax

Projection: Perspective

Clipping Planes

Near: 0.01

Far: 10

Depth: 0

Parallax Camera Far

Clear Flags: Solid Color (or whatever else you want to use as a background)

Culling Mask: Parallax

Projection: Perspective

Clipping Planes

Near: 10

Far: 500

Depth: -2

The main camera will render everything except the parallax layers in orthographic mode. That is accomplished using “Culling Mask”. The “Clipping Planes” solve which parallax objects are rendered to which parallax camera depending on their Z-position so that the foreground is before ortho plane and foreground is behind it. Our camera is placed -10 on the z-axis, so everything in parallax where Z < 0 is rendered to near camera and objects that have Z > 0 are be rendered to far camera. The “Depth” determines the correct order in which the cameras are rendered.

Now you need to put all parallax objects into the parallax layer in the editor and keep all other objects out of it.

Camera Sizes and Zoom

You need to think about the orthographic camera size and perspective field of view setup. Especially when you want to use zooming in your game, you need to setup parallax’s cameras field of view based on the orthographic size of the main camera. The point is that there is always one particular plane (in this case in z = 0), where parallax layers will be moving the same speed as the main game plane with orthographic perspective. This is important because you can then move and zoom camera and it behaves naturally. At the start of development of Mimpi Dreams, we didn’t realize that and made mistakes in our parallax setup. We were not able to change it later since it would need to reposition all parallax layers. In the end, it does not matter too much since we are not using zooming a lot. In the next project, we will definitely use this setup.

Here is a code you can use to set zoom.

public float GetFieldOfView(float orthoSize, float distanceFromOrigin) { // orthoSize float a = orthoSize; // distanceFromOrigin float b = Mathf.Abs(distanceFromOrigin); float fieldOfView = Mathf.Atan(a / b) * Mathf.Rad2Deg * 2f; return fieldOfView; }

If you want to move your camera in z-axis, you also need to update clipping planes of the parallax camera.

// distanceFromOrigin float b = Mathf.Abs(mainCamera.transform.position.z); //change clipping planes based on main camera z-position farCamera.nearClipPlane = b; farCamera.farClipPlane = mainCamera.farClipPlane; nearCamera.farClipPlane = b; nearCamera.nearClipPlane = mainCamera.nearClipPlane;

There are two options how you can zoom a camera.

You can either move your main camera in the z-axis (and recalculate clipping planes) or you can change the orthographic size of the main camera (and recalculate field of view of parallax cameras). Both of said options provide a different effect, changing the orthographic size is the more natural looking option. Alternatively, you can combine these two techniques. Check the video below.

Unity Example

Jaroslav prepared and example Unity project which you can try and learn from it. Thanks Unity for providing free assets from platformer example!

You can download the example project from Github.

The project was made using Unity 5.3.3f1

You also take a look at the video, which shows the demo.

Editor Workflow

The best way to setup objects in parallax layers is to play the game in editor play mode. You can move your character (and your camera) as the player would see it and adjust objects to the actual view. The only problem is that changes in play mode in Unity do not save. You can always copy the edited object in play mode and paste it into the editor and then save it, however. We create a prefab with child object “content”. This content is edited in play mode and copied. After quitting the play mode, this original content is deleted, new content is pasted from the clipboard, and then the prefab is applied.

Also, don’t forget to place a new object into the parallax layer. It is also possible to write or use some editor utility that will help you with saving and automatic object layer settings.

The example above is executed in edit mode, so you can also use it for setup in the editor. But we used this workflow in Mimpi Dreams since it was easier for our graphics artist to move in the scene and he was able to adjust the layers himself.

Summary

Some advantages of this solution:

Native basic setup (script just for zooming)

Better performance in our case

Static batching, since layers are not moving

Easy editor workflow

Disadvantages:

Can produce more draw calls

We introduced quite a different approach to making parallax effect in Mimpi Dreams. You might need to customize it a little. We, for example, are rendering all cameras into the render texture, but in this article, I wanted to introduce the simplest setup.

I hope you found this article useful. Let me or Jaroslav know, when you use it in your project.