April 24 2023
By Rubén Torres Bonet
April 24, 2023
So, you want to make a game where you have tens or hundreds of real-time lights, huh?
Good luck with that, my friend.
No, I’m joking. You don’t need luck, you need knowledge.
So, at some point, when you are a game developer, you might want to make a game, or your boss will tell you to make a game that has a lot of lights, right?
Like look at this scene that I have here. Tons of juicy real-time spot lights.
Is this scenario actually doable?
As you know, we have mainly three pipelines in Unity: Built-in, URP and HDRP. Currently, we’re talking about URP.
HDRP is great with deferred shading, as we can virtually have an endless amount of lights. But deferred shading doesn’t scale well with tile-based renderers, that’s why we don’t use HDRP over there. Sorry!
In URP, you are stuck with forward rendering, right?
Are you? … Are you really?
Let’s have a look, because Forward Rendering is MAYBE not the only thing that you have.
If I go to the project settings, you will see the rendering path. Here’s how it looks on my end.
Traditionally, for mobile we always choose forward rendering. Which means: every time that you draw an object, e.g. this floor, you send it to the GPU pipeline and it goes from zero to finish. Rendering this floor sequentially follows several steps: vertex shading, rasterization, fragment shading, blending, etc..
So the rendering of your objects just goes forward.
With forward rendering, performance is really good when you have a little amount of lights, but when you go over a certain amount of lights, complexity and performance explodes. BANG. In fact, you have an upper limit of eight real-time lights that may affect a single object at a time.
Like, just look at the earlier screenshot. I have over 30 lights, but how many do you see? Not as many.
There’s a limit to this because we can’t pay enough performance currency to render so many real-time lights in the forward rendering path in URP. I elaborate on the reasons behind this on the Performance Taskforce membership.
So, what can you do when you reach this limit?
But this becomes impossible in some situations.
Have you played Quake-like games? You can shoot rockets at your foes. These rockets emit light. So guess what happens when 20 players shoot every second. 40 lights affecting the floor, yummy.
Okay, so where do we go from here?
This toy is a new render technique called Unity URP Forward+ (Plus). Just go to your URP asset and change your rendering path to Forward+ like below.
The limit of eight real-time lights per object is not there anymore. Now it is… well, it depends. 16, 32 or 256 real-time lights PER camera depending on your target hardware and graphics API.
So just select Forward+ (Plus) in URP and forget?
Not really. I suggest you to understand how the Forward+ rendering path works in URP in comparison to Forward. Because it has other sort of performance implications, as I explain in the Performance Taskforce membership.
The summary is:
Forward+ (plus) aggregates all this light information into clusters so that in the fragment shader, you just need to iterate over iterate over these clusters. And then it becomes easy&fast to do the light calculations in there. Instead of iterating over every light, we just iterate over clusters, reducing the data set that we have to access in memory on the GPU.
I encourage you to understand how this works and then do your own research because there are many options other than just blindly following the advice of a random guy on the internet (that being me in this case).
I hope I helped you become aware of alternative solutions other than the boring Forward rendering path.
If you want to see more stuff or more numbers or more explanation and more technical background and all of that, you know where to go to (Performance Taskforce membership) or book a consulting call with me.
I hope you have a good day and happy game developing. And make sure to make your players happy with nice visuals.