Hi Unity Devs,
I trying to solve a basic problem with URP. I doing a fade-in/out effect for one set of objects in the scene. But I have a problem with shadows. The shadows don’t reflect the transparency of the mesh. The example is on the image.
The lights are fully real-time, it’s tested with deferred and forward rendering. URP v12.
Does anyone have an idea how to do it with URP? (without a fake shadows solution)
Thanks
Michal
1 Like
I don’t think that’s possible out of the box with URP. I can think of a couple ways to do this…
- Rendering to another RT and blending: very slow, but easy to implement.
- Injecting into _ScreenSpaceShadowmapTexture: only works for one light, requires you enable screen space shadows, potentially a bit complex
- Dithered shadows: tons of artifacts if the object is moving so basically requires post-process antialiasing and even then usually noticeable (IMO; dithered shadows look awful, but if The Witcher 2 got away with it, you can too)
1 Like
Thanks. I already tried the 3), but the result wasn’t good but it’s a possible way if I implement the AA on it.
Screen space shadows aren’t good for scenes with transparent objects. I also experimenting with rewriting the URP package, it looks like a possible way, but not ideal.
The last experiment that I planning is to create a fake shadow during fade with texture projection, that can be transparent and it hides the hard switch-off of real-time shadow.
I hoped that anyone will know about any super-hidden feature in URP 
It won’t use the screen space map for casting shadows onto transparent objects, just casting shadows onto the floor/other geometry. Once the shadow map is generated, you can draw extra stuff on it (I’m using this for stencil shadows). You don’t even need Unity to generate it for you, as long as a _ScreenSpaceShadowmapTexture exists and _MAIN_LIGHT_SHADOWS_SCREEN is defined, it’ll use that (the shader code in URP is:
half MainLightRealtimeShadow(float4 shadowCoord)
{
#if !defined(MAIN_LIGHT_CALCULATE_SHADOWS)
return half(1.0);
#elif defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
return SampleScreenSpaceShadowmap(shadowCoord);
#else
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
half4 shadowParams = GetMainLightShadowParams();
return SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), shadowCoord, shadowSamplingData, shadowParams, false);
#endif
}
You’ll need to draw the transparent objects to it yourself, but that can be done in a renderer feature, something like this:
RenderTargetHandle _rtUnityShadows;
// somewhere in your initialization code
_rtUnityShadows.Init("_ScreenSpaceShadowmapTexture");
// In Configure()
cmd.GetTemporaryRT(_rtUnityShadows.id, /* rt descriptor: size of camera and RenderTextureFormat.R8 */);
// After drawing to the target
cmd.EnableShaderKeyword("_MAIN_LIGHT_SHADOWS_SCREEN");
(for a full example: https://gitlab.com/burningmime/urpg/-/blob/master/Packages/shadow/src/internal/ShadowPass.cs )
The only thing that won’t work is if both the caster and receiver are transparent and have different alpha values (so self-shadowing or objects fading in together will work fine, but a 25%-transparent character can’t cast accurate shadows on a 75%-transparent floor).
Sadly it only works for the main light without rewriting URP internals.
If that works, that’s probably the simplest option.