I'm working on a 2D project with large and open maps, and am looking for ways to tackle large numbers of lights in such an environment. I have something that technically works but feel it is the wrong approach.
Generally what I have been doing in 2D games for lighting is drawing all the lights additively to get like a simple lightmap on a flat plane, then multiplying that with the rendered scene.
Previously these have only been lights I defined by having the lights as textures/sprites of appropriate colour and brightness, and with the view focused on a character can only see a few and it looked OK not using a proper lighting curve (way more linear so as to reach 0 after a few hundred pixels) in confined spaces. But it doesn't look so good in an open map, especially when zoomed out with lights feeling like spots and very dark areas between.
Now just computing the proper light value in a pixel shader for any distance and brightness is fairly simple, "intensity / distance^2", this has the problem with never reaching zero (in fact with just that equation, Id need a fullscreen quad for every point light in existance...).
I thought of just limiting it to a value that does not contribute much, e.g 1/255 of the highest of RGB (so if a light has an RGB of say 1.0, 0.9, 0.9 at 1m, I only draw it up to about 16 metres). But these quads are still massive and kill performance for 100's of lights. For example with just 15 lights:
Worse if there is multiple lights a similar distance from a point, the cutoff is clearly visible as they would have accumulated to something significant (consider that a lot of brighter LED lights are just a pack of individually less powerful LED's). Rendering each light out to a further distance with this solution will have even more performance consequences, while not fully solving the problem.
Is this a sensible lighting approach? Is there another equation to use that looks real while reaching 0 quickly? Do games do something clever to "combine" light sources at greater distances?
At this time I am not worrying about shadows as making 2D angled objects cast correct shadows presents a bunch of new problems, but I may want to in the future if can be done without having 3D models for every building, etc.
float4 main(Input input) : SV_TARGET
{
float4 delta = input.light_position - input.world_position;
float dist_sqr = dot(delta, delta);
return input.color / dist_sqr;
}