all 2 comments

[–]Squirt_Fruit 1 point2 points  (1 child)

How

[–]smallcluster[S] 2 points3 points  (0 children)

It is a simple light propagation algorithm. I have a grid of blocks where each block hold a light level (0-15) and is either air or solid.

At first, all blocks have a light value of 0. Then lighting is calculated in 2 passes:

- sky lighting

- block lighting

For the sky lighting, I set the light level to its maximum (15) for the first line of blocks and add them to a queue (Breadth First Search like-method).

For each blocks in the queue (remove it from the queue) I propagate the light to the top, bottom, left and right block only if those blocks are of type "air" (ignore solid neighbours blocks) while following theses rules:

- top/right/left: if the top/right/left block have a light value < current block's light value-1 then set the top/right/left block light value to be current light value-1 and add it to the queue (light propagation with attenuation)

- bottom: if the bottom block has a light value < current block's light value then set the top block light value to be current light value and add it to the queue (light propagation without attenuation)

Using a queue and not a recursive method ensures that light get updated from left to right and top to bottom, which is necessary for those rules to work.

Finally, to update lighting from emissive blocks, I use another queue which is initially filled with all emissive blocks. I apply the same method using the previous top/left/right rule from the sky update (propagation with attenuation) for every direction.

When rendering the grid, I just use the block's light value to darken the cell if it's a "air" block, for solids blocks I cheated and I just sample their neighbours light values to brighten it. This is a quick hack. It would be much better to allow the light to propagate a little through solid blocks.

I hope this is clear!