Over the coming months we’ll be offering an inside look at some of the numerous improvements and features we supported, and how we plan to bring these learnings back into the engine. Today we’re kicking off with a focus on how Unity 5.4 helped in the implementation of ReCore’s global illumination (GI) solution. First, here is a screenshot of a ReCore level.
Unity supports a couple of ways to compute GI for a scene. One way is to use Enlighten to bake lightmaps that contain the GI information for the surfaces in the scene. Another way is to bake the GI information into light probes. Both systems can be combined and used for different purposes in a typical scene. Lightmaps are good for large static objects and the light probes are good for use with dynamic objects. For large outdoor areas lightmaps will use more memory than light probes. Armature wanted a global illumination system that had short bake times and didn’t have the added memory overhead of baked lightmaps. To accomplish these goals we developed a global illumination system that baked the bounce light into Unity light probes by capturing cubemaps at the probe locations. Then the light probes were used as the only source of GI for all the objects in the scene. However, using Unity’s light probe system to provide the GI for large environmental objects can result in lighting inconsistencies between objects.
This blog post will discuss the process of fixing this issue in ReCore using the new Unity 5.4 feature Light Probe Proxy Volumes (LPPVs) and discuss some best practices. Wondering what LPPVs are and how to use them? Please read our earlier blog post.
The Unity light probe system assigns light probes to objects based on the world position of the objects. If an object is close to multiple light probes the contribution will be blended between these light probes. For small dynamic objects like characters this gives good results. However, for large objects that can cover a large area, this system will produce inconsistent results since a single light probe that is interpolated at the object’s anchor point is used to shade the entire object. In theory, you need to shade the object with an interpolated light probe per pixel to get a nice positional gradient. This is especially apparent on large objects where the lighting can vary drastically over the surface. In ReCore we ended up with Figure 1 below as a result.
In Figure 1, the highlighted area is clearly receiving a different GI contribution and this looks incorrect. To get consistent lighting there needs to be a way to apply the GI contribution across the surface of the object smoothly. LPPVs to the rescue!
In Unity, LPPVs can be attached as a component to any GameObject that has a MeshRenderer component or a MeshRenderer component can be forced to use a particular LPPV that is in the scene.
Attaching a different LPPV to each renderer was not practical as it would use too much memory, and might result in inconsistent lighting between objects. Instead, ReCore used single LPPV to cover large areas of the level with many renderers sharing the same LPPV. The LPPVs were added as a component to the Light Probe Groups and custom scripts were written to assign MeshRenderers to the LPPV that contained them. We found that arranging the light probes in a grid pattern gave good results and wrote some custom scripts to automate this process. Here’s a top down view of a typical LPPV set up in a ReCore level.
Here is what the setup of the light probe group and a typical mesh renderer looks like in the editor.
After the artists set up the LPPV and baked the lighting the resulting GI was much more consistent as seen in Figure #2.
In Figure 2, you can see the GI contribution in the highlighted area looks consistent. There is also a more gradual change in the GI contribution across the large rock structure. The lighting in ReCore is static so the update cost of the LPPV is limited to when they are loaded. This keeps the CPU cost of using LPPVs minimal. Also, the size of the LPPV texture sent to the GPU is small and adds only 3 more texture samples during the g-buffer pass so the impact on overall GPU time isn’t noticeable.
Unity 5.4 and LPPVs made it possible to ship ReCore’s custom GI solution without sacrificing quality. Stay tuned to the Unity Blog for more upcoming posts highlighting other aspects of the ReCore game development process in Unity.