Hey everyone, I am working on a feature where I am compositing 2 different unity layers into one full screen effect. I am currently using 2 separate cameras that I keep in sync and the extra cam is set to render to a texture that I then use for the compositing.
I recently did some profiling and was thinking I should be able to add an extra pass and avoid having to run the entire pipeline twice (for each of the cameras). So I made a custom RendererFeature and ScriptableRenderPass and I managed to achieve my effect with context.DrawRenderers but my issue is that the objects on layer 2 are still receiving shadows from the objects on layer 1… which makes sense since the MainLightShadow pass ran at the beginning of the pipeline and used the layer of the camera.
So the question is, how can I run a shadow caster pass a second time, for the objects on layer 2? Since we are late in the pipeline (Before Rendering Post Processing) I should be able to reuse the same shadow maps, by just clearing and rendering again in the texture (“_MainLightShadowmapTexture”). Documentation feels very limited and by digging through MainLightShadowCasterPass.cs I was not able to reproduce it as it uses a number of internal fields and properties. Also overriding the CullingResults feels extremely hacky for an API user as it needs ScriptableRenderContext.Cull, instead of the layers being configurable through the constructor or Setup.
Here is my best attempt at hijacking MainLightShadowCasterPass, with partial results. It only works if the RenderPassEvent is ‘BeforeRenderingShadows’ and it renders the shadows of layer 2, but then the natural shadow pass renders again layer 2… which means my first pass is interfering with the regular one. If I try to enqueue the path for later, there is no actual draw with the shadow map as a target in the Frame Debugger… besides a Clear, where there should be a full draw.
private class BlueprintShadowPass : MainLightShadowCasterPass
{
LayerMask m_Mask;
public BlueprintShadowPass(RenderPassEvent renderPassEvent, LayerMask mask) : base(renderPassEvent)
{
m_Mask = mask;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
RenderingData data = renderingData;
int maskCache = data.cameraData.camera.cullingMask;
data.cameraData.camera.cullingMask = m_Mask;
data.cameraData.camera.TryGetCullingParameters(out ScriptableCullingParameters cullingParameters);
CullingResults cullResults = context.Cull(ref cullingParameters);
data.cameraData.camera.cullingMask = maskCache;
data.cullResults = cullResults;
base.Execute(context, ref data);
}
}