Forward+ rendering, also known as tiled forward shading, is a rendering technique that combines traditional forward rendering with tiled light culling. This reduces the number of lights that must be considered during shading, significantly lowering computational costs for scenes with many dynamic lights.
By the end of this guide, you should be able to:
Understand the pros and cons of Forward+ rendering on Quest to decide if it’s right for your project
Use the correct Universal Rendering Pipeline (URP) package to enable Forward+ in Unity
Know best practices for maximizing performance with Forward+
Installation
To enable Forward+ rendering, follow the URP package installation instructions below:
Download the package for your Unity version from the Oculus-VR fork of Unity’s URP GitHub repository:
In your project, locate the URP Asset and URP Renderer currently in use. If these aren’t created yet, do so now by selecting Assets > Create > Rendering > URP Asset (with Universal Renderer).
In the URP Renderer, change Rendering Path to “Forward+”.
In the URP Asset, expand the Lighting section and disable both Probe Blending and Probe Atlas.
Note: The Probe Atlas checkbox is only available in our custom URP fork. If you don’t see the option, you may be using the wrong URP package.
If your project targets multiple platforms (i.e., PCVR), you may have multiple sets of URP Assets that need to be updated. For PC assets, you may be able to keep Probe Blending and Probe Atlas enabled if testing yields acceptable performance.
Optimization Details
Here’s a quick overview of how Forward+ works in Unity and why the original implementation is slow on Quest devices.
Traditionally, Forward+ works by creating a 2D grid structure in the view frustum. Lights and reflection probes are then binned into tiles in the grid if the light or reflection probe radius intersects with that tile. Unity goes one step further by also dividing the view frustum along the z axis, creating a 3D grid of z-bins. This narrows down the lights and reflection probes even further for each z-bin in the view frustum. The data inside the grid is updated every frame on the CPU and is then passed to the GPU.
With lighting and reflection information now stored in the grid, the GPU can now calculate which cell a fragment intersects.
The lighting and reflection probe information in that cell is used to calculate the resulting color for that fragment.
This is different from Forward where lighting and reflection probe information is stored per object. For more details
on how Forward+ works in Unity, check out
Unity’s Forward+ Rendering Path
documentation page.
The problem for Quest is the reflection probes. In Unity’s unmodified Forward+ implementation, reflection probes cannot be disabled, and a more complex form of reflection probe blending using a texture atlas is implemented. With Quest’s limited performance, this extra work of calculating reflection probes and sampling from a reflection probe atlas simply costs too much and easily puts applications over the frame budget. The changes in our custom URP fork allow you to disable the reflection probe atlas. Reflection probe blending is also simplified to only sample the two nearest probes if needed. This way, we can avoid costly operations while retaining the performance benefits of the tiled light culling that comes with enabling Forward+.
Visualizing Lighting Complexity
Lighting complexity can be visualized with a debug shader included in the Oculus-VR URP branch. Change your mesh material to Universal Render Pipeline > Debug > ForwardPlus to see the visualization. Below is an image showing what happens when you apply the debug shader:
The visualization shows tiles and how many lights are intersecting those tiles. The scale progresses from green to yellow to red to white as lighting complexity approaches 32 lights per tile. Use Meta XR Simulator when visualizing since tile sizes can differ based on the target device.
If the scene contains areas with many dynamic lights, add the debug shader to objects around the lit area to identify hot spots (tiles that are shaded red or white). Moving the camera can also vary the view frustum, creating different visualizations with hot spots. If performance is still lacking after enabling Forward+, try modifying your scene to reduce lighting pressure in areas with high lighting complexity.
Best Practices
Forward+ certainly has advantages over Forward rendering in scenes with many dynamic lights. But for projects that have low dynamic light count, or scenes composed of very small meshes, we recommend sticking with a Forward renderer. Fewer lights means less work per fragment, so if there are only a few dynamic lights, it may not be worthwhile to switch over. And small meshes are good because Unity has a per object optimization that makes lighting calculations in these situations faster.
When your project requires a decent number of dynamic lights, we recommend testing Forward+ to see if you get better performance. In some testing, we’ve seen Forward+ start to perform better at around 5 lights. Here’s a graph that compares Forward and Forward+ by showing how GPU frame time increases with the number of lights in Unity’s Viking Village URP sample:
GPU Resident Drawer
Enabling Forward+ also gives you access to a feature introduced in Unity 6.0 that may be useful for certain projects:
GPU Resident Drawer. When enabled, Unity will try to draw GameObjects using GPU instancing, which can reduce draw calls
and provide some CPU performance improvements. Savings are most noticeable in larger scenes that utilize a high amount of
instancing. If you are already enabling Forward+, we recommend exploring this option for some potentially free performance
savings.savings. To learn more, see Enable the GPU Resident Drawer in URP in the Unity documentation and the GPU driven rendering community forum post.