LightOccluder2D: How To Prevent Self-shadowing?

Godot Version

Tested on:

  • Godot 4.1 on Windows 10
  • Godot 4.1-4.5 on EndeavourOS, Linux 6.15.4-arch2-1 + KDE Plasma 6.4.2

Questions

I’m working on a 2D isometric 3/4 overhead game using TileMap and dynamic lights.

  • Is there an intended solution for displaying LightOccluder2D shadows behind the objects which cast them?
  • Is there an intended solution for one TileMap wall to cast a shadow onto another TileMap wall on the same Tile Layer?
  • Are there any custom sprite shaders that deal with self-shadowing?
  • What is the intended use of Show Behind Parent on LightOccluder2D as seen in documentation for v4.0 ~ 4.4?

Background

There are years of questions about how to make LightOccluder2D display shadows behind its parent.

The documentation up to 4.4 appears to suggest that one could accomplish this by checking Show Behind Parent, or else manipulating SceneTree draw order: https://docs.godotengine.org/en/4.4/tutorials/2d/2d_lights_and_shadows.html

Occluder draw order

LightOccluder2Ds follows the usual 2D drawing order. This is important for 2D lighting, as this is how you control whether the occluder should occlude the sprite itself or not.

If the LightOccluder2D node is a sibling of the sprite, the occluder will occlude the sprite itself if it’s placed below the sprite in the scene tree.

If the LightOccluder2D node is a child of the sprite, the occluder will occlude the sprite itself if Show Behind Parent is disabled on the LightOccluder2D node (which is the default).

However, this doesn’t work on any version of 4.x that I’ve tested. Further, this section is removed from the 4.5 docs: 2D lights and shadows — Godot Engine (4.5) documentation in English

Some other engines, which will go unnamed, have ShadowCaster2D components, with simple checkboxes for Use Renderer Silhouette and Self Shadows. These are easier to play with than manipulating Light Mask layers on multiple objects, and - critically - default to values for Shadow Behind Parent style behavior. I believe it would be beneficial for Godot to do this by default as well.

Some related links about LightOccluder2D:

Workarounds

The most common workaround I’ve seen is to duplicate lights; one set for lighting objects and one for casting shadows. This works, but duplication is both tedious and brittle.

MRP

I’ve recreated the issue in a smaller project, and it’s reproducible in both 4.4 and 4.5.


Image 1: The PointLight2D’s Shadow mask layer is only set to 2. The occluders cast shadow on the background, but not the parent sprites.

Image 2: I want to cast shadow on both background and other actors, so I have enabled Shadow mask layers 1 & 2. The light occluders are casting shadow on the background and each other (helpful) but also on their parent sprites (not helpful)

1 Like