The title is probably confusing, so I will try to explain it as well as I can.

In out game we use black sprites with low opacity as shadows. However, when multiple "shadows" stack on top of each other, they combine resulting into a darker color, which in certain cases makes everything look weird, like in the picture below.

Is there technically possible, maybe through shaders, to combine the opacity of these sprites into one, so that they don't become increasingly darker as more are stacked on top? How could I start doing that? Any resources I could read?

Thank you in advance for the suggestions!

Welcome to the forums @InkToPixels!

I am not sure how feasible this would be, but you could have all of your shadows on a single Viewport, remove the transparency from all the shadows so overlapping shadows will not blend (which is the issue you are seeing in the OP picture), and then use the Viewport texture as a transparently overlay.

@TwistedTwigleg said: Welcome to the forums @InkToPixels!

I am not sure how feasible this would be, but you could have all of your shadows on a single Viewport, remove the transparency from all the shadows so overlapping shadows will not blend (which is the issue you are seeing in the OP picture), and then use the Viewport texture as a transparently overlay.

Would that mean that we have to manually place each shadow in the scene?

Right now, each elements (like fences or characters) have their shadows placed in their own node, with a lower z-index. This means that it is fast and easy to set each element in the scene, which is important to us since we are a small team.

No, not necessarily. Each shadow would need to be a child of a Viewport node, but you could automate this process or even have it done automatically via a script. Then you could use the resulting viewport texture for shadows as mentioned in my previous post.

The only thing that I am not sure with this method, having thought more about it, is visual layering/culling. For example, if you have a set of boxes placed on the same diagonal line, then you would not want the shadow of the box in front to cover the box right behind it on the diagonal line, since that would visually make the box look small. In other words, the shadows would not necessarily have any way to know what was in front or behind, potentially leading to the shadows being drawn on top of everything... Maybe the viewport idea is not the way to go. I'm not sure on what another potential solution would be right off, but I will keep thinking about it and will let you know if I think of something.

2 months later

I just want to bump this thread and mention that we did not find a solution yet, but when we do, we will definitely share it with everyone in an update.

The view port idea worked in theory, but the workflow behind it was very cumbersome for us and our workflow.

However, we did find a shader that kinda works. I just want to point out that shaders are way beyond our expertise, might as well be black magic.

The shader in question (link) adds more blending modes to Godot, and it turns out that the "add" blend mode does achieve the effect we are looking for, to an extent. Here is how the implementation looks in Godot.

And here is how it looks when it is working:

As you can see, the shadow of the two separate scenes blend in together correctly.

However, the effect breaks if the character/camera is parallel to the objects, for some reason. Like this

We are still investigating why this happens. Does anyone have any idea?

So, I talked with the creator of the shader in question.

It seems that the problem arises from y-sorting, which changes the z-index of the shadows, even when the z-index is not set as relative. On top of that, because of how Godot's renderes batches draw calls, the blending mode does not seem to work between different scenes. So it would work between the crates from above, but would not work between the crates and, let's say, fences or other objects.

With that in mind, there are some solutions we could implement. For example, all shadows could be outside the y-sorting, automatically instanced and placed at the right position by a script. We have not tried that yet because it would require a lot of work, and we are currently focusing on other areas of the game.

4 months later

Could you find any solution for that?

@Ironsx said: Could you find any solution for that?

In Godot 4.0, this will be supported out of the box thanks to the CanvasGroup node. There most likely won't be a built-in solution in 3.x though, since it relies on a different renderer.

2 years later