Unity VR Optimization Lighting

Lighting can make a game go from bland to incredible. With the correct light we can help build strong player immersion in our VR experience. The one drawback is that lighting can quickly add to our draw calls and burden our VR experiences to the point that it’s no longer playable.

Let’s fix that by optimizing our lighting. 

To start off, we’re going to use the Universal Render Pipeline (URP). If you don’t have that installed, please follow this guide and come back once you’ve set things up.

Side Note : Lights Not Working

The URP introduces a ton of customization, which gives us a tons of power, but it also introduces tons of complications. If you’ve recently converted a project to URP and your lights aren’t working, consider some of these options for troubleshooting. 

The first option is to check our URP Asset settings.

  •  Select your URP Asset
    • Under Lighting
      • Main Light = Per Pixel
      • Cast Shadows = True
      • Additional Lights = Per Pixel or Per Vertex
      • Per Object Limit = <= 1 (More lights will requires a higher number)
      • Cast Shadows = True
If your lights still aren’t appearing, we can also try clearing the Unity preference cache.
 
  • Edit -> Preferences -> Gi Cache -> Clean Cache

For myself, the second option is what fixed my lights from not appearing.

If you’re experience missing lights, hopefully one of these solutions helped. If not, make sure to post the solution in the comments below!

With that out of the way, let’s focus back on optimizing our lights.

Universal Rendering Asset Settings

Let’s fix our URP Asset settings and go over what they do.

  •  Select you URP Asset correlated to the quality setting you’re currently using
    • Under Lighting
      • Main Light = Per Pixel : The other option is to set this to Disabled, which will prevent our main camera from rendering.
      • Cast Shadows = True : This option should be turned off if our project is baking all of its lighting or if we don’t need shadows. No shadows = better performance. We may want to leave this on if our main light is doing Mixed
      • Shadow Resolution = 2048 : The higher the resolution, the higher quality shadows at the cost of performance.
      • Additional Lights = Per Pixel : Per Pixel will give us higher quality lights at the cost of performance. Per Vertex is also an option if our performance is being hindered too much by our extra lighting.
      • Per Object Limit = 4 : If we have more than one light source, then this setting will determine how many lights that are not Main Lights that are allowed to render in the Scene. 
      • Cast Shadows = False : It is recommended that instead of having our lights cast shadows here, we should instead bake our additional lights in the Scene. If we have additional lights that need realtime shadows, then we would leave this on at an significant performance cost.

With that we have our light settings ready in the URP Asset. Keep in mind that there are a ton of adjustments that we’re able to play with in that small section to get the most performance vs quality. Now let’s look at shadows.

  • Distance = 50 : This determines how far in front of a camera objects can cast shadows. If our players can be confined to a smaller viewing distance, we can reduce this and save some performance and memory. 
  • Cascades = 2 : This determines how detailed shadows will be when the camera is near. The higher the number, the more it will cost in performance.
  • Depth Bias = 1 : Adjust this if you’re experiencing strange shadow artifacts on your objects
  • Normal Bias = 1 : Adjust this if you’re experiencing strange shadow artifacts on your objects
  • Soft Shadows = False :  If we’re trying to get higher performance, this is a easy one to leave out. Although it helps make the edges of our shadows softer and more realistic, the performance cost isn’t worth it if we’re trying to deploy to something like the Quest 2.
That’s it for shadows and lights in our URP Asset. Now lets take a look at setting up lightmap baking!

Lightmap Settings

To bake our lights, we first need to open a few windows. First, let’s open the Lighting Explorer.

  • Window -> Rendering -> Light Explorer

 

With this menu, we’re able to see all of our lights in the scene and change them to Baked, Mixed or Realtime. Since we’re trying to optimize our project, we should try to make all the lights baked if we can. If we still need to have real time shadows from some, we may want to try making them Mixed and only use Realtime as a last resort. 

Now let’s open the Lighting Menu.

  •  Window -> Rendering -> Lighting

This is the Lighting menu that will allow us to bake out lights in our Scene. Before we start baking lights, let’s go over some of the options. 

  •  Under Realtime Lighting
    • Realtime Global Illumination = False : This helps create more dynamic illuminations for real time lights. Think of a sun moving across the sky and changing the lighting of objects in a Scene. This has a high performance cost, which is why we set it to false.
  • Under Mixed Lighting
    •  Baked Global Illumination = True : This setting will allow us to simulate Global Illumination and bake it to improve performance with our Mixed Lighting. 
    • Lighting Mode = Subtractive : This will let our mixed lights to have direct and indirect lighting. The drawback is that it only will allow one Directional Light to produce real-time shadows. If we’re aiming for low end devices (Quest 2), this setting is ideal. I’ll go into more detail on mixed lights in a different tutorial.
  • Under Lightmapping Settings
    •  Lightmapper = Progressive GPU : For this setting, I’ve chosen progressive GPU. It’s still in “preview” so it is not a completed product. Essentially, this setting determines how our PC will generate the baked light map. Since my GPU is quicker, I find this option to be best for myself.
    •  Multiple Importance Sampling = True : This leads to faster convergence when generating lightmaps, but it can lead to noisier lightmaps. If your lightmaps are baking with a lot of noise, try turning this off.
    • Direct Samples = 32 : This determines the number of samples the Progressive Lightmapper uses for direct lighting calculations. Lowering this will reduce the time to bake lightmaps.
    • Indirect Samplers = 512 : This controls the number of samples that the Progressive Lightmapper uses for indirect lighting calculations. Raising this increases quality, but will take longer to bake the lightmap.
    • Environment Samples = 256 : This controls the number of samples used for environment lighting calculations. 
    • Light Probe Sample Multiplier = 4 : This helps controls the amount of samples that are used for Light Probes. It is a multiplier for all of the above attributes. Again, the higher number here, the longer the bake calculation will take. 
    • Bounces = 2 : This determines the number of indirect bounces to do when tracing the paths of light. 2 is the recommended amount for the majority of scenes.
    • Filtering = Auto : This helps remove noise from a bake scene. Auto will work for now!
    • Lightmap Resolution = 20 – 40 : This determines the resolution of our lightmap. The higher the number, the higher the quality. It will increase the lightmap size and time it takes to bake. While testing our baked maps, it’s recommended to put this at a lower number so we can quickly bake our scenes and raise it once we’ve prototyped enough.
    • Lightmap Compression = Normal Quality : This can help reduce the size of our lightmaps, but at the cost of introducing artifacts into the lightmap texture.
    • Ambient Occlusion = False : Ambient occlusion gives us further customization for our lightmaps. It includes options for changing the Max Distance for our rays to cast, how bright our indirect lights act and how bright our direct lights act.
    • Directional Mode  = Non-Directional : This allows us to store information about the dominant light at each point on a GameObject. With Directional, it will generate a second lightmap to store the dominant direction of the incoming light. Non-Directional does not generate a second lightmap, but store it within the same lightmap that is generated. This reduces the size, but it will not allow for diffuse normal-mapped materials to work with the GI.
    • Albedo Boost =  1 : This increases the amount of light Unity bounces between surfaces by intensifying Albedo Materials. 
    • Lightmap Parameters = Medium :  This allows us to select a few predefined settings for our Lightmap. We can also create our own custom settings for this. For now, let’s stick to the predefined options given to us in Unity.
As we can see, there is a ton of customization that comes with baking our Lightmaps. The best way to approach baking lightmaps is to experiment with lower resolutions and settings, then increase them once we’re happy with how our scene looks.
Before we start baking, we have a few more steps to go over.

Generating Lightmap UVs for Imported Models

If we have imported Models into our scene, we should make sure that we’ve set them up properly for light baking. To do that, we do the following.

  • Select a Model that we’ve imported that we wish to be baked.
  • Under the Model Tab
    • Generate Lightmap UVs = True
    • Click “Apply”

 

Next, let’s make sure our object in scene are contributing to the Global Illumination.

contribute to Global Illumination

To have our object contribute to Global Illumination, we need to make sure that they are not moving. There are two ways to make sure that they contribute to Global Illumination with our lightmaps.

  • Mark the Object in Scene as Static 

or

  • Select “Contribute Global Illumination” on the Mesh Renderer of the object that is not moving.

With that done, lets start baking our maps!

Baking Our Lightmap

It’s been a long journey, but we’re finally here. It’s time to bake our  Lightmap. 

  • Under the “Lighting” window
    • Click “Generate Lighting” in the bottom right

This may take a few minutes, but once completed, Unity will have generated a Lightmap in our Scene. This will give us the power of shadows and indirect light bouncing around without the cost of doing it all in real-time calculations. 

This tutorial is only a brief introduction into lighting and light maps. In order to fully understand it, we should experiment as much as possible to grasp all the customization available