Doing a custom per-object pre-pass with URP

In order to render a particular shader I’m using for everything, I need to do a pre-pass to get the lighting data and run a compute shader on the result. I’ve currently got this set up as a scriptable renderer feature with a scriptable render pass that tries to run a particular pass in this shader.

Shader "Custom/CrossHatchShader"
{
    Properties
    {
        //...
    }
   
    SubShader
    {
        Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True" "ShaderModel" = "4.5"}
        LOD 300
       
        Pass
        {
            Name "ForwardLit"
            Tags{"LightMode" = "UniversalForward"}
            //...
        }
       
        // The pre pass I want to achieve in SRP
        Pass
        {
            Name "CHLightingInfo"
       
            // Regular vertex pass
            #pragma vertex LitPassVertex
            // Pass in the shader that gathers the lighting info
            #pragma fragment LightingPrePassFragment
        }
    }
}

And my ScriptableRenderPass is as follows:

public class CHLightingPrePass : ScriptableRenderPass {
    // We will store our pass settings in this variable.
    CHAutoExposureSRPFeature.PassSettings passSettings;

    RenderTargetIdentifier colorBuffer;
   
    static ShaderTagId CHPrePassShaderNameID = new ShaderTagId("CHLightingInfo");

    public CHLightingPrePass(CHAutoExposureSRPFeature.PassSettings passSettings) {
        this.passSettings = passSettings;

        // Set the render pass event.
        renderPassEvent = passSettings.renderPassEvent;
    }

    public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) {
        colorBuffer = renderingData.cameraData.renderer.cameraColorTarget;
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) {
        CommandBuffer cmd = CommandBufferPool.Get("Crosshatch PrePass Commands");
        using (new ProfilingScope(cmd, new ProfilingSampler(ProfilerTag))) {

            // Should draw all objects with materials using shaders that have a pass named as CHPrePassShaderNameID's content,
            // and only that specific pass
            cmd.SetRenderTarget(colorBuffer);
            RendererListDesc desc = new RendererListDesc(CHPrePassShaderNameID, renderingData.cullResults, renderingData.cameraData.camera);
            RendererList rendererList = context.CreateRendererList(desc);
            cmd.DrawRendererList(rendererList);
        }

        // Execute the command buffer and release it.
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
   
    public override void OnCameraCleanup(CommandBuffer cmd) {
       
    }
}

When I look in the frame debugger, the pass appears but doesn’t seem to do anything:

So it looks like it’s not doing anything on the objects that are meant to be drawn via DrawRendererList

Could someone more experienced with SRP clue me in on how to properly do an object pre-pass like this?

try adding
Tags{“LightMode” = “CHLightingInfo”}

Still nothing, unfortunately

You should set your own render target otherwise you’ll render into current camera color attachment, what you definitely don’t want in your case, you want to render it to your own buffer I suppose (for example as Unity doing with _DepthTexture) and use that buffer later.

Also I suggest you use context for rendering. In your case in OnCameraSetup get temp RT for your buffer, set render target to your buffer (don’t forget to set clear flags if you need)
8416488--1112955--upload_2022-9-5_15-13-47.png

And in Execute:

Dont forget to release RT for buffer in OnCameraCleanup.
8416488--1112949--upload_2022-9-5_15-11-3.png

As result you’ll see properly filled buffer:

1 Like