I'm currently using the following steps for my lighting system
- Calculate all the tiles along the perimeter based on the radius of the light
- Cast a ray from the center of the light to each perimeter tile
- The ray cast returns which cells it intersects
- Each cell is lit based on their distance from the source (light attenuation)
- If a cell is determined to be opaque then the subsequent cells are not lit (hard shadow)
The problem is that in some cases this makes the shadowing looks a bit odd and gives a Peter Pan type of effect where the shadow is not attached to the shadow caster (opaque cell).
For example:
The culprit is highlighted here:
If we take a look at the ray causing the issue we can see that it hardly intersects the cells behind the opaque object but they are still counted as being lit:
The method used for ray traversal is a typical Bresenham line drawing algorithm:
while (true)
{
// Do not return cells outside the map bounds
if (x0 < 0 || x0 >= width || y0 < 0 || y0 >= height)
break;
// Add the current cell to the list
cells.Add(GetCell(x0, y0));
if (MathExt.AlmostEquals(maxX, maxY, 0.01f))
{
// Cannot travel any further in this direction so this is the last cell
if (x0 == x1 || y0 == y1)
break;
maxX += deltaX;
maxY += deltaY;
x0 += stepX;
y0 += stepY;
}
else if (maxX < maxY)
{
// Cannot travel any further in this direction so this is the last cell
if (x0 == x1)
break;
maxX += deltaX;
x0 += stepX;
}
else
{
// Cannot travel any further in this direction so this is the last cell
if (y0 == y1)
break;
maxY += deltaY;
y0 += stepY;
}
}
My current line of thinking is to calculate how much of the cell is intersected by the ray and use that to influence the contribution of the lighting, alongside the attenuation.
Therefore, my question is how do I calculate how much of the cell is intersected by the ray?
Alternatively, can anyone suggest a more suitable solution for this issue?