Introduction

It’s no secret that I’m working on converting the Path of Shadows prototype into a full game. The original prototype used a custom engine with a deferred rendering pipeline, as I needed it to manage the ‘shadow powers’ properly. Switching to Unity3D, I found myself having to learn how Unity3D manages deferred rendering and how to “hijack” that pipeline to give the game the look I want.

Forward Rendering vs Deferred Rendering

The rendering pipeline defines how each object in the scene will be shaded, that means, how its surface color shall be calculated.

A forward rendering pipeline cycles through each object in the scene and calculates its surface color based on its material + all the lights affecting it. This gives a shading complexity of O(number of objects * lights).

The first issue is that the number of lights becomes a big performance hit. Also, when you have more than one object covering a portion of the screen, the pixel shader might have to calculate the shading for all of those objects regardless of them being blocked from view. Lastly, objects with transparency or special effects might need to be rendered in more than one pass, increasing the render time.

A deferred rendering pipeline picks every opaque object in the scene and extracts any geometry data that you need (world position, normals..) and stores it in a MRT (Multiple Render Target). Then, it would traverse each screen-space pixel and shade it using the data you stored and the screen lights. This would give you a complexity of O(screen_pixels * screen_lights).

So, in deferred rendering the render-pass performance is much better than before, but you still must “render” the scene one time to get all that geometry data. You’ll also find that deferred is more limited when working with transparencies, but you can always render problematic objects using forward rendering. Finally, deferred rendering requires a hardware with support for MRT and a high bandwidth to handle all the MRT data reading/writing.

In Unity3D, you can set the preferred rendering pipeline in Edit->Project Settings->Player.

Unity Deferred Shaders

Unity shaders can be written in different ways. I’ll let the Unity3D documentation explain that to you.

Unity uses some internal shaders to handle the deferred rendering passes. If you want to overwrite them you’ll need to grab the Built-In shaders source code HERE. Once you have it, get “Internal-PrePassLighting.shader” and move it to your 'Assets/Resources’ folder in your project. If it doesn’t exist, just create it.

Now you can edit that shader and it will affect the rendering pipeline of your app. Basically, you’ll want to modify the 'CalculateLight’ function that handles how the light pass is rendered. For example, you could modify how the “diff” param gets calculated to create a global toon shader.

Okay, but how to take advantage of this in your object shaders? Usually, you can declare your own Lighting Model in your shader like this:

half4 LightingName (SurfaceOutput s, half3 lightDir, half atten);

But if you want to use your new Deferred Lighting pipeline you must declare it like this:

half4 LightingName_PrePass (SurfaceOutput s, half4 light);

A “default” shader for Deferred would look like this:

That’s all! If you’ve got any questions you can find me at my Twitter account , and remember to check Path of Shadows at the official website and the Facebook page!