URP Negative Color Effect Not Applying to Both World and UI Properly

Question

How can I apply the negative color effect to all cameras (including the UI camera) using Record Render Graph?

Current Issue

  • When the UI camera is disabled, the effect applies correctly to the entire world.
  • When the UI camera is enabled, only the UI is inverted, while the world remains unchanged.
  • In Scene View, both the UI and the world are inverted, but in Game View, only the UI is affected.
  • The overlay UI camera in the stack seems to take priority, causing the effect to apply only to the UI.

However, I can’t figure out how to fix this issue in the code.

Goal

I want to ensure that the negative color effect is applied to the entire world even when the UI camera is enabled.

Hierarchy & Code

Here is my hierarchy setup,

  • Main Camera (Cinemachine Brain, stacking an overlay UI Camera)
    • UI Camera (Render Type: Overlay, Culling Mask: UI)
  • Cinemachine Camera
  • Cube (Base Map Color: White)
  • Canvas (Screen Space - Camera)
  • Text (TMP)

Enable UI Camera :

Disable UI Camera:

and the code is below:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;

public class NegativeRenderPass : ScriptableRenderPass
{
    private const string ShaderPath = "Hidden/Sample/Negative";
    private Material _material;
    private Material Material
    {
        get
        {
            if (_material == null)
            {
                _material = CoreUtils.CreateEngineMaterial(ShaderPath);
            }
            return _material;
        }
    }

    public void Cleanup()
    {
        CoreUtils.Destroy(_material);
    }

    private class PassData
    {
        public Material Material;
        public TextureHandle SourceTexture;
    }

    public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
    {
        var resourceData = frameData.Get<UniversalResourceData>();
        var sourceTextureHandle = resourceData.activeColorTexture;
        
        var negativeDescriptor = renderGraph.GetTextureDesc(sourceTextureHandle);
        negativeDescriptor.name = "NegativeTexture";
        negativeDescriptor.clearBuffer = false;
        negativeDescriptor.msaaSamples = MSAASamples.None;
        negativeDescriptor.depthBufferBits = 0;
        
        var negativeTextureHandle = renderGraph.CreateTexture(negativeDescriptor);
        
        using (var builder = renderGraph.AddRasterRenderPass<PassData>("NegativeRenderPass", out var passData))
        {
            passData.Material = Material;
            passData.SourceTexture = sourceTextureHandle;

            builder.SetRenderAttachment(negativeTextureHandle, 0, AccessFlags.Write);
            builder.UseTexture(sourceTextureHandle, AccessFlags.Read);

            builder.SetRenderFunc(static (PassData data, RasterGraphContext context) =>
            {
                var cmd = context.cmd;
                var material = data.Material;
                var source = data.SourceTexture;
                Blitter.BlitTexture(cmd, source, Vector2.one, material, 0);
            });
        }

        renderGraph.AddBlitPass(negativeTextureHandle, sourceTextureHandle, Vector2.one, Vector2.zero, passName: "BlitNegativeTextureToCameraColor");
    }
}

public class NegativeRendererFeature : ScriptableRendererFeature
{
    private NegativeRenderPass _pass;

    public override void Create()
    {
        _pass = new NegativeRenderPass
        {
            renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing
        };
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(_pass);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _pass.Cleanup();
        }
    }
}
Shader "Hidden/Sample/Negative"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
        ZTest Off ZWrite Off Cull Off
        Pass
        {
            Name "Negative"
            
            HLSLPROGRAM
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"

            #pragma vertex Vert
            #pragma fragment frag

            half4 frag(Varyings input) : SV_Target0
            {
                float2 uv = input.texcoord.xy;
                half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv);
                half4 negative = half4(1 - color.rgb, color.a);
                return negative;
            }
            ENDHLSL
        }
    }
}

If the overlay is excluded in AddRenderPasses,

  public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  {
      if (renderingData.cameraData.renderType == CameraRenderType.Overlay)
      {
          return;
      }
          
      renderer.EnqueuePass(_pass);
  }

the result is as follows:

Any help would be greatly appreciated. Thank you!