Godot Version
Godot v4.2.1 and v4.3-stable
Question
My project is dark by default, and I’ve hit a wall trying to create a specific lighting vision. Every solution I’ve come up with brings its own problems.
Goal
-A dark gameboard grid with moveable game pieces.
-The screen and gameboard itself are fully dark while the game pieces are providing light.
-Lights from the pieces interact with normal maps on both the gameboard and the other pieces.
-Differently colored lights blend colors together when overlapping.
Solution - PointLight2D and Sprite2D nodes out of the box
-CanvasModulate node to darken the canvas to black.
-A gameboard made up of tiled Sprite2Ds with a CanvasTexture (solid white diffuse texture / normal map texture with white being highest point and black being lowest).
-Game pieces are instantiated from a scene containing a Sprite2D (textured similar to the gameboard tiles) and a PointLight2D (colored depending on game piece type.)
The idea being that PointLights add their color and light information to the sprite, which would show a rounded tile (thanks to the normal map) blended with the various colors of light that hit it.
Problem 1 - Cap on 2D Lights
When things weren’t working right, I searched further and discovered Godot’s cap of 15 for lights. Once a sprite renders lights to this cap it ignores any additional lights. Since my game pieces are 64x64 pixel sprites with 320x320 pixel light textures, and these pieces place right next to each other onto a grid of 64x64 squares, the light cap is reached very easily. There doesn’t seem to be a way to select which lights are rendered, so trying to prioritize either moving lights or the closest 15 lights doesn’t seem to be an option.
The most widely recommended solutions I found was to chop up the sprites into smaller bits or reduce the radius of light textures to avoid a situation where a sprite sees too many lights. Sprites are already only 64x64 pixels, but I decided to try compromising the effect and reducing the light texture to under 192x192 pixels. This reduced the lit area, and now a tile surrounded completely by other game pieces is only hit by 9 lights. Tiles moving over the pieces have a 6 light cushion (it still hits the cap when more tiles pass over it but it’s far less obvious at all times).
It compromises the full vision I had but it still seemed workable at this point.
Problem 2 - Mix Blend Mode Doesn’t Work
Lights kept adding their brightness to each other, washing out the colors and sprites and getting very bright. Height peaks on the normal map were behaving oddly when lights hit it from both sides. Changing the blend mode to Mix instead of Add solved both these visual issues, and since brightness is pretty similar on all my lights the interpolation between colors is not an issue.
However, PointLight2Ds set to Mix blend mode only work on sprites that are in the scene when the light is instantiated. Any sprites added to the scene after a light will not render that light at all. Doing nothing but changing the blend mode back to Add fixes the problem immediately, but nothing I have tried can make it work with Mix mode. I opened a bug report:
Whether it is a bug in the engine or some unique user error, I can’t find further information about solving this issue. Ultimately this makes my preferred solution unusable for the time being.
Solution - Additive Sprites:
-Use additive sprites for lighting instead of light 2Ds.
I found this suggested as a cheaper and easier way to handle lighting.
Problem - No Normal Maps
To my knowledge there isn’t a way to use normal maps using this method. Since the normal maps are the only piece of the Sprite2D that has visual information, any method that doesn’t use them won’t look right.
Solution - Lighting via Shader:
-Use a custom shader that takes in distance to all light locations, and does the math on the fragment pixels based on those distances, light colors, and normal map values.
Problem - Don’t Know What I Don’t Know
To this point I’ve used and made shaders only minimally, so I’d have to dive in and upgrade my knowledge to get something like this going. At the end of the day I don’t know enough to understand how feasible this is. A lot of the restrictions on 2D lights seem to be from trying to simulate a 3D space in a 2D environment, and redraws to the Canvas take a lot of resources.
If I go this route won’t I be faced with the same problems as those who made the original 2D light nodes anyways? Will I spend all my time on this only to find the same hard limits already imposed on me?
Solution - Make the Project in 3D
-Just do it in 3D. Lights are cheaper so go nuts.
Problem - Would Have to Give Up on Project Vision:
I’m smitten on the stylistic choice of dark 2D sprites with normal maps lit up by light textures. No one would confuse it for realistic 3D lighting but the unique look of it is the charm for me on this project. I would need to head back to the drawing board with my artist and re-conceptualize the art direction, then ask for all new assets.
Conclusion
I haven’t been able to solve my problem, and am not sure which, if any, of the solutions I’ve came up with are worth persuing. Does anyone have any suggestions, ways they’ve solved a similar problem, or see anything I’ve completely missed? Is my best bet to call it on the 2D lights and just convert to 3D, get the project out, and move on with my life?
Thanks in advance for any thoughts!