godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.73k stars 20.12k forks source link

2D light limit not documented and does not provide feedback #92952

Open Avantir-Chaosfire opened 3 months ago

Avantir-Chaosfire commented 3 months ago

Tested versions

Tested on 4.2.2.stable.mono.official

System information

macOS 14.5

Issue description

https://github.com/godotengine/godot/assets/11003232/6d72b5af-7efe-47b9-acde-eb1476c9e2f1

When many PointLight2Ds are added to a scene, they can get culled even when in full view. You can see the video that many of the light sources only become visible when near the edge of the screen, while others are visible all of the time.

From my testing, this works the same in editor and in game.

Steps to reproduce

Put a lot of PointLight2Ds in one scene (or load the Demo project) and move the camera around, causing the lights to go on and off screen. They should disappear even when still on the screen.

Minimal reproduction project (MRP)

BadlyCulledLighting.zip

AThousandShips commented 3 months ago

This looks like you're over the limit of lights per object and these lights aren't culled they're just not affecting the object until there's few enough other lights affecting it

These limits seem to be undocumented at the moment though

Related:

Avantir-Chaosfire commented 2 months ago

@AThousandShips Thanks, yeah I think you're right, I didn't know about that. It would be great if this could produce a warning in the editor when it happens, otherwise it just looks like lights don't work properly, and the dev will have no idea why. If it's just in documentation, it will still be hard to find.

AThousandShips commented 2 months ago

I don't think you'd be able to check it in the editor except cases where the lights are in specific positions, but yes this should be documented

But detecting this isn't simple and would still miss cases where the object isn't behind that many lights specifically when in the editor, and the obvious first step when something isn't working right IMO is to read the documentation

Avantir-Chaosfire commented 2 months ago

I'm not a rendering expert so probably just not understanding, but I'd assume when you load up the buffer with the lights to send to the shader, you could simply check if the total # of lights is greater than the max capacity of the buffer, and throw a warning if so. In fact, there must already be some code checking that to prevent a buffer overflow.

AThousandShips commented 2 months ago

You can but the error would be pretty meaningless, as there's no way to tell what node is associated with the item being rendered, so all it'd say would be that some item can't be lit, it'd also spam the error

In general development such an error would give no useful information to the user and you wouldn't really be able to fix anything based on it except by going through visually to find the offending item, which should show up anyway, so it'd just be annoying rather than helful IMO

The checking for what light should be affecting which item is also internal to the renderer for performance reasons and isn't known externally, so it can't be checked that way either, so the information simply doesn't exist to make a helpful error message

crayonape commented 1 week ago

I'm not a rendering expert so probably just not understanding, but I'd assume when you load up the buffer with the lights to send to the shader, you could simply check if the total # of lights is greater than the max capacity of the buffer, and throw a warning if so. In fact, there must already be some code checking that to prevent a buffer overflow.

Hi, did you find a solution to this problem? I also encountered this problem and I needed to launch "many" fireballs in a very dark night, so Sprite2D as an alternative did not seem feasible.

AThousandShips commented 1 week ago

Again, please ask in other community channels not here

crayonape commented 1 week ago

Again, please ask in other community channels not here

Forums, discord, stackoverflow, reddit, youtube, and believe me, github is the last place I would look for solutions to my problems because I know it will bother others, but I really have no other choice.

Avantir-Chaosfire commented 1 week ago

@crayonape Quoting myself from the thread linked above:

  • The 2D light cap is 15, not 16.
  • The cap is per node - drawing multiple textures from the same node won't help. I think this is because the shader material is applied to the node itself, and that's what has the limit.
  • The cap is not smart. It doesn't care if the lights are overlapping each other, and it treats every node as a rectangle. This means even if you have a non-rectangular polygon that is only directly overlapped by 15 lights, but there's a 16th light that doesn't overlap the polygon but does intersect the same rectangular area as your polygon, it will count towards the cap, and one of the lights actually on your polygon probably won't render.
  • If you are using dynamic lighting, you have to limit yourself to a VERY SMALL number of dynamic lights. In my project, I can only have one dynamic light that can be arbitrarily instantiated, and fixed number of other dynamic lights. That limits me to about 10 static lights per node, assuming it's very unusual for there to be more than 4 of the arbitrarily instantiated lights.
  • For most sources of dynamic lighting, you're probably better off using glow, as it has no such limit (but is much harder to control on a node by node basis and doesn't support shadows).
  • If you're looking for more extreme options, you can:
    • Create a custom build of the engine and increase the light limit yourself (no idea how to do this, it would be nice if someone else could provide guidance)
    • Reimplement the lighting system on your own in-engine, using Node2Ds with a custom script to represent lights, and passing those to a shader via a buffer which you can choose the size of. I haven't experimented with this at all, but it should be possible. Basic, no-shadow lights should be pretty simple, but it's gonna get complicated if you want shadows.