URP - Limited number of pixel lights, why ?

Hello,

I am making shooter similar to doom/quake/unreal tournament and I just decided to add point light to my projectiles just to make it prettier. And as expected, I reached the limit of 8 pixel lights very fast.

6780623--784754--upload_2021-1-29_20-21-5.jpg

If you look at Unreal Tournament (game from 1999), then you can see that projectiles were emiting light. And since its multiplayer game, there could be hundreds of those lights and the game had no problems at all.

6780623--784769--upload_2021-1-29_20-31-22.jpg
6780623--784772--upload_2021-1-29_20-31-49.jpg

Now, over 20 years later I am limited by 8 real time lights which I really don't understand as my knowledge about rendering is very basic.

So could someone please explain to me why is that ? Maybe these are not actual lights but just some kind of a "fake" lights since it has to be very performant ?? But since it actually enlightens dark areas I am very confused..

I am using URP with forward rendering and I would love to achieve similar effect without being limited to 8 lights.

Thank you very much for answers.

4 Likes

In URP's defense UT wasn't doing PBR and I think I remember it mostly used vertex lighting instead of pixel lights. However, you are totally right about the light limit being too low. They should at least make that configurable for the forward renderer.

That said I don't think the light limit will really change anytime soon unless their deferred renderer doesn't share that limitation. For the forward renderer to scale well they would need to do something like tiled forward or cluster shading instead of the brute force loop they do at this point. I also don't recall URP being able to mix vertex and pixel lighting either like built-in can do once you have too many pixel lights. So at this point if the deferred renderer can't get around this then I don't think you can do anything about it with vanilla URP.

Hey!
For many small lights (like in your example) it definitely makes sense to use deferred rendering.
This is soon to be released for URP. Actually you can try it out on the Unity-Technologies/Graphics master branch right now if you'd like.
This gif running the deferred renderer hopefully shows that what you want is possible:
6787790--786284--DeferredBattle.gif

24 Likes

That is such a tease! Cant wait to experiment

[quote=“Jonas-Mortensen”, post:3, topic: 826574]
Hey!
For many small lights (like in your example) it definitely makes sense to use deferred rendering.
This is soon to be released for URP. Actually you can try it out on the Unity-Technologies/Graphics master branch right now if you’d like.
This gif running the deferred renderer hopefully shows that what you want is possible:

[/quote]

1 Like

thank you guys.. so I'll be looking forward to deferred renderer. Hopefuly its very close to release :)

1 Like

[quote=“Jonas-Mortensen”, post:3, topic: 826574]
For many small lights (like in your example) it definitely makes sense to use deferred rendering. This is soon to be released for URP. Actually you can try it out on the Unity-Technologies/Graphics master branch right now if you’d like.
[/quote]
Hi @Jonas-Mortensen - I’ve upgraded my 2021.1 project to URP 12 from Master.
I tried to create a new Deferred Renderer Data to assign to a URP Asset’s Renderer List, but when I click Create->Rendering->Universal Rendering Pipeline-> it only lists Forward Renderer. Is that because there’s no such thing as Deferred Renderer Data and we’re just supposed to use Forward Renderer Data asset? If I just switch to Deferred Lighting in that I get warnings in the URP Asset about both OpenGLES2 and OpenGLES3 not being supported. Does this mean WebGL isn’t capable of it? Which Graphics APIs are supported (or will be)? Thanks !

We also have a forward+ renderer in progress, which is adding a novel form of light tiling to our existing forward renderer. This will allow you to go well beyond the 8 light per object limit with the forward renderer without the inherent limitations of deferred rendering (deferred renderers do not support msaa and we also need to fallback to the forward renderer for transparent complex lit materials):
https://portal.productboard.com/unity/1-unity-graphics/c/261-forward-renderer-support

The reason there is currently an 8 light limit per object is because of performance considerations. Ideally, light data should fit entirely into constant buffers, because they are consistently fast universally across all platforms, whereas structured buffers are a lot slower on a lot of platforms. Without tiled/clustered lighting, there is a per object classification for the forward renderer, as we need to loop over all lights over all objects O(num_objects*num_lights), but with forward+, the performance will only be relative to the number of visible lights within each tile.

We are considering making the light limit configurable, but this would require us to use the slow structured buffer path, which will potentially keep your games from being able to run on lower tier hardware. We are making URP as fast as possible across all hardware, but every new feature requested adds complexity to the existing renderer, so we are working very closely with all hardware vendors to define a universal fast path.

14 Likes

[quote=“nigeljw_unity”, post:7, topic: 826574]
We also have a forward+ renderer in progress
[/quote]
We just recently finished our own version of a cluster shading forward renderer in URP and I can say it has been invaluable to have. We don’t have to worry about old devices so I think the work was much simpler but this is something you guys should have in the near future. I look forward to it!

1 Like

[quote=“nigeljw_unity”, post:7, topic: 826574]
We also have a forward+ renderer in progress,
[/quote]

Awesome!

Curious will you guys do a forum/blog/documentation post going into details about the deferred, forward+, and original URP forward?

2 Likes

@Bosozuki The documentation for deferred is in progress. There will documentation for forward+ considerations as well when the feature lands.

There is a presentation on URP's deferred renderer from Arm's Moving Mobile Graphics at Siggraph last year:
https://community.arm.com/developer/tools-software/graphics/b/blog/posts/moving-mobile-graphics

Please feel free to ask any questions in the meantime. @adamgolden I will get back to you with an explicit answer to your questions.

4 Likes

[quote=“nigeljw_unity”, post:10, topic: 826574]
@adamgolden I will get back to you with an explicit answer to your questions.
[/quote]
Cool - thanks :slight_smile:

[quote=“adamgolden”, post:6, topic: 826574]
Hi @Jonas-Mortensen - I’ve upgraded my 2021.1 project to URP 12 from Master.
I tried to create a new Deferred Renderer Data to assign to a URP Asset’s Renderer List, but when I click Create->Rendering->Universal Rendering Pipeline-> it only lists Forward Renderer. Is that because there’s no such thing as Deferred Renderer Data and we’re just supposed to use Forward Renderer Data asset? If I just switch to Deferred Lighting in that I get warnings in the URP Asset about both OpenGLES2 and OpenGLES3 not being supported. Does this mean WebGL isn’t capable of it? Which Graphics APIs are supported (or will be)? Thanks !
[/quote]
To enable deferred renderer in project, after adding packages to local package folder, you need to add Scripting Define Symble “ENABLE_RENDERING_PATH_UI” in project settings player. After that rendering mode will appear in Forward Renderer Data’s UI, and there you go.

1 Like

[quote=“BobFlame”, post:12, topic: 826574]
To enable deferred renderer in project, after adding packages to local package folder, you need to add Scripting Define Symble “ENABLE_RENDERING_PATH_UI” in project settings player. After that rendering mode will appear in Forward Renderer Data’s UI, and there you go.
[/quote]
6923696--812399--enable_deferred_lighting_for_urp_12.jpg

It’s now available to select - thanks! I’ll see if I can get the unlimited-ish point lights feature running in my project this weekend for a glance at compatibility/performance implications. I might have to wait on Forward+ but it’s worth a look either way. WebGL 2.0 is currently my baseline platform and I haven’t heard back yet from @nigeljw_unity :smile:

2 Likes

great news on Forward+ that's really beneficial for stylized projects that can't rely on the deferred gbuffer but want more lights.
Is there a specific branch on the graphics github or is it still early compared to Deferred?

1 Like

[quote=“adamgolden”, post:13, topic: 826574]

It’s now available to select - thanks! I’ll see if I can get the unlimited-ish point lights feature running in my project this weekend for a glance at compatibility/performance implications. I might have to wait on Forward+ but it’s worth a look either way. WebGL 2.0 is currently my baseline platform and I haven’t heard back yet from @nigeljw_unity :smile:
[/quote]
Did you get the unlimited point lights to work? I did choose the deferred option but it actually did not change anything. Did you follow a specific step that I missed? It still just turns on 8 lights a time.

1 Like

It's not compatible with WebGL.. I got as far into trying as seeing the warnings.

I didn't actually realize this was the reason I could pick up to 8 lights now though, just figured that was a recent change I hadn't noticed :roll_eyes:

[quote=“adamgolden”, post:16, topic: 826574]
It’s not compatible with WebGL… I got as far into trying as seeing the warnings.

I didn’t actually realize this was the reason I could pick up to 8 lights now though, just figured that was a recent change I hadn’t noticed :roll_eyes:
[/quote]
I am not using WebGL. Does the function for you work without?

1 Like

I just confirmed it's working in Windows 10:
6955751--818720--50_realtime_point_lights.jpg
6955751--818723--50_realtime_point_lights_2.jpg

Instructions..
- create new URP template project (I'm using 2021.2.0a9)
- in Hierarchy, delete everything except "Main Camera" and "Post-process Volume"
- add the ENABLE_RENDERING_PATH_UI thing noted above
- change Lighting to Deferred (select ForwardRenderer in Project window)
- create a new 3d object->plane
- drag the 'Ground_Mat' material from Project window onto it
- add the DeferredPointLightsTest component to it
- enter play mode
- during play mode, select the Plane with the component, then in the Inspector,
- drag/change the number of lights and animation shape

DeferredPointLightsTest.cs

// @polemical, Unity Forum
using UnityEngine;
public class DeferredPointLightsTest : MonoBehaviour
{
  public float animationShape = 1;
  public int numberOfLights = 50;
  private int prevNumberOfLights = 0;
  public Vector3 offset = new Vector3(-5, 0.2f, 0);
  public Vector3 spread = new Vector3(10, 0, 0);

  private GameObject[] instances;

  private Vector3[] instanceOrigins;
  private void Start()
  {
    Regenerate();
    prevNumberOfLights = numberOfLights;
  }
  private void Regenerate()
  {
    Clear();
    numberOfLights = Mathf.Clamp(numberOfLights, 1, 50);
    Vector3 instanceStep = spread / numberOfLights;
    Vector3 instanceCenterOffset = instanceStep * 0.5f;

    GameObject prefab = new GameObject();
    Light light = prefab.AddComponent<Light>();
    light.type = LightType.Point;
    light.intensity = 1;

    instances = new GameObject[numberOfLights];
    instanceOrigins = new Vector3[numberOfLights];
    for (int i = 0; i < numberOfLights; i++)
    {
      instanceOrigins[i] = offset + instanceCenterOffset + (instanceStep * i);
      instances[i] = Instantiate(prefab, transform);
      instances[i].GetComponent<Light>().color = GetRandomLightColor();
      instances[i].transform.localPosition = instanceOrigins[i];
      instances[i].name = (i + 1).ToString();
    }
    prevNumberOfLights = numberOfLights;
    Destroy(prefab);
  }
  private void Update()
  {
    if (prevNumberOfLights != numberOfLights) Regenerate();
    if (instances == null) return;
    for (int i = 0; i < instances.Length; i++)
    {
      instances[i].transform.localPosition = instanceOrigins[i] + new Vector3(
        0, 0, Mathf.Sin((Time.time + (i * 100)) * animationShape)
      );
    }
  }
  private void Clear()
  {
    if (instances != null)
    {
      for (int i = 0; i < instances.Length; i++)
      {
        Destroy(instances[i]);
      }
      instances = null;
    }
  }
  private Color GetRandomLightColor()
  {
    return new Color(
      Random.Range(0.5f, 1.0f),
      Random.Range(0.5f, 1.0f),
      Random.Range(0.5f, 1.0f)
    );
  }
  private void OnDestroy()
  {
    Clear();
  }
}

:)

1 Like

I think URP has an 8 lights limit on the number of lights in front of the camera
Why do you need more than 8 lights in front of the camera at the same time durin play mode ?
The lights are generally fixed and use a light shaft and projector for real-time light simulation in other multiplayer players...
The difference between a projector and real light is in casting shadows
The use of too many lights is a sign of weakness in the design

[quote=“aliyeredon2”, post:19, topic: 826574]
The difference between a projector and real light is in casting shadows
The use of too many lights is a sign of weakness in the design
[/quote]
Would you mind sharing a way to do this without lights? There’s no shadows in it:
https://discussions.unity.com/t/826574/3