[Recommended: read the original blog post "Unity ray-traced global illumination" for proper interactive content]
Let's get back to ray tracing with global illumination in Unity. Discover what global illumination is and choose the better fit for your game:
- Baked GI
- Screen-space Raster GI
- Screen-Space Ray-traced GI
TABLE OF CONTENTS
Can You Guess What's Missing in This Scene?
Take a second to have a look at the screenshot below.
Can you guess what is this picture missing to be... visually "appealing"?
It's looking either too bright or too dark. That's not an easy thing to see in real life.
Because light bounces between surfaces.
These bounces soften the "transitions" between bright and dark areas. And you don't see that happening in the screenshot above.
Now, let's see something more realistic.
Have a look below. Use the slider to transition to a more "visually correct" scene:
What's the difference?
Global illumination (GI). To be more specific, indirect illumination.
Let's quickly explain how GI works.
What's Unity Global Illumination?
Like I said, light rays bounce off surfaces and lose energy in the process (e.g. brightness, a change in color, etc.). Eventually, light will reach your eyes from different surfaces.
In graphics, we distinguish between:
- Direct lighting: the sun light hits the floor and reflects into your eyes. That lets you see that specific fragment on the floor.
- Indirect lighting: the sun light hits the floor, bounces to your hand watch and then bounces towards someone's eyes. That person becomes temporarily stunned.
The difference is that GI takes more bounces into account. Not just one.
Direct lighting is easy and cheap to calculate. Indirect lighting, not so much.
So, how do you do indirect lighting* in Unity?
Here are your options.
* I use the words indirect lighting and global illumination interchangeably. In theory, they're not the same. But in practice, we treat them as if they were.
Your Options for Global Illumination in Unity
Let's build an ultra-simple scene to see and compare the different methods you have in Unity to do global illumination.
Here's the scene we are building:
Light Bounces Global Illumination Diagram
First, take a deep breath and enjoy my drawing skills.
Now, let's explain it.
A wall is covering/occluding another wall, which in real-life would prevent light from reaching it.
However, there's a small gap below.
This bottom gap will allow some sun rays to "escape" the big wall and reach the wall behind after these rays bounce off the floor.
The diagram is clear, right?
Here's how our baseline (just direct lighting + shadows) looks in Unity.
Global Illumination Scenario
We won't use that angle. It's hard to see the effect of indirect lighting later on.
Here's a better angle.
Global Illumination Baseline (No GI)
The wall behind is quite dark.
No global illumination means light is not bouncing. Our black shadow on that wall remains untouched with no secondary light rays coming in.
Not what you want in your game. Nope.
So let's improve this scenario and add some GI with our first method: baked global illumination(Unity Lightmapper).
Unity Baked Global Illumination
Baking global illumination is the cheapest way to do global illumination.
We do all these expensive calculations offline (in the editor). That process produces textures that we later "paint on top" of our scene.
It takes some effort to get the results you want with this method, as there are many settings to play with. And baking takes time.
But once you get it right, it looks great.
In fact, it's probably the best-looking method out there to do (static) global illumination.
Well, it only works with static geometry.
I mean, you can use light probes to add some indirect illumination to dynamic (moving) elements. But that also goes with many downsides.
Anyway, let's see how it looks.
Use the slider to see the evolution from no GI to baked GI.
* You know what I mean. Not the simplified scene per se, but the indirect lighting.
However, did you ever play an interactive game with just static elements?
No, you say?
That's why we need more options.
One is to use light probes together with baked GI. The issue with light probes is that you need many of them to have smooth indirect lighting transitions. And guess what? That's going to break batching for good.
Let's consider instead something else: Screen-space (Raster) Global Illumination.
Unity Screen-Space Global Illumination (SSGI)
The idea with SSGI is simple. It's execution is not.
We analyze the rendered frame (G-buffer) and guesstimate the way light should bounce between surfaces that are within that frame.
Again, we don't do that for the whole scene. Just for the current rendered image.
Doing this effect in screen-space makes this option affordable in terms of performance.
Use the slider below to find out what SSGI paints on top of our baseline.
Screen-Space Global Illumination (SSGI)
A small tint of red.
Not much else.
Here is in detail the indirect lighting that we are adding to our baseline:
Unity Global Illumination: Screen-Space Effect
That's a very shy effect. Quite different from baked GI, isn't it?
That's one of the limitations of SSGI: accuracy. Two reasons for this:
- We have incomplete information (the G Buffer, information about our lights and that's about it).
- We have a low performance budget: we need to keep this effect cheap.
But hey, it works with dynamic elements. And in real-time
Can we do better?
What if we used ray-tracing for global illumination?
After all, with ray-tracing we have access to off-screen data. And that removes a limitation of this method.
Let's check out ray-traced SSGI.
Ray-Traced Global Illumination in Unity
This is getting exciting.
If your project is ray-tracing-ready, you just need to click a checkbox in your screen-space global illumination effect: enable ray-tracing.
Use the slider below to discover it.
Ray-Traced Global Illumination
Here's the singled-out effect that ray-tracing GI is adding to our baseline:
Unity Global Illumination: Ray Traced Effect
Indeed, ray-tracing gets you good-looking indirect lighting. And it works with dynamic elements... in real-time.
The question is, can you really afford ray-traced global illumination in Unity?
Let's analyze the performance cost of these effects.
The Performance Cost of Ray-Traced Global Illumination in Unity
Here are some quick tests I ran with:
- CPU: AMD Ryzen 2700X
- GPU: TITAN RTX beefy edition
- Dataset: 3000 frames taken on the editor
- Scene: HDRP template
- Versions: Unity 2020.2.0b7 + HDRP 10.0.1
Here are the average frame times at full-HD resolution:
- Baked GI: 27.64ms
- Baked GI + SSGI (low quality): 28.19 ms
- Baked GI + SSGI (medium quality): 30.36 ms
- Baked GI + SSGI (high quality): 32.96 ms
- Baked GI + Ray-Traced SSGI (performance mode — low quality): 32.07 ms
- Baked GI + Ray-Traced SSGI (performance mode — medium quality): 32.88 ms
- Baked GI + Ray-Traced SSGI (performance mode — high quality): 34.81 ms
- Baked GI + Ray-Traced SSGI (quality mode): 107.91 ms (ouch)
And here are some of these numbers at 4K resolution:
- Baked GI: 106.21ms
- Baked GI + SSGI (medium quality): 114.56
- Baked GI + Ray-Traced SSGI (performance mode — medium quality): 119.77 ms
- Baked GI + Ray-Traced SSGI (quality mode): 421 ms (OUCH)
Why did I take them all with baked GI, you might ask? Well, I removed the baked lightmaps and the entire scene broke for good. Like visually, all was pure white.
Don't take these times as absolute figures.
After all, it's a specific scene, a specific software/hardware setup and within the editor.
But you can compare the relative frame times and see how performance scales on this high-fidelity scene.
You get the idea.
Two interesting questions arise (and two subjective answers):
- Are we ready for 4K real-time ray-traced GI? Nope.
- Ok, and are we ready for 1080p real-time ray-traced GI? Yeah, maybe.
It depends on your game.
But if you put enough optimization effort into it, you can get real-time ray-tracing global illumination in. It's feasible.
Just run it on performance mode at 1080p and you'll be fine on most NVIDIA 2000+ cards (and maybe even on the NVIDIA 1000 series).
And the importance of performance brings me to...
How much did you like real-time ray-traced global illumination?
Well, you can get RTGI in your game if you make enough performance room (and all other Unity ray-tracing effects as well).
And nothing better* than my Unity Performance Optimization Checklist for that.
* Unity performance consulting is better (but not many can't afford it).
Till next time,
(The Gamedev Guru)