Search Unity

Global Illumination in ReCore: Our Work with Microsoft & Armature

, October 4, 2016

It’s no secret: we love hearing from our developers. From feature requests to feedback, the community helps ensure that Unity is always improving in order to help you do your jobs better. But to really do our jobs, we think it’s important to eat a bit of our own dogfood, too. So when some of us had the opportunity to work with Armature and Microsoft Game Studios on the Xbox One and Windows game ReCore, we couldn’t pass up the chance.  What resulted was a deep exploration of console development in Unity 5 has opened our eyes in some surprising ways.

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 Problem With Light Probes in ReCore

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.  

Figure #1 - Light Probe GI

Figure #1 – Light Probe GI

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!

LPPV Setup In ReCore

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.


Figure 2 – GI with LPPV

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.

16 replies on “Global Illumination in ReCore: Our Work with Microsoft & Armature”

This is excellent work, guys! I recently started doing this for my game levels since I didn’t want to wait for baking out lightmaps, and LPVS behaved as predicted… clean lighting across an entire surface. I also used Pre-Computed lighting since it was fast to bake and the results were clean. I am making a 2.5D fighter and lighting was the number 1 thing I wanted to nail correctly. A+ right here.

I don’t even set my levels to static anymore.

This is a nice post with some advanced features.

But maybe you should make the engine honor culling mask when using baked lighting and GI soon? Bug reports on this has been postponed.

I’m looking into doing something like this myself (baking cubemaps to light probe SH coefficients), but I appear to have hit a brick wall – namely, that it seems light probe coefficients are no longer accessible from script. How exactly is ReCore doing this? Do they have source code access or something? Or is there some way I’m supposed to be able to change probe coefficients via script (because LightmapSettings.lightProbes.bakedProbes is an empty array, despite LightmapSettings.lightProbes.probeCount returning the correct number of light probes in the scene)

Ah, actually I found the problem – it only works if I disable precomputed realtime GI. Otherwise, even assigning my own coefficients has zero effect (which sorta makes sense, I guess).

I saw that Enlighten 3.04 and 3.06 (on their blog) brought a lot of speed improvements in the precalculation of the GI and also in the runtime of the GI. I think one in particular is of much interest for the case stated in this post about ReCore’s trouble with large objects : “Per pixel probe interpolation (PPPI) is a feature that improves the visual quality of large, static objects that are lit by probes.”

Great post and really interesting too. Never heard of the previous inconsistencies but I’m glad it got fixed. Keep up the great work!

Really nice to see that more and more developers are considering Unity for their games, and the results are unbelievable. Show how much the engine has come from the v4 days.
One thing that got my attention is load times as they talk about it in this video and some other reviews of this game:
My guess is that it’s caused by loading all the baked lighting data and seems to be CPU-limited and not an IO problem. I wanted to know if this is something you’re aware of and/or looking into improving? Or is this can be improved by optimizations from the dev’s side?

Honestly light baking is still one of the greatest pains in the Unity. I loved what you achieved here but yet I’m not 100% sure how you achieved it. Please as soon as possible create a live training exercise in a real life scenario. I mean lighting a very small room with 3 lights is easy but lighting a whole area as in this game… That’s where I fell short.

We are currently working on a detailed tutorial about optimising large scenes for precomputed lighting. Look out for it on our Learn area in the next few weeks, we’ll naturally promote it via social channels too.

In their blog, Enlighten stated that with version 3.04 brought some improvements for terrains and with version 3.06 for large objects.
I don’t know though why I get from their posts that these features are just for Unreal Engine 4 (which is not included by default and needs a separate license).
I think these new features would make Enlighten in Unity 5 a lot more… likable :)

Comments are closed.