# 2D XNA Tile Based Lighting. Ideas and Methods [closed]

I am currently working on developing a 2D tile based game, similar to the game 'Terraria'. We have the base tile and chunk engine working and are now looking to implement lighting. Instead of the tile based lighting that terraria uses, I want to implement point lights for torches, etc.

I have seen Catalin Zima’s shader based shadows, and this would be perfect for the torches (point lights). My problem here is that the tiles on the surface of the world need to be illuminated, doing this by a big point light is firstly extremely expensive, but also doesn't look right.

What I need help with (overall) is...

1. To have a surface that is illuminated regardless of torches, etc.
2. To also have point lights, or smooth tile lighting similar to Catalin Zima’s shader based shadows.

Looking forward to your replies. Any ideas are appreciated.

• When you say you want your surface that's illuminated, do you mean "surface" as in above the ground, or do you mean that you want some kind of ambient light that your point lights add on to, or what? – Tetrad Dec 12 '11 at 8:03
• Ahh sorry, I mean "surface" as in above the ground. – FrenchyNZ Dec 12 '11 at 8:36
• You never model the sun as a point light anyway. The sun is usually modeled either as a constant ambient contribution which is added to everything, or as a directional light. Check my answer for a simple way to handle this. – David Gouveia Dec 13 '11 at 2:27
• @Twitchy, I'm also currently working on an XNA tilebased game. If you want to discuss implementations and exchange ideas, you can hit me up on my email address found on my profile. – William Mariager Dec 13 '11 at 4:04

Finding the surface and applying ambient light

To find which tiles are on the surface and should receive some ambient light, in a very simple way, how about doing a one dimensional (vertical only) flood fill starting from the sky?

In other words, you start at the top of your world, one column at a time, and search downwards until you hit a solid tile. All tiles that you search this way (including the solid tile) will be considered as being on the surface and get a constant light contribution added to them (i.e. you draw them a bit lighter).

For example something like this (where # is a solid tile, and . is a tile that will receive ambient light):

..........................
..........................
..........................
..........................
..........................
.....##########.###.......
..############ .#####.....
.#########     #########..
.#########  ############..
#####      ###############
##########################
##########################
##########################


Then just do the torches and everything else as point lights.

Finally, while I don't feel it's necessary, but if you also wanted to have the sun cast shadows on the surface, you should model it as a directional light rather than a point light (since the sun is "infinitely large and infinitely far away" for practical purposes). That basically means that every shadow will be coming from the same direction (i.e. forming the same angle).

Method 1

If you'd like to add some variation to the lighting on the surface so that not every tile has the same brightness, you could try to compute some sort of ambient occlusion factor for the "surface tiles".

The easiest way, without having to rely on raycasting, would be to simply count the number of neighboring tiles that can block the sun light.

The basic idea is for each solid tile on the surface, count how many other solid tiles there are in the immediate surroundings (at the same level and above it). Use this number as a factor to decide how much light it should recieve.

For example:

.#.#.    .....
.#@#.    .#@#.
#####    #####


Consider the @ a solid tile. In the first example there's 4 solid tiles surrounding the @ while in the second example there's only 2. Thus the @ in the first example would be drawn darker than the @ on the second example.

This method has the disadvantage of only working on the surface, and being a somewhat crude approximation.

Method 2

Another alternative that will give better results but be a lot more expensive, would be to start with the entire world illuminated, and then for each tile do a series of raycasts towards the sky (in several directions, all along the hemisphere surrounding and above the tile) and count how many collided with terrain. Then darken the tile depending on the number of collisions.

This would allow ambient light to sip into caves and shed a little light into the underground too which would look pretty cool.

The biggest disadvantage besides having to do the raycasts is that you would need to compute this for every tile, not just the surface ones.

For this you'll need to use a pixel shader and do the previous calculations per vertex instead of per tile.

Each tile will be a quad, so start by calculating and storing how much light reaches each individual vertex of the quad. This could be for stored for instance instance as a grayscale vertex color (ranging from [0,0,0] to [1,1,1]).