Hello fellow Cookie Destroyers,
In this developer log, I want to talk about the lighting for Mega Giga Cookie Destroyer TD. This means we will get deeply technical in this log.
I implemented a ray marched lighting system with a GPU-based precomputed distance field.

Introduction
In the world of 2D lighting, there are basically just three components to consider: the light source, the occluders, and the unlit image we get from the rendering. This means our approach is a post-processing effect applied on top of the rendered image.
Using Rays for lighting
We want to display lighting realistically. This means light should respect occluders and show sharp rays on the edges.

To achieve this, we use a form of ray tracing that allows us to simulate the light. In a brute force approach, we could just go from each pixel to the next pixel and check if we found an occluder. This would involve a lot of computation, as each pixel would need to be checked on each ray. There is a ray for each light in the scene to each pixel on the screen. You see how this escalates into burning GPUs very quickly.
PS: No GPU has been harmed during the development of Mega Giga Cookie Destroyer TD
To reduce the number of checks we have to do, we can use signed distance functions to calculate a distance field of our scene. With a signed distance function, we can get the distance from the current pixel to the nearest occluder. This means we can move at least this amount along our ray.
Pre computed distance field
A distance field is a one-channel texture that holds, for every pixel, the distance to the nearest occluder. This is essential information we can use to move along rays in a lightning-fast way.
To generate a distance field, we need to build the signed distance function from our scene. This sounds complex, but in Mega Giga Cookie Destroyer TD, we mostly need rectangle and circle occluders.
If you really want to see the math behind this, take a look here:
Signed Distance Functions. We can combine distances to different shapes by simply taking the minimum of the distance to each shape.
Now we use a shader (a program that runs on the GPU) to build our distance field with a lot of math and move that to the actual ray marching lighting shader.
Lighting
Calculating light in 2D is actually pretty easy if we forget about the occluders for a second. We have a point somewhere in our scene. This point gets a color and a strength value. We can use the distance between the current pixel and that point to decide how much of an effect this light has. The farther away the light, the lesser the effect it has.
Now we just add the ray marching into the mix. We check with a ray if there is something between our current pixel and each light in the scene. If there is nothing, we color the current pixel with the light. If there is something in the way, we leave the pixel untouched. And that is about it.
Conclusion
Does a 2D tower defense game need fancy lighting? I hope so. Eye candy is a big value for these kinds of games, though I have to admit, it is very tempting to turn this up to 11. :)
Stay tuned for more updates, and thank you for joining us on this technical journey through the lighting system of Mega Giga Cookie Destroyer TD. We hope you enjoy the visual improvements as much as we enjoyed creating them!
PS: This approach does not need some fancy ray tracing hardware ;)
PSS: If you want to know more about ray marching, you can ask me questions on the
Discord[ 2024-07-14 09:24:56 CET ] [ Original post ]