Lighting in Unity


Lighting in Unity tutorials

Verbatim extracts from https://learn.unity.com/tutorial/introduction-to-lighting-and-rendering#5c7f8528edbc2a002053b528

Global illumination, or ‘GI’, is a term used to describe a range of techniques and mathematical models which attempt to simulate the complex behaviour of light as it bounces and interacts with the world. Simulating global illumination accurately is challenging and can be computationally expensive. Because of this, games use a range of approaches to handle these calculations beforehand, rather than during gameplay

Realtime Lighting

By default, lights in Unity - directional, spot and point, are realtime. This means that they contribute direct light to the scene and update every frame. As lights and GameObjects are moved within the scene, lighting will be updated immediately. This can be observed in both the scene and game views.

Baked GI Lighting

When 'baking’ a ‘lightmap', the effects of light on static objects in the scene are calculated and the results are written to textures which are overlaid on top of scene geometry to create the effect of lighting.

 

Left: A simple lightmapped scene. Right: The lightmap texture generated by Unity. Note how both shadow and light information is captured.

These ‘lightmaps’ can include both the direct light which strikes a surface and also the ‘indirect’ light that bounces from other objects or surfaces within the scene. This lighting texture can be used together with surface information like color (albedo) and relief (normals) by the ‘Shader’ associated with an object’s material.

With baked lighting, these light textures (lightmaps) cannot change during gameplay and so are referred to as ‘static’. Realtime lights can be overlaid and used additively on top of a lightmapped scene but cannot interactively change the lightmaps themselves.

With this approach, we trade the ability to move our lights at gameplay for a potential increase in performance, suiting less powerful hardware such as mobile platforms.

Precomputed Realtime GI Lighting

Whilst traditional, static lightmaps are unable to react to changes in lighting conditions within the scene, Precomputed Realtime GI does offer us a technique for updating complex scene lighting interactively.

With this approach it is possible to create lit environments featuring rich global illumination with bounced light which responds, in realtime, to lighting changes. A good example of this would be a time of day system - where the position and color of the light source changes over time. With traditional baked lighting, this is not possible.


simple example of time of day using Precomputed Realtime GI.

In order to deliver these effects at playable framerates, we need to shift some of the lengthy number-crunching from being a realtime process, to one which is ‘precomputed’.

Precomputing shifts the burden of calculating complex light behaviour from something that happens during gameplay, to something which can be calculated when time is no longer so critical. We refer to this as an ‘offline’ process.

So how does this work?

Most frequently it is indirect (bounced) light that we want to store in our lightmaps when trying to create realism in our scene lighting. Fortunately, this tends to be soft with few sharp, or 'high frequency’ changes in color. Unity’s Precomputed Realtime GI solution exploits these ‘diffuse’ characteristics of indirect light to our advantage.

Finer lighting details, such as crisp shadowing, are usually better generated with realtime lights rather than baking them into lightmaps. By assuming we don’t need to capture these intricate details we can greatly reduce the resolution of our global illumination solution.

By making this simplification during the precompute, we effectively reduce the number of calculations we need to make in order to update our GI lighting during gameplay. This is important if we were to change properties of our lights - such as color, rotation or intensity, or even make change to surfaces in the scene.

To speed up the precompute further Unity doesn’t directly work on lightmaps texels, but instead creates a low resolution approximation of the static geometry in the world, called ‘clusters’. 

Left: With scene view set to ‘Albedo’ the texels generated by Unity’s Precomputed Realtime GI can clearly be seen. By default a texel in this view is roughly the size of a cluster. Right: The scene as it appears in-game once the lighting has been calculated and the results converted to lightmap textures and applied. Traditionally when calculating global illumination, we would ‘ray trace’ light rays as they bounce around the static scene. This is very processing intensive and therefore too demanding to be updated in realtime. Instead, Unity uses ray tracing to calculate the relationships between these surface clusters beforehand - during the 'Light Transport' stage of the precompute.

By simplifying the world into a network of relationships, we remove the need for expensive ray tracing during the performance-critical gameplay processes.

We have effectively created a simplified mathematical model of the world which can be fed different input during gameplay. This means we can make modifications to lights, or surface colors within the scene and quickly see the effects of GI in scene lighting update at interactive framerates. The resulting output from our lighting model can then be turned into lightmap textures for rendering on the GPU, blended with other lighting and surface maps, processed for effects and finally output to the screen.


Benefits and Costs

Although it is possible to simultaneously use Baked GI lighting and Precomputed Realtime GI, be wary that the performance cost of rendering both systems simultaneously is exactly the sum of them both. Not only do we have to store both sets of lightmaps in video memory, but we also pay the processing cost of decoding both in shaders.

The cases in which you may wish to choose one lighting method over another depend on the nature of your project and the performance capabilities of your intended hardware. For example, on mobile where video memory and processing power is more limited, it is likely that a Baked GI lighting approach would be more performant. On ‘standalone computers’ with dedicated graphics hardware, or recent games consoles, it is quite possible to use Precomputed Realtime GI or even to use both systems simultaneously.

The decision on which approach to take will have to be evaluated based on the nature of your particular project and desired target platform. Remember that when targeting a range of different hardware, that often it is the least performant which will determine which approach is needed.


Enabling Baked GI or Precomputed Realtime GI

By default, both Precomputed Realtime GI and Baked GI are enabled in Unity’s Lighting panel (Lighting>Scene). With both enabled, which technique is used can then be controlled by each light individually (Inspector>Light>Baking).

Using both Baked GI and Precomputed Realtime GI together in your scene can be detrimental to performance. A good practise is to ensure that only one system is used at a time, by disabling the other globally. This can be done by unchecking the box next to either Precomputed Realtime GI or Baked GI from Unity’s lighting panel (Lighting>Scene). Now only the checked option will be present in your scene, and any settings configured per-light will be overridden.


Per-Light Settings

The default baking mode for each light is ‘Realtime’. This means that the selected light(s) will still contribute direct light to your scene, with indirect light handled by Unity’s Precomputed Realtime GI system.

However, if the baking mode is set to ‘Baked’ then that light will contribute lighting solely to Unity’s Baked GI system. Both direct and indirect light from those lights selected will be ‘baked’ into lightmaps and cannot be changed during gameplay.

                                              

 Point light with the per-light Baking mode set to ‘Realtime’.

Selecting the ‘Mixed’ baking mode, GameObjects marked as static will still include this light in their Baked GI lightmaps. However, unlike lights marked as ‘Baked’, Mixed lights will still contribute realtime, direct light to non-static GameObjects within your scene. This can be useful in cases where you are using lightmaps in your static environment, but you still want a character to use these same lights to cast realtime shadows onto lightmapped geometry.


The Precompute Process

In Unity, precomputed lighting is calculated in the background - either as an automatic process, or it is initiated manually. In either case, it is possible to continue working in the editor while these processes run behind-the-scenes.

When the precompute process is running, a blue progress bar will appear in the bottom right of the Editor. There are different stages which need to be completed depending on whether Baked GI or Precomputed Realtime GI is enabled. Information on the current process is shown on-top of the progress bar.

Progress bar showing the current state of Unity’s precompute. 


In the example above, we can see that we are at task 5 of 11 which is, ‘Clustering’ and there are 108 jobs remaining before that task is complete and the precompute moves on to task 6. The various stages are listed below:

Precomputed Realtime GI                                            Baked GI

01 - Create Geometry                                    01 - Create Geometry

02 - Layout Systems                                        02 - Atlassing

03 - Create Systems                                        03 - Create Baked Systems

04 - Create Atlas                                               04 - Baked Resources

05 - Clustering                                   05 - Bake AO

06 - Visibility                                       06 - Export Baked Texture

07 - Light Transport                                         07 - Bake Visibility

08 - Tetrahedralize Probes                                           08 - Bake Direct

09 - Create ProbeSet                                      09 - Ambient and Emissive

10 - Create Bake Systems

Probes                                  11 - Bake Runtime

12 - Upsampling Visibility

01 - Ambient Probes                                       13 - Bake Indirect

02 - Baked/Realtime Ref. Probes                                               14 - Final Gather

15 - Bake ProbesSet

16 - Compositing

 <p> </p>


Starting a Precompute

Only static geometry is considered by Unity’s precomputed lighting solutions. To begin the lighting precompute process we need at least one GameObject marked as ‘static’ in our scene. This can either be done individually, or by shift-selecting multiple GameObjects from the hierarchy panel.

From the Inspector panel, the Static checkbox can be selected (Inspector>Static). This will set all of the GameObject’s ‘static options’, or ‘flags’, including navigation and batching, to be static, which may not be desirable. For Precomputed Realtime GI, only 'Lightmap Static' needs to be checked.

For more fine-grained control, individual static options can be set from the drop-down list accessible to the right of the Static checkbox in the Inspector panel. Additionally, objects can also be set to Static in the Object area of the lighting window.

If your scene is set to Auto (Lighting>Scene>Auto), Unity’s lighting precompute will now begin automatically. Otherwise it will need to be started manually as described below.

Auto/Manual Precompute

If ‘Auto’ is checked from the bottom of Unity’s Lighting panel (Lighting>Scene>Auto), then this precompute will begin automatically as a background process whenever changes are made to static geometry within your scene.

However, if Auto is not selected, you will need to manually start a precompute by clicking the ‘Build’ button next to it. This will begin the precompute in much the same way, while giving you control over when this process starts.

Manually initiating a precompute will cause all aspects of your scene lighting to be evaluated and (re)computed. If you wish to selectively recalculate Reflection probes by themselves, this can be done via the drop-down menu next to the Build button (Lighting>Scene>Build).


GI Cache

In either Baked GI or Precomputed Realtime GI, Unity ‘caches’ (stores) data about your scene lighting in the ‘GI Cache’, and will try to reuse this data whenever possible to save time during precompute. The number and nature of the changes you have made to your scene will determine how much of this data can be reused, if at all.

This cache is stored outside of your Unity project and can be cleared using (Preference>GI Cache>Clear Cache). Clearing this means that all stages of the precompute will need to be recalculated from the beginning and this can therefore be time consuming. However in some cases, where perhaps you need to reduce disk usage, this may be helpful.

Comments

Popular posts from this blog

Dr Hannah Thompson, Royal Holloway University