Multiple ShadowGenerators for one light source

Shadows are really affecting my game’s performance, so I’ve been having a look at improving it.

I had 1 DirectionalLight in my scene, and pretty much all the meshes in it are shadow casters. The good news is that the majority of my meshes are static buildings, so I want to freeze the shadows for them by setting the refreshRate = BABYLON.RenderTargetTexture.REFRESHRATE_RENDER_ONCE.

However, the singular light in my scene is also responsible for casting shadows off the player meshes, and obviously players can move around, so I don’t want their shadows to be frozen. There doesn’t seem to be support for this currently in the ShadowGenerator.

I tried creating multiple ShadowGenerators, however, if the same light is used for multiple ShadowGenerators, only the last-created generator seems to cast any shadows at all. Additionally, creating a clone of the light in my scene isn’t a good solution either, because that results in the shadows “stacking” when they overlap, as opposed to for a singular light source, where “stacked” shadows don’t make the shadow-receiving-area darker.

Is there another way I can solve this problem currently? If not, could we add support for partial freezing of shadows in the ShadowGenerator? The ideal change, though, would be to make a single light work for multiple shadow generators - that way it would be possible to have differing qualities of shadows for each generator.

Playground link where I’m doing 2 lights (2nd is a clone) and 2 ShadowGenerators, demonstrating the overlapping dark shadows: https://playground.babylonjs.com/#4CDJPH#2

shadows_issue

Cc @sebavan and I can take a look too when I’m in a PC :smiley:

1 Like

I’m on my iPad so no PG right now, but there are two things that occur to me:

  1. Create a clone of the light and set it via includedMeshes (or is it exclude…?) to only affect the buildings. Add your shadow caster with render once

  2. Pre-bake the static shadows cast by the buildings into a texture (would this properly be an AO texture?)

:nerd_face:3. Switch to a physical-based rendering and let the shaders figure out shadows

HTH!

1 Like
  1. I’ve updated the PG a bit to do exactly this https://playground.babylonjs.com/#4CDJPH#2 (there doesn’t seem to be any field called included/excludedMeshes, I’ve instead added the static mesh as a shadow caster to the static shadow generator only, and the moving mesh as a shadow caster to the dynamic shadow caster only) - the issue here is when the shadows overlap, the resulting area is very dark, and that doesn’t make sense if the goal is to emulate 1 light source (ie. 1 sun) in the scene

  2. That makes sense, however there are a very large number of buildings (and future areas in my game will also contain some of the same buildings, in different positions/orientations relative to the light source), so I would really love a way to generate and freeze the shadows programmatically rather than baking as textures

  3. Would you be able to elaborate on this one a little more? Thanks!

1 Like

Maybe @Evgeni_Popov can have a look as he is a shadow guru :slight_smile:

1 Like

I’m very much interested in reading this answer. Did a number of attemps with no success. I hope @Evgeni_Popov will impress me once more :wink: Already bookmarked for later reference :thinking:

Edit: I’m quite sure that if there is a solution, it must be a twist. It feels not natural, since light only adds to light (and shadows to shadows). I mean I have been able to do something similar but not with casting two shadows from light (one static and one dynamic) on a same mesh (in this case, the ground). I know of how to cast a single shadow on the ground and another shadow contact hardening with maxZ and minZ limits on other objects or on self, but the above really leaves me wondering…

1 Like

Vile flatterer! :wink:

The only way I can see to do it is to modify the shadow code to not darken the color further when handling the 2nd light if the pixel is already in shadow from the 1st light.

Here’s a way to do it with a material plugin (new in 5.0 - doc: Material Plugins | Babylon.js Documentation):

For this to work:

  • 1st and 2nd lights must be directional lights and have the same intensity
  • you must not use any shadow filtering method

Note that the plugin works for both the standard and the PBR materials.

If you change the type of the light (point, spot) and/or the shadow filtering method (PCF, poisson, …), the regular expression lines 106/112 must be changed accordingly. It’s a bit cumbersome to do, so I have created a PR to allow reusing regular expression groups in the injected code:

When this PR is merged, this PG will work:

It allows you to use any type of lights and any type of shadow filtering methods.

4 Likes

WOW! Do that and become my hero (well, you already are). OK, so become my super…outmost…spectacular hero :superhero: :grin:

Yeah, I know, I’m a bad ass :see_no_evil: I’m only here to soak-up the knowledge and efforts of others. :laughing:
Just don’t tell the others :grin:

1 Like

Well, in fact it was a reply to @sebavan post :slight_smile:

1 Like

LOL, no worries. I can take it for me aswell :wink:

I think the approach that ya’all settled on for this makes the most sense for your use case as I see it. A PBR approach would be very heavy and be overkill I think!

Basically, PBR is when your materials use a realistic set of simulated properties that define how light reflects from it, which includes occlusion (shadows) as a emergent property of the PBR system.

Much more complicated and powerful, and probably not what you’re looking for :slightly_smiling_face::sunglasses:

1 Like

Hey @Evgeni_Popov, that solution works great, I’ve now implemented it and it’s working perfectly - many thanks!!!

Additionally, thanks to everyone else who’s popped by this thread and given their input as well. This community is honestly one of the most supportive and helpful forums I’ve come across, I haven’t come across any other open source projects that are as well-maintained and supported as BabylonJS. :tada:

3 Likes