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.