+14 votes

How do I prevent a sprite from getting dark inside it when using 2D lights?
Here is a screenshot for example:
enter image description here
My sprite has a square occluder encompassing it.
What I want is to have the shadow "below" the sprite (for any rotation), so it keeps its original color and is not darkened. Or, in math words, have the shadow projected from back edges and not front edges.

asked Mar 17, 2016 in Engine by Zylann (26,055 points)

Seems like this feature is not done at the moment, maybe you should suggest on https://github.com/godotengine/godot/issues

7 Answers

0 votes

Try to change CanvasItem/Visibility/Blend Mode in Sprite2D from Mix to Add.

answered Mar 20, 2016 by puppetmaster- (667 points)

This makes black parts of the sprite invisible.

0 votes

Use behind parent option or decrease Z value on your LightOccluder.
Or you can increase Z of your Sprite.

answered Mar 20, 2016 by Kermer (80 points)

This won't stop shadow being created on the occluder, but the sprite will be drawn after it, so it'll cover the shadow.

Would it work if other objects cast shadows that are "higher" in Z?
For example, shadows projected by walls should darken crates, but crates should not darken walls.

Things with lower Z are drawed first, then those with higher.
Your LightOccluder is drawing the shadow.
If needed you can use absolute Z (uncheck "relative").

The problem is that lights draw the shadows (or, to state it better, they don't draw where shadows should be), and lowering the Z has absolutely no effect in-game, only in the editor.

My bad then. I didn't run the game, because I thought it should work same for the editor as in-game. Maybe it's a bug then?

I replied on the original question with a link to issues. If the OP doesn't open an issue soon, feel free to do so yourself.

0 votes

Other possibility are:

a. set a light with texture (same as box but White)

Sprite (Box)
- LightOccluder2D
- Light2D (shadow disable, texture same as box in White color)

b. set on sprite a CanvasItem/Material and set shading Mode to unshaded.

answered Mar 20, 2016 by puppetmaster- (667 points)
+1 vote

Found a temporary solution until this is fixed: simply place a duplicate spite on top of the sprite+occluder and change its blend mode to Add. Brightness can be controlled with Opacity value.
occluder fix scene tree
sprite settings

The result:

Before
occluder before fix

After
occluder after fix

answered Jun 17, 2016 by ericdl (1,284 points)
+1 vote

All you have to do is create a new material for your sprite, and set the "Shading Mode" to "Unshaded". Of course this will stop it from having any shadows cast on it, or from being affected by any CanvasModulate nodes.

enter image description here

answered Dec 24, 2016 by rgrams (522 points)

Hmm that's nice to solve my first problem :)

But it won't provide "height affected" shadows, which was my underlying goal actually. For example, if A is taller than B, B should not project shadows on A. Here, walls should project shadows on objects and characters, but characters should not project shadows on walls. And as a result, no self-shadowing, because the top would be "higher" than the sides of the object and won't receive its own shadow. That would be an interesting feature^^

I'm not working on this anymore at the moment, but if I have to I'll probably get back some info here :)

Solution: Use 3D. :P

Yeah... that's a bit excessive when you know the 3D engine is completely different in its way of working, API-wise and performance-wise...

0 votes

Try with an open light occluder polygon (5 points for a square), by default it makes a closed one, you will have to add the 5th point manually.

But maybe 4 ocluders with simple segments with different cull mode will work better (allowing shadows from other occluders).

All this is accesible from the inspector, editing the polygon.

answered Dec 26, 2016 by eons (7,759 points)

Couldn't resist to try it and made a mess of resources with the lights and shadows demo, as long as the cull mode of the closed occluders stay untouched, everything works fine.

Also, the open polygon needs a cull mode set to work (both, polygon and segments seem to do the same).

Here is a modified demo with open occluders (the unlocked are the sprites with modified occluders):
https://cloud.openmailbox.org/index.php/s/afvtQ1K4LmoToyn

+6 votes

Interesting - 6 working solutions and none of them is the one that I would say is the correct one.
You said "in math words, have the shadow projected from back edges and not front edges.", and that can be achieved quite literally.
Edit the OccluderPolygon2D resource in the LightOccluder2d node and set the Cull Mode. The default is "disabled" which means that the polygon casts shadows both from the inside and from the outside. Setting the Cull mode to either ClockWise or CounterClockWise chooses whether the polygon should cast shadows only from the outside (so that lights inside the polygon don't cast shadows) or cast shadows only from the inside, which would mean that in your case only the back edge casts shadows.

answered Dec 26, 2016 by Warlaan (1,114 points)

I was unable to do it with a closed polygon :/

I just tried it again. I don't know what you are doing wrong, but for me it behaved exactly as advertised.
Keep in mind that LightOccluder2D-Nodes are displayed in the editor, so in there the bitmap will appear darker (but it should still be visible that there is light inside the occluder, just not as clearly as when you are running the scene).

shadowcaster demo
The top left one doesn't use culling, the top right one uses clockwise culling and the bottom one counter clockwise. Which culling direction is the right one for you depends on the order in which you defined the points of the occluder polygon (I assume, I haven't tested it).

Maybe I messed up the lights, occluder resources or something, tried on another project and worked, on tilemaps too.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.