2D Lighting From Sun

I have been developing a game for over a year now and I have successfully implemented the basic foundation for lighting, but there are still a few things I'm struggling with. The biggest issue right now is the lighting that should be cast from the "sun". The sun should technically light up any block that doesn't have a lot of blocks above it covering up the light that should be reaching it.

The way the current light system works is through a flood-fill algorithm that goes block to block recursively setting light based on different conditions. The light is recalculated when a light source is placed or a block is broken and the algorithm is very efficient. Currently I have a basic implementation of sun where the highest block has light generated straight down from it until the light "runs out". This works when first generated, but doesn't look natural. One case where there's problems is if there is a single block 10 blocks above the terrain which would cause the terrain to be unlit under that block because it didn't receive any sun.

I have been doing research and trying out different techniques, but nothing has worked well and efficiently. Any suggestions are appreciated.

Here is an image of the game in it's current state. You can see the lighting issue with the tree blocking the light of the ground.

• on what data structure are you operating? 3D-blocks or 2D-tiles? – Benedikt S. Vogler Sep 29 '16 at 12:06
• 2D tiles, I had a link to the game but it was removed. I've added a picture of the game in it's current state. – Jmrapp Sep 29 '16 at 15:39

2 Answers

I think your problem is in the way you have chosen to structure your lighting model. It looks like you want the tiles closer to the surface to be more lit than the tiles deep in the ground (if I'm wrong, clarify this). That's all well and good, but that shouldn't be done with a lighting system per se because in actuality, everything under the top 1 inch of earth should be completely black.

That being said there is something you could do without reworking your whole model, I think. Appears that, in order to get your desired "effect", you have designed it such that the top tiles are having a shadow effect on tiles deeper in the earth, and the deeper or further away from the top tile they are, the stronger the shadow effect is. Further more, it looks like you are having the treetops have the same effect, and since the top layer of ground is pretty far away from the treetop, it is having a pretty strong shadow effect. Right?

Method the First

Ok, so what to do about it? I would probably just flag tree elements as not being shadow casters. That should fix the immediate issue.

Method the Second

The other option would be to redesign your shadow method in this way

if (tile has other tile directly above it){
tile shade increase by 4
}
if (tile has other tile two spaces above it){
tile shade increase by 3
}
if (tile has other tile three spaces above it){
tile shade increase by 2
}
if (tile has other tile four spaces above it){
tile shade increase by 1
}


What this will do is cause a penumbra effect which is how shadows really work. When something is far away, it's shadow is weaker than when it is really close. But this pseudo code I wrote will still cause an accumulative effect on a tile that has other tiles piled on it, so if you play with the numbers you'll get the same basic effect as in your current model, with the benefit of a penumbra model.

• I understand what you're getting at and that's a very basic implementation of what I already have implemented. Flagging the tree elements as blocks that don't cast shadows will not solve the problem however. Say for example that someone grabs a dirt block and places it 5 tiles about the ground layer, that should technically create a shadow, but because the light adjacent to it "generated" by the sun should override the shadow that it casts. – Jmrapp Oct 18 '16 at 0:45

One way to do this would be to take into consideration the block types that the 'light beam' passes through - e.g. if there's a non-air block ten blocks above ground, then the light beam would note that, continue on through the next nine air blocks, then hit the ground with less (but still some) light than it would have done if the non-air block hadn't been in the way. If your light beams are currently coded to illuminate the next ten blocks as soon as they hit a non-air block, that might be the part that needs to change so that they effectively carry on until they've a) run out of steam through hitting blocks or b) go past a predefined plane that could be the bottom of the screen.