Shadows and post-processing with custom material

I’m trying to make shadows and post-processing (volumetric light scattering to be precise) work with custom materials. Custom material is transparent with some opaque pixels and they’re ignored by shadow casting and volumetric light scattering post-process. This material mostly done via shaders (it has no texture samplers except for transparent 1px size diffuse texture to get uv coordinates working). My assumption is that shadows and post-processing need texture with alpha info to determine which pixels are affected and which are not. Is that correct?

So, I’m wondering if there’s way to get alpha value directly from shader or somehow pass shader as a texture? I’m guessing there’s something possible with RenderTargetTexture, but this topic is way beyond my comprehension.

Here in playground you can see two planes and moving “sun”. Plane on the left has texture and it’s working as intended. However plane on the right does not cast shadow and volumetric light is rendered in front of it.

The volumetric light scattering post process is using its own shader to render objects that occlude light rays, and in your case you would need to pass your own shader as you are performing some special computation in the fragment shader.

Fortunately, since 5.0 it’s now possible to associate a specific material to a render target texture for a given mesh. In the volumetric post process case, you can use volPP.getPass().setMaterialForRendering(...) to set a specific material for the right plane. The volumetric post process is expecting that the mesh will be rendered black with alpha=1 where the object is opaque and 0 elsewhere. See the createCustomMaterialForVolumetric function in the PG below.

Unfortunately, there are some changes to be done in the volumetric post process to support this new feature from 5.0, so you will need this PR to be merged before the PG can work as expected:

Regarding the missing shadow for the right plane, you need to set material.useAlphaFromDiffuseTexture = true for the shadow to be displayed… But you still won’t see it because your diffuse texture is full 0-alpha and it is the one used by default by the shadow generator. You need to instruct the shadow generator to use a custom shader so that your shadow is the circle you expect. See the createCustomMaterialForShadow function in the PG. This material should be wrapped in a ShadowDepthWrapper class instance and set to the material.shadowDepthWrapper property of the right plane material.

Here’s the PG:

Note that it is working except for the volumetric effect on the right “plane”. Once the PR is merged this should also work:

One caveat: I switched to a non cascaded shadow generator as I could not make the ShadowDepthWrapper work in the cascaded case for some reason…

1 Like

Good stuff. Thank you very much! :slight_smile: I wonder what’s the deal with cascaded shadow generator. I intend to use this on open world scene.

Here’s a simplified version that doesn’t need a ShadowDepthWrapper and that also works with cascaded shadow maps:



One more question. I noticed that enableSoftTransparentShadow does not work with this approach. I guess this would need custom ShadowDepthWrapper?

The problem is in your all 0-alpha texture.

That alpha value from this texture is used to discard pixels in the enableSoftTransparentShadow=true mode. As it is 0 everywhere, all pixels are discarded.

As this texture is only used to have uv coordinates, use a texture that has alpha=1 everywhere, like textures/ground.jpg for eg:

If you want soft shadows from your custom shader, you need to add #define SHADOWDEPTH_SOFTTRANSPARENTSHADOW (see doc) at the location where you want the special check to happen. In your case, you should do it after your custom code and make sure to update the alpha variable, as it is used in the computation:

The soft shadow is not very nice because it is using PCF. Using blur exponential is better in that case, but it’s only available in non cascaded mode:

In cascaded mode, PCSS is also better than PCF but is more GPU intensive: