Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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.

share|improve this question
    
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. –  Twitchy 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 'MindWorX' Mariager Dec 13 '11 at 4:04
add comment

closed as too broad by Josh Petrie Dec 5 '13 at 6:50

There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.If this question can be reworded to fit the rules in the help center, please edit the question.

3 Answers

up vote 4 down vote accepted

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).

Adding some shading on the surface with Ambient Occlusion

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.

Make the shading continuous instead of tile-based

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]).

Then simply read this color back in your pixel shader (which will automatically interpolate it across your quad's surface for you due to gouraud shading) and multiply it by the color you have read from the texture. This will allow smooth gradients within your tiles.

share|improve this answer
    
Each chunk is 128x128. There can be a maximum of 120 columns of tiles on the screen at once. Would a flood fill be too expensive? Also, could you explain in what way would you do ambient light, I want the lighting to be smooth, not tile based brightness. –  Twitchy Dec 13 '11 at 2:40
    
The flood fill would be done on the entire map once as a preprocess, and then only once for a single column whenever a tile changes. Should be okay I think. –  David Gouveia Dec 13 '11 at 2:42
    
As for smoothness: ambient light typically affects everything equally (well that's the way it's usually approximated by default in graphics hardware anyway). If you want it to change smoothly you'll want to combine it with another technique, such as a variation of ambient occlusion. Check my answer back in 3 minutes, I'll edit something in. –  David Gouveia Dec 13 '11 at 2:43
    
Oh wait maybe you meant that you didn't want the entire tile to have the same brightness, but rather to transition smoothly from the neighboring tiles? Misunderstood. Well that could be done too, editing some more info in. –  David Gouveia Dec 13 '11 at 2:56
    
Good edit, this poses some good ideas that I will try implement tonight. It will also mean that I will need to recalculate each column in the vicinity of the changed tile thats top tile is at tune same level or above. If I wanted to then pass light to tiles below the surface, that would mean having to do calculations for those tiles aswell right? –  Twitchy Dec 13 '11 at 3:09
show 7 more comments

Does this answer your question?

“But how do I get global (ambient) lighting (with or without shadows)? I don’t want the rest of the “world” (background) to be pitch black.” Just render a quarter-strength (64,64,64) quad over the ShadowCaster map.

share|improve this answer
add comment

You should look into raycasting :)
Here is a very nice tutorial on how it works!
Use a vector, to create the point-light effect.

share|improve this answer
2  
This is basically a link-only answer. Try explaining some of the concepts yourself here. Make your answer useful even in the event the link goes dead. –  Sean Middleditch Jun 30 '13 at 0:58
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.