Precomputed Realtime GI (Global Illumination)
Tutorial
Intermediate
1 Hour
Overview
Summary
In Unity, there are two distinct techniques available for precomputing global illumination (GI), or bounced lighting. These are Baked GI and Precomputed Realtime GI. This tutorial focuses on Precomputed Realtime GI.
Topics we'll cover
Language
English
Recommended Unity Versions
5.5
Tutorial
Precomputed Realtime GI (Global Illumination)
1.
Introduction to Precomputed Realtime GI
In Unity, there are two distinct techniques available for precomputing global illumination (GI), or bounced lighting. These are Baked GI and Precomputed Realtime GI. This tutorial focuses on Precomputed Realtime GI.
When working with Precomputed Realtime GI, a lighting precompute is the process of calculating the bounce of light around the static geometry within a Scene in the Unity Editor and storing this data for use at run time. This process reduces the number of lighting calculations that must be performed at run time, allowing realtime bounced lighting while maintaining interactive framerates.
When using Baked GI, traditional lightmap textures are generated offline during the precompute process. These textures then exist as assets within the project and cannot be changed at run time. Precomputed Realtime GI does not create lightmap assets in the same way. Instead, lighting data is saved as a Lighting Data Asset which contains the information needed to generate and update a set of low resolution lightmaps interactively, at run time.
Unless our Scene has been properly prepared and optimized, the time it takes to complete these calculations can become excessive. In this tutorial, we will learn how to optimize a Scene for Enlighten (the backend for Unity’s Precomputed Realtime GI and Baked GI solutions) so that lighting precomputes take minutes rather than hours.
Over the course of the document we will cover:
  • How to determine an appropriate lighting resolution for our Scenes.
  • What Charts are and how they affect our precompute times.
  • How to start the precompute process.
  • Using probe lighting to reduce the complexity of our lighting solution.
  • Improving auto-unwrapped UVs generated by Unity’s Precomputed Realtime GI.
  • What Clusters are and how they are used to generate globally illuminated lighting.
  • Using Lightmap Parameters to fine-tune our lighting on a per-object basis.
Once we have learned and applied these techniques, we can leverage the benefits of using Precomputed Realtime GI: fast lighting iteration times, the ability to experiment more rapidly during the lighting process and realtime bounced lighting during gameplay.

Reducing precompute times from hours to minutes

In the Lighting Tutorial Scene used for this tutorial, precomputing the lighting with a default, non-optimized setup took around 7.5 hours on our test machine. For a Scene of this complexity, clearly this is unacceptable.
 
Default Scene: Precompute took 7.5 hours. Optimized Scene: Precompute took 2.25 minutes.
Following around 30 minutes of Scene preparation using the techniques covered in this tutorial, the precompute time was 2.25 minutes for a production-quality result. Considering that we can rapidly iterate on Scene lighting without needing to re-calculate GI and change GI lighting during gameplay, the attractive benefits of this technology are quickly apparent.

Downloading assets for this tutorial

Throughout this tutorial we will be referring to the Lighting Optimization Tutorial project available from the Unity Asset Store:
In this written tutorial, we will be using the example Scenes contained within the Scenes/Article folder: LightingTutorialOptimal, LightingTutorialNonOptimal and LightingTutorialStart.
  • LightingTutorialOptimal has been set up according to this tutorial and is intended to represent an example of how production-ready lighting results can be achieved with minimal precompute time using Unity’s Precomputed Realtime GI.
  • LightingTutorialNonOptimal reflects a lot of the common problems we see in projects that either don’t finish baking, or take an unacceptably long time. This is a good reference for how Scenes should not be configured.
  • LightingTutorialStart will be the Scene which we are working with throughout this tutorial. As we follow the steps laid out in this tutorial, we will take this Scene to a completed, production-ready result.

2.
Realtime Resolution
When setting up a Scene for lighting using Precomputed Realtime GI, one of the first decisions that needs to be made is to determine your Scene’s default Realtime Resolution. Realtime Resolution is the number of realtime lightmap texels (texture pixels) used per world unit.
Realtime Resolution can be observed or set in the Lighting window, as follows:
  • Open the Lighting window (Window > Lighting) and then select the Scene tab.
  • Ensure Precomputed Realtime GI is enabled by checking the Precomputed Realtime GI checkbox.
  • Observe the Realtime Resolution property beneath the Precomputed Realtime GI checkbox.
 
Unity’s Lighting window showing the Scene’s global Realtime Resolution setting.

Choosing an appropriate Realtime Resolution

When setting up a Scene it is important to have some idea of the unit scale your project will need. It could be that in your project a unit is a meter, a foot or a centimeter. Unity units do not have a default equivalence in real world scale so it it down to the user to decide what a unit represents.
In our example project we have decided that a unit is equivalent to 1 meter. Certain physics concepts assume the same. For example, gravity is represented in units per second as a default in Unity. Assuming that a unit is equivalent to 1 meter is therefore a good setup for a real world game scenario.
Often your Scene’s Realtime Resolution can be determined from the scale of your game world. For example, is your Scene a small, but richly populated indoor environment with a lot of variance in the bounced lighting? In this case, higher lightmap resolutions such as 2-3 texels per unit might be justified in order to capture this more detailed or ‘high-frequency’ lighting.
Perhaps your Scene is a large outdoor environment where the world scale is considerably bigger. You might have surfaces that are hundreds or even thousands of units in area with little variation to modify the color of bounced light. In cases such as these, a resolution which is appropriate to capture the intricate lighting details present in an indoor Scene would be wasteful when applied across the large and less featured expanses of an outdoor environment. We would be wasting valuable CPU time and available memory by having to store and update lightmap texels which aren’t contributing much to the overall look of the Scene. More importantly, for the purposes of this tutorial, we would be increasing the number of lightmap texels that must be considered during the lighting precompute. This can have a huge impact on precompute times.
In the case of an outdoor environment, an appropriate lightmap resolution might be be somewhere between 0.5 -1 texels per unit for large objects within the Scene, or 0.1 - 0.5 texels for the terrain.

Precomputed Realtime GI Resolution vs. traditional lightmaps

The Realtime Resolution values needed by Unity’s Precomputed Realtime GI are orders of magnitude less than ‘traditional’ lightmap texel densities. This is because we are only capturing indirect lighting in these lightmaps, and this tends to be very soft or ‘low frequency’. When using Precomputed Realtime GI, crisp shadows will usually be provided by realtime shadows rather than high resolution lightmaps.
Using values which may seem appropriate in traditional lightmapping techniques - say 30 texels per unit - will likely result in precomputes failing or otherwise not completing. More suitable values are around 2 - 3 texels per unit for indoor Scenes, and 0.5 - 1 for outdoor environments. This is assuming that we are working with a human scale Scene with a unit size of 1 unit = 1 meter. If the world scale was substantially different, these values would need to be adjusted accordingly.
Appropriate values assuming a human-scale world with 1 unit representing 1m.
When initially setting our Scene’s Realtime Resolution, we are specifying the default resolution for Static objects within our Scene. New GameObjects with a MeshRenderer marked as Lightmap Static at the top of the Inspector will use this value until otherwise modified.
In addition to choosing the Realtime Resolution for the entire Scene we also have the option to change lightmap resolution on a per-object basis. In cases where we need the extra fidelity offered by higher resolutions, we can selectively increase this value. Generally it is less work to set the most common resolution as the Scene default and then manually raise the resolution on those objects which need more lighting detail. We will discuss approaches to modifying resolution per-object later in the tutorial.

Setting our Scene’s Realtime Resolution

If you want to follow along, we will be working in the LightingTutorialStart Scene included with the Lighting Optimisation Tutorial linked at the top of this page.
In our example Scene, we have an outdoor environment with a medium size terrain of a reasonably consistent color. For this, a low Realtime Resolution of 0.5 texels per unit would be sufficient to capture the bounced lighting from other objects in the Scene. However, there are also a number of wooden houses. These are much more detailed. As there are many more houses than there are terrain objects in the Scene, we should set the Realtime Resolution to be appropriate for the houses. We can then modify the resolution used by the terrain objects individually. This will reduce the amount of work needed when preparing our Scene. With this in mind, we are going to use a value of 1 texel per world unit for our default Realtime Resolution.
  • Open the Lighting window (Window > Lighting) and select the Scene tab.
  • Set the Realtime Resolution value to 1.
Given that we have decided our Scene’s scale to be 1 unit = 1m, this means that a single lightmap texel created by Unity’s Precomputed Realtime GI will be equivalent to 1x1m in size. This might seem very low, but remember that we are only capturing the indirect light. Crisp shadows and specularity from direct lighting will be provided by realtime lights in the Scene.

3.
Understanding Charts
In Unity’s Precomputed Realtime GI, a Chart is an area of a lightmap texture to which we map the lightmap UVs of a given Scene object. We can think of this as a small tile containing an image of the lighting affecting that object. A Chart is made up of two parts: irradiance (lighting) and directionality (encoding the dominant light direction).
When the Precomputed Realtime GI is generated, lighting is calculated for every texel that is included in a Chart. Large numbers of Charts in a Scene can be one of the biggest detriments to precompute times so it is important to understand how Charts work and how we can manage them in order to optimize lighting precompute times.
 
Illustration showing a UV Chart of a minimum 4x4 texel size. Lightmap UVs are always clamped to within half a texel of the outside of the Chart in order to prevent bleed caused by texture filtering.
By default, each Chart is a minimum of 4x4 texels. A Chart therefore requires a minimum of 16 texels regardless of the scale of the object within the world or the size of the corresponding UV shell. So, for example, if an object is 1x1 meter, the object has 1 Chart and our indirect resolution is 1, 16 texels are required for the object. This minimum size enables Unity to stitch Charts together for seamless lighting across geometry edges. Unity requires at least 4 texels along a Chart edge in order to uniquely identify it before the corresponding partner can be found and stitched.
Note that no padding is needed for realtime GI because Unity clamps the lightmap UVs to give a half texel border inside the Chart during the packing stage of the mesh import pipeline. This means that Charts can be right next to each other and still be bilinearly interpolated without cross bleeding, saving valuable lightmap space.
Imagine the same 1x1 meter object we discussed earlier had 50 Charts. Unity would create 800 texels for the object, despite it being relatively small. This demonstrates how having a large number of Charts can quickly drive up the number of texels. More texels means more lighting calculations and more data to compute, compress and store. All of this adds up in complex Scenes and can result in lengthy precomputes and reduced performance at run time.
Inappropriate Charting is the major culprit for lighting precomputes not completing or taking too long. With this in mind, many of our obvious strategies for reducing precompute times are to reduce the number of Charts we have in our Scene.

4.
Starting the precompute process
To generate a lighting solution using Precomputed Realtime GI, we must initiate the precompute process. For this to begin, we must have at least one object marked as Lightmap Static in our Scene.
Organizing and grouping GameObjects within the Hierarchy view makes it quick and easy to select GameObjects for inclusion in the lighting precompute. There are numerous strategies for organizing the hierarchy of GameObjects. Discussing these different strategies in detail is outside the scope of this tutorial. However, what is important is to understand that having some scheme for organizing GameObjects will greatly improve productivity when making repeated selections in the Scene.
In our example Scene, we have organised our GameObjects into classifications underneath a parent object called Environment. This group contains all the visible, static MeshRenderers which make up the environment of our Scene. Underneath this we have sub-groups of objects which have similar characteristics in terms of size or topology.
 
Grouping of objects within the Scene hierarchy can help when making repeated selection of objects.
It is most efficient to begin by applying lighting settings in broad strokes and then progressively refine the details as we move forwards.
  • Select the Environment GameObject.
  • In the Inspector window, check the box marked Static
  • When asked if you wish to enable the Static flags of the child objects as well, select Yes, change children. Doing this ensures the GameObject and its children will receive the Lightmap Static flag. They will then be included in the lighting precompute.
Now that our Scene has some Static GameObjects, we can begin the precompute process.
  • Open the Lighting window (Window > Lighting) and then select the Scene tab.
  • Ensure that the Auto checkbox is checked. The Auto checkbox can be found next to the Build button, which will be greyed out if the Auto checkbox is checked.
  • The precompute process will now begin. The progress of the precompute process is shown in the bottom right of the Unity Editor and is represented by a blue progress bar. The current task (written as x/xx) and the number of jobs remaining in that task are displayed within the progress bar.
  • If the Auto checkbox is not enabled, the process can be manually initiated by clicking the Build button. When working through this tutorial, it is recommended that Auto mode is left on.
 
Progress bar showing the current task, remaining tasks and remaining jobs of the precompute.

5.
Probe lighting
Having understood that the number of Charts in our Scene is detrimental to precompute times, we are able to make big gains in lighting performance by choosing to exclude certain objects from the precompute altogether. This will reduce the number of Charts generated. Instead, we can use probe lighting on these objects, which is an efficient means of receiving indirect lighting from the Scene. Although probe lit objects will not contribute bounced lighting to the Scene, often this is has little noticeable impact. The objects most suitable for probe lighting tend to be smaller objects which would have little effect on bounced lighting anyway.

What is probe lighting?

Probe lighting is a fast technique for approximating lighting in realtime rendering applications such as games. It is commonly used for lighting characters and other non-Static (dynamic) objects in the game world. Probe lighting is very performant at run time and has the added benefit that it is quick to precompute.
Probe lighting works by sampling the incoming lighting at a specific point in 3D space and encoding this information across a sphere using mathematical functions known as spherical harmonics. These coefficients have low storage cost and can be then be quickly ‘unpacked’ at gameplay and used by shaders within the Scene to approximate surface lighting. In Unity, this functionality is offered by Light Probes.
There are limitations to using probe lighting. One such limitation is that it is difficult to represent high frequency or dappled lighting across the spherical range without increasing the order (size) of these special numbers. Unfortunately the costs quickly escalate as the precision increases, meaning that for performance reasons we are limited to lower order spherical harmonics.
The fact that we only have one spherical representation of lighting for one 3D position in the world makes probe lighting unsuitable for representing lighting across very large objects where lots of lighting variation could be expected. Another limitation is that - as spherical harmonics encode values on a sphere - they are generally unsuitable for large planar objects or those with significant concavity. Note the Unity Manual offers some information on Light Probe Proxy Volumes (LPPV) if you are considering using probe lighting with large objects.
Despite these limitations, probe lighting will yield suitably convincing results at relatively low cost when used with suitable smaller, convex objects. Later in the tutorial we will explore the setup and placement of Light Probes in more depth, but for now, we need only understand that we can reduce the number of lightmap Charts in our Scene by instead choosing to use probe lighting where appropriate.

Choosing objects to light with probes

While it was broadly useful to set our GameObjects under the Environment group to be Static in order to get our lighting setup underway, there are many objects under this parent which would make good candidates for probe lighting instead. Clearing the Static flags for these objects will mean that they are no longer considered by Unity’s Precomputed Realtime GI system and therefore the number of lightmap Charts will be reduced. Remember that reducing the number of Charts in our Scene is key to improving precompute times.
 
Small, convex debris objects make perfect cases for probe lighting.
Looking at the Hierarchy panel of the Unity Editor, let’s examine the children of the Environment GameObject. If we look specifically at the objects we find under Props, we find that many of these are small, debris style objects and Scene ‘dressing’ such as stones, buckets and wooden planks. These objects are numerous, and many of these relatively small objects would be complex to unwrap. Getting lightmap UVs that are free of distortion would most likely result in a large number of UV shells. More UV shells require extra Charts, more Charts mean more lightmap texels to compute, and so on.
Given that these objects are so small, they are unlikely to contribute much to the indirect lighting within the Scene. Equally, their size means that there is little surface area in which detailed lighting variation can be displayed. This makes these objects great candidates for probe lighting. Not only will our precompute times benefit, but performance at run time will also be improved due to the reduced number of lightmaps we need to store in memory and decode in our shaders.
  • Select the Props GameObject in the Hierarchy view.
  • In the Inspector panel, uncheck the Static checkbox.
  • Choose Yes, change children when prompted.
At this point, if we were to leave the precompute long enough, we would eventually see our lighting results in the Scene view. We would probably notice that our probe-lit, non-Static objects are lit differently to the objects around them and do not match the lighting of the Scene. This is because we have not yet set up our Light Probes and therefore these objects are falling-back to the Scene’s Ambient Probe. The Ambient Probe is essentially a hidden probe within the Scene, invisible to the user, which only samples the Ambient Source set in the Lighting window.
 
Image showing how, without light probes, non-Static objects can look out of place in their environment.
In order to place our non-Static objects more convincingly into their lit surroundings we need to spend some time placing Light Probes around the Scene in order to sample indirect lighting throughout the world.

Placing Light Probes

Non-Static objects receive lighting based on proximity to nearby probes. The decision about which probe an object might ‘read’ from is made by dividing the space between the Light Probes into tetrahedral volumes and then checking to see which tetrahedron the given object falls within. In order to make these tetrahedrons, the probes must therefore be positioned such that they create a 3D volume, or cage.
 
Scene showing the placement of Light Probes - visualized in the editor as lit spheres.
Probe lighting is relatively inexpensive at run time and is quick to precompute. However, to maximise performance, some care does need to be taken when placing probes. Although quicker to setup, dense grid arrangements of Light Probes are potentially wasteful as many of these probes will not be sampling much variance in the local lighting conditions. For efficiency, it is better practice to position probes in greater density around areas where there is pronounced change in the lighting. This may include areas where there is transition from light into shadow for example, or perhaps where there are likely to be strong colors created by light bounce.
  • To set up Light Probes, begin by creating a Light Probe Group from the GameObject menu (GameObject > Light > Light Probe Group).
  • Now we will begin placing our probes. Select the newly created Light Probe Group in the Hierarchy view.
  • In the Inspector panel, select Edit Light Probes from the Light Probe Group component.
  • You can select the probes themselves in the Scene view. Delete all but one of the corner probes from the default cube arrangement which is created.
  • Position the remaining probe to be just above the Terrain in the environment and then duplicate it by pressing Ctrl+D (Cmd+D on Mac).
  • Using the Translate tool (W), move this second probe up in the Y axis to be around 2 meters above the first.
  • Now duplicate the probe again and move the new copy to be much higher, perhaps another 5 meters up in the Y axis.
 
The Edit Light Probes button within the Light Probe Group component.
The reason for creating a vertical arrangement like this is so that we can sample the indirect lighting bounced from the ground, from around head height and also in the air (it is feasible that objects might leave the ground). When we copy these Light Probes around the Scene in order to create our volumes, we want to ensure objects anywhere in the playable area will fall within one of the tetrahedrons created between the probes. These volumes are visualized as magenta lines drawn between the probes.
 
Image showing position of Light Probes and the tetrahedrons made up between their positions.
  • Select all 3 probes you just created by holding Shift and clicking each probe individually, or by dragging a selection.
  • Duplicate the whole vertical chain we have created and move this to a nearby area of lighting interest in the Scene.
When deciding what is an area of lighting interest, look for areas of shadow, or perhaps where there is a strong change in the color of the Terrain material. Remember we are aiming to sample indirect, or bounced, lighting throughout the Scene. In order to justify the cost of adding a new probe, we must ensure that it is sampling some noticeable change in the lighting. If we were to use our Light Probes to sample areas with general or consistent lighting, then we are unlikely to see much change as the receiving object passes these probes. Like many aspects of game optimisation, we have to ensure every item we include in our Scene offers some benefit.
  • Continue repeating this process, positioning probes in greater density around areas of lighting change until you have created a sparse cage layout which encapsulates the playable area.
  • While positioning our probes, always remember to check the bottom-most Light Probe remains just off the ground.
In our example LightingTutorialOptimal Scene we have created two groups of Light Probes: one for the more densely populated village area called VillageLightProbeGroup, and one for the sparse non-playable area outside the village called ExtentsLightProbeGroup. This second group covers the extents of the game world in case any non-Static MeshRenderers leave the playable area. We don’t need the same degree of fidelity in these unreachable parts of the Scene therefore this group can be much less dense. Two probes in the vertical axis is sufficient.
Splitting the Light Probe Groups into two GameObjects makes it easier to position the probes. Individual Light Probe Groups can be enabled or disabled to offer a clearer view when working in the Scene. These groups will be automatically combined at run time, along with a de-duplication pass to remove any overlapping probes.
To see our Light Probes lit according to their environment, we must wait for a lighting precompute to complete. If Auto mode is enabled in the Lighting window, this will happen automatically. If Auto mode is not enabled, we must manually begin a precompute by navigating to the Lighting window (Window > Lighting) and pressing the Build button.
Once this process has completed, you will notice that the non-Static GameObjects in the Scene now read from the Light Probes and look better matched to the Scene lighting. To see Light Probes in their lit state, deselect the Light Probe Group in the Hierarchy view.
Now that we have set up Light Probes in our Scene, we get the visual benefits of indirect lighting on our smaller ‘prop’ objects without the expense of extra Charts created by the inclusion of these objects in the precompute.

6.
Unwrapping and Chart reduction
Now that we have excluded suitable objects from the lighting precompute, we can begin the work of reducing the number of remaining Charts.
Charts are created to encompass the UV lightmap coordinates of a Static Mesh Renderer. The number of Charts that an object requires is therefore largely determined by the number of UV shells (pieces) needed to unwrap the object in question. Unwrapping is always a tradeoff between distortion of the texel distribution on geometry faces, and the number of shells required for sufficient texture coverage.
Unity’s sophisticated unwrapping algorithms will often achieve good results without our intervention; however, sometimes we need to provide a little guidance. It is therefore important that we understand the theory and process behind automatic unwrapping.
Consider the following illustrations:
 
An unwrap without distortion, but requiring multiple UV shells.
 
UV coordinates which result in a single UV shell, but yield unacceptable texture distortion.
 
An ideal result, with no texture distortion and a single UV shell.
In the images above, we show three different examples of how the UVs on an object can be projected or unwrapped.
In the first image, we can see a result which is largely free of distortion. The checker pattern we are using as a texture is mapped in such a way that each tile of the texture remains square in aspect. If we imagine that this checkerboard was a lightmap (an ‘image’ of the lighting applied to the object), we would get a result that looked visually correct and without distortion. However, we require six UV shells to get this coverage. As a result, we would get six Charts using Unity’s Precomputed Realtime GI system. Regardless of the size of the object, each Chart would require a minimum of 4x4 texels, meaning that this object would use at least 96 texels irrespective of resolution.
In the second image, we have a different problem. The object’s UV texture coordinates have been projected so that we have one complete UV shell covering all faces. While this would be optimal in terms of the number of Charts required to cover the object, the visual results would be unacceptably distorted. We would likely see ‘smearing’ of textures applied across the surface of the object. The faces of the object also overlap in UV texture space - meaning that if we we were referencing a lightmap, the lighting from one side of the object would be displayed on opposing faces. Clearly this method of unwrapping the object will not give us an acceptable result.
The third image shows an example of an ideal unwrap. We have a result which is free of distortion: the tiles of our checkerboard texture have remained square in aspect. We have also succeeded in covering all faces of the object while only outputting one UV shell. This has been achieved by joining, or stitching UV edges which correspond to contiguous geometry edges on the model.
If we think about this programmatically, what have we done to achieve an ideal unwrap? First, we have made our UV projections orthographically onto the object in order to create our individual shells. We have then evaluated these shells for edges which are shared in the geometry of the corresponding object. Where shared edges are found, we have moved and stitched those shells to the partner edges of their neighbouring shell. This is what Unity’s unwrapping algorithms attempt to do automatically with Static geometry.

Visualising Charts

Before working to optimize our unwrapping and lightmap Charts, we need a way to visualize them in the Editor. Charts are generated during the unwrapping stage of the mesh import pipeline. For Precomputed Realtime GI, these Charts are then packed into atlasses during the Geometry stage of the precompute process. This is to ensure that they don’t overlap. We can only see a preview of our Charts once the Geometry stage of the precompute has completed and the visualisation data has been saved.
If you are working with version control as part of a team, please be aware that this information is cached locally. This means that a precompute must be carried out on your local machine before the various diagnostic draw modes become available.
 
UV Charts draw mode representing the different Charts used in the Scene as colored regions and lightmap resolution as a checkerboard overlay.
One way to quickly visualize your Charts is to use the UV Charts draw mode in the Scene view.
  • In the top left of the Scene view, use the Draw Mode drop-down menu to select UV Charts.
Using this mode, Charts can be seen as different-colored panels overlaid with a checkerboard texture representing the corresponding lightmap resolution. If you have Auto mode enabled (Window > Lighting > Auto), changes to unwrap parameters will be calculated automatically and the Scene view will be updated with the results.
 
The Charting mode of the object Preview window showing Charts as colored squares and lightmap UVs as light blue wireframe.
It can be easy to miss Charts in the Scene view when working with complex objects. By using the Preview pane in the Lighting window, we can view all the Charts used by an individual object. This can help us to more accurately assess the unwrapping of these objects, which will help us to reduce Chart counts in our Scene.
  • Open the Lighting window (Window > Lighting) and select the Object tab.
  • Select the object that we wish to view in the Hierarchy window.
  • In the top left of the Preview pane of the Lighting window, choose Charting from the drop-down menu.
The number of Charts used by that object will be represented by colored squares overlaid with the corresponding UV coordinates in light blue.

Unwrapping parameters explained

There are a number of settings that we can tweak to optimize UV unwrapping. All of these settings are per-object. We can access these settings through the Lighting window, as follows:
  • Open the Lighting window (Window > Lighting) and select the Object tab.
  • Select the object that we wish to view in the Hierarchy window.

Auto UV Max Distance

Unity’s unwrapping algorithms attempt to simplify lightmap UVs by moving shells and stitching UV edges together. UV shells will only be considered for this operation if shells are within the distance defined by Auto UV Max Distance. This range is defined in Unity’s world space units. Remember that in our tutorial Scene we are assuming that a unit is 1 meter.
 
The Auto UV Max Distance setting found in the Object tab of the Lighting window.
In many cases the default value of 0.5 units will give acceptable results. For particularly large objects with large faces, it may be necessary to increase this value. This is to prevent suitable candidate UVs from being excluded from selection by the stitching algorithm.
Increasing the Auto UV Max Distance will often reduce the number of Charts required by the selected object. Decreasing this value is useful in situations where there is visible stretching of lightmap texels and we may actually need more Charts in order to get the required texel coverage. The results of these changes can be easily assessed using the checkerboard overlay in the UV Charts Scene draw mode. Finding the right balance can often require a little experimentation.

Auto UV Max Angle

Lighting UV shells are also evaluated for stitching based on the angle between neighbouring faces of the corresponding mesh. Auto UV Max Angle defines the maximum angle permitted between faces sharing a UV edge and is calculated using the internal angle. If the angle between the backfaces is greater than this amount, these UV shells will not be considered for stitching.
 
The Auto Max Angle settings can be found within the Object tab of the Lighting window.
Increasing this value will make it more likely that lighting UVs will be combined by Unity’s unwrapping algorithm. Auto UV Max Angle can therefore can be a good way to reduce the number of Charts required by a selected object. However, sometimes stretched lightmaps can occur when this tolerance is too relaxed. Decreasing the Auto UV Max Angle will make the unwrapper less likely to combine UV edges, which will result in more Charts but less distortion. Again, using the checkerboard overlay in the UV Charts Scene draw mode is a good way of assessing the suitability of the values we are using.

Preserve UVs

In some cases it may be impossible to get an ideal unwrap using the auto unwrapper. We may end up with too many Charts or unacceptable distortion in our lightmaps (visualized as stretched checkering when in GI Charts draw mode). In these cases it may be necessary to manually author UVs in the UV01 channel of our model file. This is work that needs to be done while in our chosen content creation package.
If this is the case, we can use the Preserve UVs option to force Unity’s unwrapping algorithms to preserve the shape of the UV shells defined in your model’s UV01 channel.
 
The Preserve UVs option is useful when it is desirable to keep your manual lighting UVs.
It is important to note that these shells will always be be repacked to save lightmap space. It is the manner in which the shells are unwrapped, individually, which will be preserved rather than the shell’s position within the lightmap.
We must be cautious when using this approach. In cases where our lightmap UVs contain a large number of UV shells, this option can actually increase precompute times. This is because the UV merging step offered by Unity’s auto unwrapper is bypassed and our manual UV layout is preserved. Remember that the desired outcome is as few UV shells - and therefore as few Charts - as possible, while keeping an acceptable level of distortion.

Ignore Normals

In certain cases the mesh importer may decide to split geometry. This will also affect Charts. For example, if a mesh has an extremely high triangle count it may be more performant for Unity to split it into separate sub-meshes. Often this is for hardware specific requirements, such as reducing the number of triangles in each draw call. Where these splits occur is decided based on areas where there is large variance in the normal angle between adjacent mesh faces, such as hard edges . Splitting meshes in this way happens during the mesh import process for your models. Charts can potentially be split during this process as edges that fall within a Chart may be separated, resulting in multiple shells which in turn will require additional Charts.
 
The Ignore Normals checkbox prevents charts being split during the import pipeline.
Sometimes it is not desirable to split your Charts in this way. The resulting increase in the number of Charts may be detrimental to precompute times, and lighting seams can cause unwanted visual artefacts in the resulting lightmaps. In these cases, enabling the Ignore Normals checkbox will prevent the Charts being split for Precomputed Realtime GI lighting.
Note that only Precomputed Realtime GI is affected by this option. Splits in the selected meshes are still preserved for other uses in Unity.

Faster iteration in larger Scenes

Complex Scenes can contain hundreds - even thousands - of Static objects. Generating the Chart atlases for all these objects can result in slow lighting precomputes and this can negatively affect the speed with which we are able to iterate on our Scenes.
When experimenting with unwrap settings for objects, sometimes it can be useful to isolate an object of interest in an empty Scene where we can iterate quickly with minimal precompute times. The unwrap settings we determine can then be taken back and applied to other objects of that type in our original Scene. Working in this way can add up to big time savings when preparing Scenes for lighting.
  • Open the LightingTutorialStart Scene included in the example project.
  • Select one of the objects called HouseBig02 in the Hierarchy window. These are grouped under Environment > Structures > Houses.
  • Copy this object to the clipboard by pressing Ctrl+C (Cmd+C on Mac).
  • Create a new Scene by pressing Ctrl+N (Cmd+N on Mac).
  • If prompted to save your changes, select Yes if you are happy with your current Scene progress or No if you wish to discard it.
  • In the newly created Scene, paste HouseBig02 from the clipboard by pressing Ctrl+V (Cmd+V on Mac).
  • Open the Lighting window (Window > Lighting) and then select the Scene tab.
  • Enable Auto precompute mode by enabling the Auto checkbox.
  • Now select the Object tab.
  • In the top left of the Object tab, select Charting from the drop-down menu.
  • Expand the Preview area to see how the object is unwrapped.

7.
Optimizing Unity's auto unwrapping
When configuring unwrap parameters, the ideal outcome is to find a combination of values that results in the lowest number of Charts while having the least lightmap distortion. Remember that distortion is visualized as stretching of the checkerboard texture applied to objects in the Scene view when UV Charts draw mode is enabled.
 
The checkerboard pattern can be used to visualize lightmap texel distribution. Notice here that the checkerboard is relatively consistent across our model - meaning there is little lightmap distortion.
 
Stretching and warping of the checkerboard indicates that there is some inconsistency in the distribution of lightmap texels.
In this example, we will apply what we have learned about UV unwrapping to optimize precompute times on an object in our tutorial project.
  • Open the LightingTutorialStart Scene included in the example project.
  • Select one of the objects called HouseBig02 in the Hierarchy window. These are grouped under Environment > Structures > Houses.
  • Open the Lighting window (Window > Lighting) and select the Object tab.
  • Select Charting from the drop-down menu in the top left of the tab.
  • Expand the Preview area at the bottom of the tab. Note how many UV shells are displayed here and the number of corresponding colored Charts.
 
Image showing the Charting preview for the HouseBig02 object with default unwrap settings. This number of Charts can be easily reduced.
HouseBig02 is a fairly complex object within our Scene, which may justify the use of multiple Charts. However, we may still be able to reduce this number by modifying our unwrap settings.
 
The Object unwrap settings panel
There is no one-size fits all solution for unwrapping objects. Unity’s unwrapping algorithms attempt to make sensible decisions based on appropriate defaults, but with some user guidance, we may be able to achieve a more optimal result.
  • Select HouseBig02 in the Hierarchy window.
  • Open the Lighting window (Window > Lighting) and select the Object tab.
  • Lower the Auto UV Max Distance to its minimum value of 0.1.
The precompute process will begin. Following a brief calculation, we can see in the Preview area of the Lighting window that number of Charts has noticeably increased. Checking the Scene view there seems to be little distortion, which is good. Unfortunately, however, this many Charts for an object of this complexity is unacceptable. Remember that more Charts means longer precompute times and reduced performance at run time.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Set the value of Auto UV Max Distance to 10.
We now have the opposite problem. The number of Charts has decreased, but at the cost of introducing unacceptable distortion to our lightmaps. We can observe this distortion in the UV Charts Scene draw mode. The distortion appears as streaking or stretching of the checkerboard overlay.
 
Selecting an Auto UV Max Distance which is too high can result in distortion of our lightmap UVs.
We know that Unity’s unwrapping algorithm attempts to minimise the number of Charts by merging UV shells together. The Auto UV Max Distance setting specifies the maximum distance, in worldspace, permitted between UV shells when they are considered for merging. If the shells are further apart than this value, they will not be combined.
When we decreased our Auto UV Max Distance, fewer UV shells were eligible for merging. This meant that more individual Charts remained at the end of the process. When we increased our Auto UV Max Distance, UV shells that were very far apart in worldspace were then able to be merged. This resulted in fewer Charts, but this aggressive merging also caused warped lightmap UVs and therefore more distortion in our lightmap output.
Note that with large objects it can sometimes be necessary to increase the Auto UV Max Distance in order to accommodate the size of faces within the mesh. Conversely, with smaller objects decreasing the Auto UV Max Distance might yield better results.
With the example of our object, HouseBig02, an Auto UV Max Distance value of 0.8 gives a good compromise between Chart count and distortion.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Set the value of Auto UV Max Distance to 0.8.
 
Using a Auto UV Max Distance of 0.8 gives a good result with our example object. However, we can still improve this further.
Now we will look at the Auto UV Max Angle parameter. Like Auto UV Max Distance, this value affects the UV merging step of Unity’s unwrapping algorithms. In addition to being tested for distance before UV shells are combined, the unwrapper also tests the angle between adjacent mesh faces. Only edges with an angle below this value will be considered for merging.
A smaller Auto UV Max Angle means that fewer edges will pass the test. As a result, fewer UV shells will be merged and the number of Charts will increase. Conversely, a larger Auto UV Max Angle means that the merging algorithm will be more tolerant of angles between faces. More UV shells are likely to be merged, the result of which will likely be fewer UV shells and therefore fewer Charts. As with the Auto UV Max Distance, if unsuitable edges are combined due to overly wide tolerances, distortion may occur in the final lightmaps UVs.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Set the value of Auto UV Max Angle to 0.
When we look at the Preview area of the Lighting window, we can see that the number of Charts created is unacceptably high. This is because we are only allowing a deviation of 0 degrees or less between faces before they are considered for merging. This almost certainly means that no UV shells will pass the test and therefore many Charts will remain following this merging process.
 
Without some tolerance, a low Auto UV Max Angle will result in an excessive number of Charts.
Next we will try increasing the Auto UV Max angle.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Slowly increase the value of Auto UV Max Angle, observing effects of each change in the Preview area of the Lighting window.
We can see that the number of Charts decreases as the value goes up. This is because the angle permitted between mesh faces considered for merging is more tolerant. More UV shells pass the test and will be merged. Consequently, the number of lightmap UV shells is reduced and the number of corresponding Charts decreases.
 
Increasing the Auto UV Max Angle can help reduce Charts - particularly on objects with rounded surfaces.
An Auto UV Max Angle of 93 yields good results with our example object, HouseBig02.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Set the value of Auto UV Max Angle to 93
Notice how the number of Charts is reduced in the Preview area of the Lighting window following a brief precompute.
 
The Charting preview for HouseBig02 following some optimisation of its unwrap settings.
At this stage, our optimized unwrap settings can be taken back into the working Scene.
  • If HouseBig02 is not selected in the Hierarchy window, select it.
  • In the Inspector panel, locate the MeshRenderer component and click the cog icon in the top right of its display.
  • Click Copy Component.
  • Open the LightingTutorialStart Scene.
  • Find all the objects in the Hierarchy named HouseBig02.
  • Hold down Ctrl (Cmd on the Mac) and click each of the HouseBig02 GameObjects in the Hierarchy window to select them all.
  • Navigate to the Lighting window (Window > Lighting) and select the Object tab.
  • Select the the cog icon in the top right.
  • Choose Paste Component Values to apply the settings you previously copied.
 
Copy Component is an easy way to take your unwrap settings back to the main Scene.
The modest savings these settings give us can add up to much more significant optimisations when applied across a Scene of several hundred objects.

Unwrap settings: per-instance or per-Prefab?

Unwrap settings can be stored in a Prefab by applying them to any Static MeshRenderer component that lives within that Prefab’s hierarchy. Alternatively, unwrap settings can also be applied to individual GameObjects within the Scene. Unwrap settings applied to an instance of a Prefab in a Scene will override the settings stored within the Prefab. This way of working offers us some useful approaches to setting up Scene lighting.
It is often useful to configure a default unwrapping and lighting setup for your Prefabs. If the Prefabs are to be instantiated numerous times, it can save effort to have the unwrapping for that object preconfigured rather than having to specify this repeatedly throughout the Scene.
On the other hand, it is frequently desirable to configure lighting settings based on the context in which an object is used within the overall Scene. For example, if an instance of a Prefab will be seen up close within the playable area then it makes sense to use higher fidelity setting on that instance. If the instance of the Prefab is far away, then it would not make sense to use our lighting budget maintaining the same settings. Here, we would likely want to lower the quality of our lightmaps and use more aggressive stitching parameters in our unwrap.
The ability to configure default settings that suitable for most use cases and then override these settings in special cases can be very useful. In the case of this lighting tutorial, we will be applying our settings per-instance, in the Scene.

Applying unwrap settings throughout the Scene

It is time to start applying what we have learned about Unity’s automatic unwrapping algorithm to the remaining Static geometry within the LightingTutorialStart Scene. Working systematically, it should not take long to set up the Scene for significantly improved precompute times.
  • Open the LightingTutorialStart Scene included in the example project.
  • In the Hierarchy window, select the top GameObject found under Environment > Structures.
  • Copy the GameObject to an empty Scene.
At this point we should apply what we have learned about the unwrap parameters and feel free to experiment with different values. Remember to use the UV Charts Scene draw mode in combination with the Charting mode of the Preview area of the Lighting window. This will enable us to find the right balance between lightmap distortion and the number of Charts required.
The LightingTutorialOptimal Scene can be used as a reference in cases where we are unsure. Note that in some cases it may even be unnecessary to change the default unwrap values at all. The default values may actually provide the best outcome.
  • Experiment with different values for the unwrap parameters until a balance is reached between number of Charts and lightmap distortion.
  • Copy the settings, return to the LightingTutorialStart Scene and paste them into all other instances of the same GameObject. Multi-selecting all the corresponding objects in the hierarchy will enable you to use Paste Component Values to quickly apply the settings across multiple objects.
  • Repeat this process for every uniquely named GameObject in the Hierarchy view.
Once all of the GameObjects under the Structures group have been optimized, move onto the remaining Static geometry under the Rocks group. Working methodically in this way, it should take no longer than a few minutes to set the unwrap values for all of the Static geometry within your Scene. The outcome of this manual preparation will be faster iteration when lighting the Scene and better performance at run time.

8.
Understanding Clusters
Up to this point we have discussed Precomputed Realtime GI in terms of Charts. Reducing or otherwise optimizing the number of Charts in our Scene limits the number of operations such as lightmap compositing and packing required during the precompute. This benefits precompute performance and is a broad approach to reducing the size of the data set required by Unity’s Precomputed Realtime GI solution.
Modifying Clusters is a finer-grained approach which will allow us to reduce the number of operations needed during later tasks in Unity’s precompute process. An additional benefit of reducing the number of Clusters is that run time performance will also be improved.
When generating the Scene’s lighting solution using Precomputed Realtime GI, Unity simplifies the calculations required by working on a voxelized ‘proxy’ of the Static Scene. These voxels are called Clusters. Clusters are effectively surface patches (small tiles) mapped onto Static geometry which we use for lighting. Clusters are stored in a hierarchical relationships and are used for the complex irradiance calculations needed when precomputing Unity’s diffuse global illumination solution. Note that although Clusters are mapped in a similar way to Charts, the two are actually independent.
 
The Clustering Scene draw mode can be used to visualize the size of clusters generated by Unity’s Precomputed Realtime GI.
Clusters sample the albedo of the Static geometry to which they are mapped. Then, during the Light Transport stage of the precompute, the relationship between these Clusters is calculated so that light can be propagated throughout the Cluster network. Unity generates this low resolution approximation of the Static Scene in order to simplify the amount of lighting data which needs to be updated during run time in order to deliver global illumination at interactive frame rates with the limitations of current hardware.
 
Illustration showing how the lighting value of Cluster X is related to the value of nearby Clusters (Image courtesy of Geomerics).
Once the precompute has been completed, ambient (skybox) lighting along with light positions, intensities and colors can then be modified without needing to restart the precompute process. These lighting changes will bounce and permeate throughout the Cluster network, taking into consideration the underlying albedo and emission of the Scene’s materials in the eventual output.
Following this initial bounce, updated lighting results can then be applied to the Clusters themselves. Following each iteration, lit Clusters will be sampled into the corresponding lightmap texture before finally being used by shaders within the Scene.
As this process is performed asynchronously on the CPU, the time it takes to refresh the global illumination solution is bound by the number of available worker threads. If needed, the amount of worker threads can be controlled using the ‘CPU Usage` setting found in the Lighting window.
 
The Lit Clustering Scene draw mode shows the Clusters once light has been bounced throughout the Cluster network.
Clusters can be visualized using the Clustering or Lit Clustering Scene draw mode. Using Clustering, the Scene will be overlaid with a diagnostic pattern made up of multicolored squares. The size of each square represents the size of a Cluster when mapped on to the corresponding Static geometry. Each unique color represents a different Cluster within the Scene. Similarly, the Lit Clustering Scene draw mode shows these Clusters once lighting has been bounced throughout the Cluster network and the results written back to the Clusters.
Reducing the number of Clusters largely determines how quickly this update occurs and, as a consequence, how interactive Unity’s Precomputed Realtime GI appears on your target platform. More importantly, for the purposes of this tutorial, reducing the number of clusters will improve the time it takes to precompute your lighting. As a result, iteration speeds when lighting your Scene will also improve. We will move onto techniques for reducing the number of Clusters in the following section of the tutorial.

9.
Fine tuning with Lightmap Parameters
Many of the advanced lightmapping controls offered by Unity are available through the use of Lightmap Parameters. These settings are stored within a Lightmap Parameters asset. This allows lighting settings to be shared between Scenes and version controlled for shared use in collaborative team environments.
  • To create a Lightmap Parameters Asset, navigate to the Project window.
  • From the Create drop-down menu in the top left of the Project window, choose (Create > Lightmap Parameters).
  • We can also create a Lightmap Parameters asset from the right-click menu within the Project window, or from the top menu bar (Asset > Create > Lightmap Parameters).
 
Advanced controls for both Baked GI and Precomputed Realtime GI are made available through Lightmap Parameters.
Once created, a Lightmap Parameters asset can then be assigned to a Static MeshRenderer component.
  • Select the GameObject that we wish to assign the Lightmap Parameters asset to in the Hierarchy window. The GameObject must be marked as Static and have a MeshRenderer component.
  • Open the Lighting window (Window > Lighting) and select the Object tab.
  • Use the Advanced Parameters drop-down menu to assign the Lightmap Parameters Asset to the GameObject. The ‘Edit’ button to the right of the Advanced Parameters drop-down menu can be used as a shortcut to modifying the Lightmap Parameters assigned to the selected object.
 
Lightmap Parameters are assigned using the Advanced Parameters drop-down from the Object tab of the Lighting window.
The same Lightmap Parameters asset can be assigned to multiple objects. To do this, select multiple objects in the Hierarchy window and then follow the steps above. Changes to this Lightmap Parameter asset will then affect all objects to which it is assigned.

Lightmap Parameters: per-instance or per-Prefab?

Similar to unwrap settings, Lightmap Parameters assets can be assigned to a Prefab or applied to individual GameObject instances within the Scene. Lightmap Parameters assets applied to an instance of a Prefab in a Scene will override the Lightmap Parameters asset stored in the Prefab.
The advantage of this approach is that default Lightmap Parameters that are suitable for most cases can be applied to the Prefab. These defaults can then be overridden on a case-by-case basis in the Scene when more fine-grained control is needed.
In this tutorial, we have chosen to apply Lightmap Parameters assets on a per-instance basis. This is because we want to select different Lightmap Parameters assets depending on the context in which each GameObject is used.

Default Parameters

It is possible to configure Scene-wide default Lightmap Parameters. These default Lightmap Parameters will be assigned to all existing MeshRenderers within a Scene not already assigned a Lightmap Parameters asset. Any MeshRenderers that are then created in the Scene will also use the default Lightmap Parameters. Using this approach reduces the amount of manual assignment which needs to be performed when setting up a Scene for lighting.
  • Open the Lighting window (Window > Lighting) and select the Scene tab.
  • Use the Default Parameters drop-down menu to assign the Lightmap Parameters asset to the Scene.
Note that although this Default Parameter will be applied to all newly created objects, it can still be overridden on individual objects by assigning an Advanced Parameter to the object, as described above.
 
The Default Parameters will be assigned to all newly-created Static Mesh Renders.
Unity provides a number of preconfigured Lightmap Parameters to help quickly set up Scene lighting. These are:
  • Default - HighResolution
  • Default - Medium
  • Default - LowResolution
  • Default - VeryLowResolution
Assigning one of these Lightmap Parameters will configure a number of settings that determine the overall lighting cost of the selected object. These settings include lightmap resolution, global illumination parameters and Cluster resolution, amongst other advanced per-object settings. These are important factors when trying to balance lighting performance throughout a Scene.

Lightmap Parameters explained

Unity’s Default Parameters are intended to cover a number of common use cases and will be generally enough for many lighting scenarios. More fine-grained control over the Precomputed Realtime GI system can be achieved by creating our own Lightmap Parameters assets.
The Unity Manual page on Lightmap Parameters provides an overview of all of the settings contained within the Lightmap Parameters asset. However, in this tutorial, we will focus on the settings that are most useful for lighting optimization.

Resolution

The Resolution value determines the lightmap resolution required by objects using this Lightmap Parameter. Resolution is a multiplier used against the Scene-wide Realtime Resolution specified in the Scene tab of the Lighting window. For example, if the Scene’s Realtime Resolution is set to 2, and the Resolution property is set to 0.5, any objects which are assigned this Lightmap Parameter will use 1 texel per unit in the resulting lightmap texture.
As Precomputed Realtime GI represents only the diffuse, indirect lighting within a Scene, we do not need to use the resolutions required by traditional baked lightmapping approaches. The lightmap resolution required by Precomputed Realtime GI will generally be 2-3 texels per unit as a maximum, as opposed to the 20-30 texels per unit we might use in traditional lightmapping. In most cases, particularly with large outdoor objects such as terrains, this value can be many times lower still. Here, a lightmap resolution as low as 0.1 texels per unit may provide sufficient detail.
 
Dappling artefacts when using high resolution lightmaps can be alleviated by increasing the Irradiance Budget value.
Bear in mind that when using very high lightmap resolutions, artefacts which are otherwise not noticeable at lower resolutions may become an issue. These artefacts may appear as dappling or smudged lighting in the resulting lightmap texture. If this happens, increasing the Irradiance Budget in your Lightmap Parameters can often reduce the appearance of such issues.

Cluster Resolution

Cluster Resolution specifies the number of Clusters that can fit within a texel of a Precomputed Realtime GI lightmap. For example, if Cluster Resolution is set to the maximum of 1 there would be 1 Cluster for each texel within the lightmap. A Cluster Resolution value of 0.5 would mean that only 0.5 Clusters would fit inside the lightmap texel. In other words, the Cluster would be twice the size of a lightmap texel.
Extending this idea further, imagine our Scene’s global Realtime Resolution was set to 1. We create a cube with a size of 1x1x1 units, and then assign a Lightmap Parameters asset to this object. If our Lightmap Parameters asset specified a Resolution of 1 and a Cluster Resolution of 1, we would have 1 Cluster per side of the cube. If we then increased our Resolution to 2, the result would be 2x(1x1) Clusters per side of the cube, giving 4 Clusters.
 
Image showing a 1x1x1 unit cube in a Scene with a Realtime Resolution of 1. The assigned Lightmap Parameters specify a Cluster Resolution of 1 Cluster per texel. Therefore with a lightmap Resolution of 2 texels per unit, we have 4 Clusters per face.
In most cases, Cluster Resolution only needs to be a fraction of the size of our lightmap texels. For example, the Default - HighResolution Lightmap Parameters asset which ships with Unity has a Cluster Resolution of 0.6.
A high number of Clusters in a Scene can quickly drive up precompute times and reduce the interactivity of the Scene’s global illumination at run time. We must therefore ensure that using more Clusters offers some tangible benefit to the quality of the lightmap output. If we can use fewer Clusters without a detrimental effect to our lightmaps, then this is always preferential.
Specifying the Resolution of a lightmap and Cluster Resolution as a ratio means that we can build a relative relationship with the Scene-wide Realtime Resolution value. We can use the Realtime Resolution defined in the Lighting window as a high-level resolution value for the overall Scene. Lightmap Parameters are then used to exert fine-grained control over individual objects or groups of objects.
Unity takes this hierarchical approach in order to offer more global control to the user. If it was necessary to specify an absolute value for Resolution and Cluster Resolution, every Lightmap Parameter within a Project would have to be reconfigured by hand should we want to modify the overall lighting resolution.

Irradiance Budget

We discussed earlier in the tutorial how Unity calculates Precomputed Realtime GI by generating an approximation of a Scene’s Static geometry using Clusters. During the precompute, the relationships between these Clusters are calculated so that light can be quickly propagated throughout this hierarchical network.
Essentially, the value of a lightmap texel is determined by taking a ‘view’ of the Scene Clusters from the texel’s position. This allows us to quickly calculate light bounce between Clusters in order to create the effect of global illumination. These Clusters can then be sampled into lightmaps before finally being rendered.
Irradiance Budget determines the amount of memory used by each lightmap texel when sampling the Cluster network. This determines the precision (accuracy) of the lighting result. A lower Irradiance Budget means that each texel uses less memory when recording this view of the Scene. This results in both reduced memory use and lower CPU cost at run time, but at at the cost of lighting fidelity. Lower Irradiance Budgets will result in a more lower frequency (blurred) lighting result. In contrast, a higher Irradiance Budget will deliver more accurate GI, but increased memory usage and additional CPU overhead at run time.
If our Precomputed Realtime GI is not updating quickly enough (lagging) during run time, it may be beneficial to lower the Irradiance Budget. This is best employed on objects where the advantages of higher fidelity lighting are perhaps not so noticeable, such as large, obscured or distant geometry.

Irradiance Quality

When Precomputed Realtime GI lightmaps are generated during the precompute, each lightmap texel fires rays into the Scene in order to report the visibility of nearby Clusters. The percentage of each Cluster that the texel can see is then calculated. This value is used when determining the lighting contribution of visible Clusters to each texel in the lightmap. Irradiance Quality specifies the number of rays that a texel is able to shoot during this process.
Increasing Irradiance Quality should be considered in situations where objects do not accurately match the lighting conditions of their surroundings. Sometimes situations can arise where lightmap texels have an unexpectedly bright result. This may be because insufficient rays have been cast into the Scene and therefore Clusters which may occlude a lightmap texel have been missed. Similarly, brighter Clusters might not have been detected. Here, the lightmap result will be unexpectedly dark.
Firing more rays increases the likelihood that an accurate representation of the surrounding Clusters is reported back. These improvements to the accuracy of the lightmap output come at the expense of increased precomputation time. To optimize precomputation times, we should use the minimum Irradiance Quality needed to achieve the lighting results we want. Note that this value does not affect run time performance.

Backface Tolerance

Rays fired from lightmap texels can sometimes hit backfacing geometry when gathering lighting from the Scene Clusters. When generating global illumination we are only concerned with the light which bounces from faces which are visible to the world. Light coming from backfacing geometry is always considered invalid. These backface hits have the potential to corrupt or otherwise invalidate the lighting result. Modifying the Backface Tolerance is a way to prevent such situations arising.
 
Here the dark lightmap texels on the floor are created by invalid backface hits during Unity’s radiosity calculations. Increasing the Backface Tolerance settings can be a solution to this problem.
Backface Tolerance specifies a percentage of light that must come from front-facing geometry in order for a texel to be considered valid. If a lightmap texel fails this test, Unity will use the values of neighbouring texels to approximate a correct lighting result.
Modifying Backface Tolerance does not affect the optimization of your Precomputed Realtime GI. Changing this value will not have a great impact on the length of your precompute or affect run time performance. However Backface Tolerance is useful as a troubleshooting tool in situations where you have erroneous dark or light texels which remain despite increasing the Irradiance Budget.

Modelling Tolerance

Unwanted artefacts, such as black halos, can sometimes appear in areas where there are small gaps in the Static geometry within your Scene. This can happen particularly in areas where there is opposing geometry in close proximity. Objects on a floor, for example.
 
Dark fringing artefacts such as there can often be fixed by increasing the Modelling Tolerance.
In these situations, there is a small gap between the object and the opposing surface where little or no light can enter. Very dark texels may be recorded in the lightmaps underneath. At lower lightmap resolutions, the size of the dark texels can mean they extend beyond the boundary of the occluding object and may cause some unwanted black fringing. In the context of lighting, the shadow values these small objects create may be unwanted or otherwise considered as noise.
Modelling Tolerance is used to ignore details smaller than the threshold value. Increasing this value will ensure that Unity’s GI calculations ignore parts of geometry which exist very near another surface. Higher values will force the Light Transport task of the precompute to ignore gaps smaller than this percentage of a lightmap texel. Decreasing the Modeling Tolerance ensures that smaller objects remain considered by the GI calculations.
Modelling tolerance does not affect the optimization of Precomputed Realtime GI. It does not negatively affect precompute times or run time performance. However it can be used when troubleshooting unwanted visual artefacts. Modelling Tolerance may be useful if artefacts remain despite increasing other values such as Irradiance Budget or Irradiance Quality.

Building our Lightmap Parameters assets

Now that we have explored what the various Lightmap Parameters settings provide in terms of functionality, it is time to start applying this knowledge by building our own Lightmap Parameters assets and using them in the tutorial Scene.
  • Open the LightingTutorialStart Scene.
  • In the Project window, navigate to the folder Assets > LightmapParameters.
  • In the top left of the Project window, choose Create > Lightmap Parameters.
  • Name this newly created Lightmap Parameters asset TutorialTerrainLow.
 
The GameObjects are very large in scale and distant from the Camera, this is good case for selecting Lightmap Parameters other than the Scene default.
Next, we are going to assign this Lightmap Parameters asset to objects within the Scene.
  • In the Scene view, select the two mountain GameObjects that are nearest to the playable area. These are both named MountainPeak. Note that we will ignore the furthest mountain for now.
  • Using the Inspector panel, ensure that both MountainPeak GameObjects are flagged as Static. This is indicated by the checkbox marked Static.
  • Open the Lighting window (Window > Lighting) and then select the Scene tab.
  • Ensure that Auto mode is enabled. This is indicated by the checkbox marked Auto.
  • Now select the object Object tab.
  • From the Advanced Parameters drop-down menu, select the newly created TutorialTerrainLow Lightmap Parameters asset. This will assign the Lightmap Parameters asset to the selected GameObjects.
  • Click the Edit button to the right of the Advanced Parameters drop-down menu to begin editing the settings.
 
The default settings when creating a new Lightmap Parameter.
The first parameter that we will look at is Resolution. Reducing the resolution of lightmaps improves both precompute times and run time performance, so we should aim to use the lowest Resolution value that we can without affecting the quality of the lighting.
A higher lightmap resolution is suitable for objects that will be seen up close, but the two instances of MountainPeak are both relatively distant from the Camera. Other factors suggest that a low lightmap resolution would be suitable here. These large objects are generally fairly consistent in the albedo of their materials. Additionally, from the camera’s perspective, there will be little variance in the color of light received by these objects given their scale. Without much lighting detail to capture, we reduce the resolution of these objects’ lightmaps without affecting the quality of the result.
 
For large scenery objects such as mountains and terrain,the default lightmap resolution would be wasteful.
 
Using a lower resolution can be a great saving in precompute and run time performance with little detriment to the perceived quality of the lighting result.
  • Try slowly decreasing the Resolution parameter of the TutorialTerrainLow Lightmap Parameters asset and observe the changes to the lightmap resolution in the Scene view.
Remember, the Resolution value is a multiplier against the Scene-wide Realtime Resolution defined in the Scene tab of the Lighting window. In our Scene, we have opted for a Realtime Resolution of 1. Therefore, if we then chose a Resolution value of less than 1 in our Lightmap Parameters, the resulting lightmap output would be less than 1 texel per unit.
The MountainPeak objects are far enough away from other Scene geometry that they are unlikely to receive any detailed or high frequency lighting. This means we there will be little visual loss should we opt for a lower Resolution. In our tutorial Scene, we have found a Resolution value of 0.05 is enough to capture the very diffuse bounce lighting received by these objects. Enter this value into the newly created TutorialTerrainLow Lightmap Parameters.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, set the Resolution value to 0.05.
Next, we will look at the Cluster Resolution value. As described earlier, Cluster Resolution is a multiplier used against the texel size of any lightmaps generated for that object. At a value of 1, a single Cluster will be the same size as a lightmap texel. Lower values will be fraction of this. Remember that Clusters are essentially a voxelized approximation of the Static Scene used for Unity’s Precomputed Realtime GI. We only need to consider higher Cluster resolutions when the size of these voxels is insufficient to capture the variance in the color of light bounced to or from an object.
Similar to the resolution of our lightmaps, Cluster Resolution can be lowered substantially for the MountainPeak GameObjects. Using Clusters at the default resolution required throughout the rest of our Scene would mean many hundreds were needed to cover an object of this size.
Considering that MountainPeak has a material with a fairly consistent albedo, and the object is relatively far from the Camera, we can make important savings by selectively reducing this object’s resolution. While accuracy of the lighting solution may not be the same as using higher resolutions, we are unlikely to notice any visual difference in the context that the object is used within our Scene.
 
  • Cluster Resolution can be considerably lower for very large objects, far from the Camera.
  • In the top left of the Scene view, use the Draw Mode drop-down menu to select Clustering.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, reduce the Cluster Resolution value. Observe how the size of the colored patches increases as the value is lowered.
Alternatively, the Lit Clustering draw mode can be a useful way to assess whether the resulting resolution of the Cluster approximation is sufficient to capture details present in the Scene lighting.
  • In the top left of the Scene view, use the Draw Mode drop-down menu to select Lit Clustering.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, reduce the Cluster Resolution value. Observe how the view changes as the value is altered.
When adjusting this, it is always good to ask yourself whether any critical lighting detail is missed by using lower Cluster Resolutions. If there is no visual benefit to having a higher resolution, the preference should always be to use fewer Clusters. Remember that the number of Clusters within your Scene will have a big impact on both the length of the precompute and the interactivity of GI at run time. Here, we have found a Cluster Resolution of 0.4 works given the context of the MountainPeak instances.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, set the Cluster Resolution value to 0.4.
 
Lit Clustering Scene draw mode is useful for evaluating whether you have sufficient Cluster resolution to capture the lighting present within the Scene.
In many cases, just lowering the resolution of your lightmaps and Cluster size will be enough to achieve big gains in lighting performance. However, we also can make additional finer-grained improvements by modifying the values used in Unity’s radiosity calculations: Irradiance Budget and Irradiance Quality.
First we will look at Irradiance Budget. As discussed earlier, this value controls how much memory is allocated to each lightmap texel when its value is calculated. In the interests of run time performance, we should use the lowest Irradiance Budget value we can without negatively impacting the appearance of our lighting.
We may wish to increase our Irradiance Budget if our Precomputed Realtime GI appears soft or otherwise indistinct. This can be particularly noticeable in areas where high contrast lighting in the Scene is not being accurately represented
 
The Irradiance Scene draw mode is useful when assessing changes to the Irradiance Budget or Quality values.
In the case of the two MountainPeak GameObjects, the lighting here is generally low frequency. We don’t need to capture any dappled or high contrast lighting, which means that we can reduce the Irradiance Budget from its default value of 128 bytes without noticeable negative effects upon our lighting.
  • In the top left of the Scene view, use the Draw Mode drop-down menu to select Irradiance.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, reduce the value of Irradiance Budget.
  • Notice how, as we reduce this value, the lighting on the MountainPeak GameObject becomes slightly softer.
Following some experimentation, we have found that halving the Irradiance Budget to a value of 64 bytes does not affect the lighting quality too noticeably.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, set the value of Irradiance Budget to 64.
Now we will move on to the Irradiance Quality. As discussed earlier, Irradiance Quality determines the number of rays that each Cluster fires when calculating the value of a lightmap texel. Unlike Irradiance Budget, which will impact run time performance, Irradiance Budget only affects our lighting precompute time.
It may be useful to increase the Irradiance Quality in situations where small but important Clusters are missed due to an insufficient number of rays being fired. For example, in situations where we may have a very prominent color on a piece of geometry which does not feature in the resulting lightmaps.
With our MountainPeak GameObjects, the huge scale of the objects within the Scene means that we are unlikely to miss nearby Clusters. This means that we can improve precompute performance by lowering Irradiance Quality without negatively affecting the lighting results.
  • In the top left of the Scene view, use the Draw Mode drop-down menu to select Irradiance.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, reduce the value of Irradiance Quality.
  • Notice how the resulting lightmaps become slightly less sharp as the value goes down.
Having tested a number of results, we have found that an Irradiance Quality of 2048 rays gives a good compromise between the quality of our GI lighting and the cost this places on our precompute times. Despite some loss in accuracy, the overall lighting effect is sufficient for our needs with this distant object.
  • Select the TutorialTerrainLow Lightmap Parameters asset in the Project window.
  • In the Inspector panel, enter an Irradiance Quality value of 2048.

Assigning Lightmap Parameters assets throughout the Scene

With a Lightmap Parameters asset configured for the distant scenery, we can now apply what we have learned and create Lighting Parameters assets for the remaining Static geometry within the LightingTutorialStart Scene.
We discussed earlier in the tutorial how it is often a good idea to decide on a taxonomy, or ‘scheme’ for organizing objects within our Scenes. Breaking the Scene up into object groupings based on characteristics such as size or proximity to the Camera will help you make easier selections when applying Lightmap Parameters assets to fine tune lighting performance.
While working through the remaining Static objects under the Environment GameObject, look for distinct categorisations of objects in order to assign a shared Lightmap Parameters asset. For example, is the object likely to be close to the playable area and seen up-close? In this case, increasing the Resolution value for this object may yield a tangible improvement in the lighting result. Is the object distant or perhaps partially obscured? Here you would be unlikely to need the same Resolution value as the visual benefits might not be noticed. Similarly, if an object’s material does not feature a great deal of variance in albedo, higher lighting resolutions may not deliver much benefit.
It is not necessary to be too fine-grained when assigning Lightmap Parameters assets. For most Scenes, a handful of distinct of distinct variants is enough. Lots of subtle variants are difficult to work with, as any adjustments will need to be applied numerous times throughout the different Lightmap Parameters assets.
In our completed tutorial Scene LightingTutorialOptimal we have divided the Scene up into the following categories based on the complexity of the object and the required resolution:
  • RocksLow: Smooth, convex rock type meshes that are distant from the Camera. Their distance means these objects only require a low Resolution and reduced Cluster Resolution.
  • RocksMedium: Smooth, convex rock type meshes that are closer to the playable area and the Camera and therefore more visible. For this reason we use a slightly higher Resolution and Cluster Resolution, along with higher Irradiance Budget and IrradianceQuality.
  • StructuresHigh: Important buildings that benefit from higher Resolution and Cluster Resolution. This therefore requires greater Irradiance Quality and Irradiance budget values.
  • StructuresLow: Buildings which are far from the camera, needing only lower Resolution values.
  • TerrainLow: Large, distant meshes such as mountains which do not benefit from higher resolution lighting.
  • TerrainPlayable: Large terrain objects which will be close to the camera and require a lightmap resolution balanced for closer inspection by the Camera. The scale of the object means lower Cluster Resolutions are still feasible however.
  • TerrainVeryLow: Very distant and partly obscured terrain objects needing only low Resolution and Cluster Resolution values. These also have low Irradiance Quality and Irradiance Budget settings.
In addition to these custom Lightmap Parameters assets, in the completed tutorial Scene LightingTutorialOptimal we also have a number of structures using the Default Parameters set from the Scene tab of the Lighting window. Here we are using Unity’s standard Lightmap Parameters Default-Medium.
Using the Default Parameters for the majority of Static objects within the Scene reduces the amount of manual assignment that needs to be performed. It often is useful to set the Default Parameter to be the settings that the majority of objects will use. For our purposes, Default-Medium used in combination with a Realtime Resolution of 1 texel per unit gives us optimal results for the majority of objects within the Scene.
 
The Irradiance Scene draw mode is a useful tool when evaluating Scene lighting as it shows your lighting results without the distraction of materials or non-Static objects which do not contribute to your Precomputed Realtime GI.
Use the LightingTutorialOptimal Scene as a guide when making decisions about assigning and configuring your lighting. It should not take long to assign Lightmap Parameters to the remaining Static objects within the Scene. Remember while you are working through these remaining objects, to always question whether there is an objective benefit to keeping settings high. If it possible to lower settings without negatively affecting the visual output, this will always be preferable.

10.
Summary - Precomputed Realtime GI
Like so many aspects of game development, optimizing Scene lighting is about finding the right balance between desired visual result and performance cost. In many cases, it is worth sacrificing a small amount of lighting fidelity in exchange for reduced precompute times and improved run time performance.
 
Our tutorial Scene with a nighttime lighting treatment applied. Following our initial precompute, no further precomputation was required while generating an alternative lighting solution. This would be impossible with ‘traditional’ baked lightmapping techniques.
In this tutorial we have:
  • Explored how to evaluate our Scenes to make appropriate decisions about lightmap resolutions for Precomputed Realtime GI.
  • Learned that one of the most costly elements in lighting precomputes is the number of Charts in our Scene, and examined a number of techniques that can reduce Chart counts.
  • Set up efficient Light Probes volumes for use by small props and debris-type objects.
  • Looked at how adjusting the parameters of Unity’s Precomputed Realtime GI unwrapping algorithm can help it make better decisions about stitching lighting UVs, therefore reducing the Chart count.
  • Explained what Clusters are, how they are used to calculate global illumination in Unity and how they can affect lighting performance.
  • Experimented with using Lightmap Parameters to fine tune resolution and lighting fidelity for objects within the Scene, reducing the precompute costs of objects that are less visually important.
Employing all of these techniques together should enable you to create production-quality lighting results in your Scenes with minimal precompute times. Combining this with the ability to quickly iterate on lighting with realtime updates to GI, plus the ability to change bounced lighting at run time, it quickly becomes apparent how Unity’s Precomputed Realtime GI can be an attractive option for many realtime applications.
For further reading, please see the ARM Guide for Unity Developers here.