Implementation of 2D Shadow Culling for Player Line of Sight

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By sutrsfire

I’m attempting to implement a player line of sight system using light2d and light occluders. The intended effect is for it to function like a standard roguelike line of sight or that found in games like Monaco, and should support lighting from other sources.

I’ve changed the z-level (relative and not) of the occluders to no effect, along with exploring light2d modes. Mask has produced the result below in combination with clockwise shadow culling on the occluders:

The two wall tiles immediately up from the player are rendered correctly, however they are casting shadows on the other tiles in the scene, which should not be happening. Adding another sprite on top will not work either, as the only wall tiles that should be rendered are those that can be raytraced to the player.

I’ve searched a bit and can’t find any solutions other than possibly raycasting to generate triangles/polygons for line of sight on to a separate viewport and using that as a masking texture on the active viewport - which seems like too much of a hack workaround and I’d probably just write something in nativescript at that point, but I’d like to avoid that.

Has anyone gotten anything like this to work, or have any ideas?

I’ve added what I believe is an exhaustive answer to a slightly older question I believe this question duplicates: https://forum.godotengine.org/23818/how-can-make-tilemap-walls-with-occluder-show-and-cast-shadows?show=81284#a81284

The short answer is that I don’t believe it is possible without writing your own tile-aware visibility code, but you can integrate the results with the engine 2D light system by dynamically placing occluders to reflect current visibility.

llasram | 2020-09-01 19:36

:bust_in_silhouette: Reply From: SoggyBitStudios

I believe you merely need to specify an incomplete path for the occluder and swap the winding order. The window order matters for light OccluderPolygon2D and will determine if the light passes through the first set of edges.

I believe the OP has already done that – the tiles in the screenshot are not self-shadowing, but rather shadowing adjacent tiles. It would be possible place incomplete occluder polygons only at the “backs” of the wall tiles (e.g., line segments), but the “back” depends on the position of the player/light, and so can’t be done statically without specifically designing levels and tilesets with this in mind.

llasram | 2020-09-01 19:43

:bust_in_silhouette: Reply From: Wibbly

So, I was finally able to make it work. All I did was to set the LightOccluder2D into a different Light Mask than the Light2D.
:D

Changing the visible node light mask to be exclusive of the light shadow mask prevents any shadows from casting on the visible node. Without additional dynamic behavior this leaves all walls visible, which doesn’t seem to be at least what the OP wanted.

llasram | 2020-09-01 19:45