The main issue for projecting shadows on transparent surface is how the projector knows the transparency of the surface. Usually, the transparency of the surface is calculated from alpha components of a texture and a color property. Those properties are belonging to the material of the receiver object. We need to copy some properties from the material of the receiver object to the material of the projector.
If you want to cast shadows regardless of the transparency of the surface, like casting shadows on a glass, you can skip ahead to Rendering Order Issue section.
In AR application, there are needs for projecting shadows on invisible plane to blend shadows and real image. If you are seeking such technique, please refer to Project shadows on invisible plane page.
Pass receiver properties to projector material (available from version 1.2.0)
If just one material is shared by all the receiver objects, it is okay to manually copy the receiver properties to projector materials and use them in projector shaders. However, if there are more than one materials that are used by receiver objects, it is impossible to do so, even by a script, because we cannot change properties of projector materials while rendering shadows on the receiver objects.
Unity has a nice mechanism which override material properties. That is MaterialPropertyBlock. The properties stored in this object override material properties of projectors as well as the properties of the renderer’s material.
Dynamic Shadow Projector provides PropertyBlcockForTransparentReceiver component which utilizes MaterialPropertyBlock to pass the properties of the receiver’s material to projector materials in the format required by the dynamic shadow projector shaders.
This component must be added to all the transparent receiver objects. If the materials of those receiver object use Standard (Builtin RP) or Lit (Universal RP) shaders, you can use the default settings.
If a custom shader is used, you can change the default settings to fit the custom shader.
Use receiver properties in projector shaders (available from version 1.2.0)
By default, dynamic shadow projector shaders do not use receiver’s properties even if the receiver has PropertyBlcockForTransparentReceiver component. You have to explicitly enable projector material to use receiver’s properties because using receiver’s properties requires additional instructions and that may make the projector shader slower.
In Inspector view of the projector material, you can find ‘Transparent Support’ field. You need to add checks to this field to enable receiver’s properties.
The table below shows which item you need to check for the surface types of the receiver objects.
|Item Name||Rendering Mode (Standard)||Surface Type (URP Lit)|
|Cutout||Cutout||Opaque + Alpha Clipping|
|Transparent||Transparent / Fade||Transparent|
If you have ‘Transparent + Alpha Clipping’ surface type in URP Lit material, you need to check both (Everything).
Rendering Order Issue
If the shadows are projected on only opaque and cutout objects, we do not have issues any more. However, if some transparent objects needs shadows, rendering order will be a problem.
In builtin render pipeline, the default value of the render queue property of projector materials is 2999, which means projectors are drawn after the sky box and before the transparent objects.
To render the projectors after the transparent objects, we need to change the render queue value of the projector materials to 3000 or greater. However, all the shadows projected on the transparent objects are drawn after the transparent objects. That means, we have sorting issues. Let’s say, we have two transparent objects A and B, and a round shadow is projected on the object B. If object A is closer to camera, the shadow should be look like the left image below, but actual rendering result will be like the right image.
If the render queue values of these objects have relations like this:
then, rendering result can be look like the left image. However, the rendering order of transparent objects should be sorted by the distance from camera. Using fixed order is not a good idea.
If the object B can be rendered before all other transparent objects, it is okay to change the render queue value of the object B to 2998 or below and draw projector shadows in the default order.
In Universal Render Pipeline, the render queue value of projector material is not used. Instead, ‘Render Pass Event’ property of Projector For LWRP component is used. The default value is ‘After Rendering Opaques’ which means the projector is rendered after the opaque objects and before the sky box. In addition, Projector For LWRP component has ‘Render Queue Lower/Upper Bound’ properties. To project shadows on transparent objects, we need to change ‘Render Pass Event’ property to ‘After Rendering Transparents’ and ‘Render Queue Upper Bound’ property to 3000 or greater.
Universal Render Pipeline also have the sorting issue as same as builtin render pipeline. We cannot fix this issue perfectly, but we can reduce the impact a little bit.
Projector For LWRP has AdditionalProjectorRenderer component which enable Projector to render shadows more than one times with different materials and different timings. This is an example of the usage of AdditionalProjectorRenderer.
In this example, ProjectorForLWRP component draws shadows on opaque objects, and the first AdditionalProjectorRenderer component draws shadows on cutout objects. The second AdditionalProjectorRenderer draws shadows on transparent objects. Each component uses a different material which is optimized for each surface type of the receiver objects. For more details, please have a look at ShadowsOnTransparent sample scene in Dynamic Shadow Projector Extension For LWRP.