Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Help! Custom Pass not rendering

Discussion in 'Universal Render Pipeline' started by JoNax97, Mar 3, 2023.

  1. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    Hello there!

    I'm attempting to port this overlay shader/system to URP:

    I've moved the bulk of the code to a ScriptableRendererFeature with 2 passes. I will explain briefly how the system works so you don't have to skim through all the code:

    There's a component on the couch that adds it to a global (static) list of objects that should have an overlay. Each object belongs to a group that shares a color and a single outline.

    The shader works in 2 passes: the first draws all the objects depth and group ID to a temporal RT.
    The second pass reads this RT and draw everything again with the correct color, and calculates outlines.

    The thing is, I can't get it to render in the game view at all. It renders only in the scene view if I set the RenderPassEvent of the second pass to "After Rendering". Any other value makes it disappear. It's specifically the second pass that's causing trouble. This configuration works (only in the scene view):



    I also discovered that disabling post-processing also makes it disappear from the scene view, even when set to "After Rendering"


    And no mater the settings, I can't get it to render in the game view at all.

    Can anyone point me in the right direction?

    This is the RendererFeature:

    Code (CSharp):
    1. public class OverlayRendererFeature : ScriptableRendererFeature
    2.     {
    3.         [Header("Settings")]
    4.         public RenderPassEvent RenderEventForFirstPass = RenderPassEvent.BeforeRenderingPostProcessing;
    5.         public RenderPassEvent RenderEventForSecondPass = RenderPassEvent.BeforeRenderingPostProcessing;
    6.        
    7.         public DepthTests depthTest = DepthTests.LEqual;
    8.         public OutlinePatterns outlinePattern = OutlinePatterns.Diamond;
    9.  
    10.         [Range(0.000001f, 0.001f)]
    11.         public float Bias = 0.001f;
    12.  
    13.         public GroupColor[] GroupColors;
    14.  
    15.         private WriteGroupIDPass firstPass;
    16.         private RenderOverlayPass secondPass;
    17.  
    18.         public Material Material { get; private set; }
    19.         public RenderTexture OverlayIDTexture { get; private set; }
    20.  
    21.         [SuppressMessage("ReSharper", "UseObjectOrCollectionInitializer")]
    22.         public override void Create()
    23.         {
    24.             var shader = Shader.Find("Hidden/OverlayShader");
    25.             Material = new Material(shader);
    26.            
    27.             PrepareShaders();
    28.            
    29.             firstPass = new WriteGroupIDPass(this);
    30.             firstPass.renderPassEvent = RenderEventForFirstPass;
    31.  
    32.             secondPass = new RenderOverlayPass(this);
    33.             secondPass.renderPassEvent = RenderEventForSecondPass;
    34.         }
    35.  
    36.         public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    37.         {
    38.             var camera = renderingData.cameraData.camera;
    39.             if (camera.cameraType is not (CameraType.Game or CameraType.SceneView)) return;
    40.            
    41.             if (Material == null) Create();
    42.  
    43.             // Request needed textures
    44.             OverlayIDTexture = RenderTexture.GetTemporary(camera.pixelWidth, camera.pixelHeight, 24, RenderTextureFormat.R8);
    45.  
    46.             renderer.EnqueuePass(firstPass);
    47.             renderer.EnqueuePass(secondPass);
    48.  
    49.             // Don't forget to release the temporary render texture
    50.             RenderTexture.ReleaseTemporary(OverlayIDTexture);
    51.         }
    52.        
    53.         private void PrepareShaders()
    54.         {
    55.             // Pattern Selection
    56.             if (outlinePattern == OutlinePatterns.Rect)
    57.             {
    58.                 Material.DisableKeyword("Pattern_Diamond");
    59.                 Material.EnableKeyword("Pattern_Rect");
    60.             }
    61.             else
    62.             {
    63.                 Material.DisableKeyword("Pattern_Rect");
    64.                 Material.EnableKeyword("Pattern_Diamond");
    65.             }
    66.  
    67.             // Depth testing
    68.             if (depthTest == DepthTests.LEqual)
    69.                 Material.EnableKeyword("EnableDepthTest");
    70.             else
    71.                 Material.DisableKeyword("EnableDepthTest");
    72.         }
    73.     }
    These are the render passes:


    Code (CSharp):
    1. public class WriteGroupIDPass : ScriptableRenderPass
    2.     {
    3.         private const int PassID = 0;
    4.        
    5.         private readonly OverlayRendererFeature rendererFeature;
    6.         private CommandBuffer commandBuffer;
    7.  
    8.         public WriteGroupIDPass(OverlayRendererFeature rendererFeature)
    9.         {
    10.             this.rendererFeature = rendererFeature;
    11.         }
    12.        
    13.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    14.         {
    15.             commandBuffer = CommandBufferPool.Get(nameof(WriteGroupIDPass));
    16.             commandBuffer.SetGlobalFloat(ShaderIDs.ZBias, rendererFeature.Bias);
    17.            
    18.             commandBuffer.SetRenderTarget(rendererFeature.OverlayIDTexture);
    19.             commandBuffer.ClearRenderTarget(true, true, Color.clear, 1.0f);
    20.            
    21.             foreach (var instance in OverlaySelectable.Instances)
    22.             {
    23.                 if (!instance._highlightAlways) continue;
    24.                 commandBuffer.SetGlobalInt(ShaderIDs.GroupID, instance._overlayGroupID);
    25.                 commandBuffer.DrawAllMeshes(instance.gameObject, rendererFeature.Material, PassID);
    26.             }
    27.            
    28.             context.ExecuteCommandBuffer(commandBuffer);
    29.             CommandBufferPool.Release(commandBuffer);
    30.         }
    31.     }
    Code (CSharp):
    1. public class RenderOverlayPass : ScriptableRenderPass
    2.     {
    3.         private const int PassID = 1;
    4.        
    5.         private readonly OverlayRendererFeature rendererFeature;
    6.         private CommandBuffer commandBuffer;
    7.  
    8.         public RenderOverlayPass(OverlayRendererFeature rendererFeature)
    9.         {
    10.             this.rendererFeature = rendererFeature;
    11.         }
    12.        
    13.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    14.         {
    15.             commandBuffer = CommandBufferPool.Get(nameof(RenderOverlayPass));
    16.             commandBuffer.SetGlobalFloat(ShaderIDs.ZBias, rendererFeature.Bias);
    17.            
    18.             // Step 2: Apply overlay effect
    19.             commandBuffer.SetRenderTarget(renderingData.cameraData.targetTexture, rendererFeature.OverlayIDTexture);
    20.             commandBuffer.SetGlobalTexture(ShaderIDs.OverlayIDTexture, rendererFeature.OverlayIDTexture);
    21.            
    22.             foreach (var instance in OverlaySelectable.Instances)
    23.             {
    24.                 if (!instance._highlightAlways) continue;
    25.                
    26.                 commandBuffer.SetGlobalVector(ShaderIDs.FillColor, rendererFeature.GroupColors[instance._overlayGroupID]._fillColor);
    27.                 commandBuffer.SetGlobalVector(ShaderIDs.OutlineColor, rendererFeature.GroupColors[instance._overlayGroupID]._outlineColor);
    28.                 commandBuffer.DrawAllMeshes(instance.gameObject, rendererFeature.Material, PassID);
    29.             }
    30.            
    31.             context.ExecuteCommandBuffer(commandBuffer);
    32.             CommandBufferPool.Release(commandBuffer);
    33.         }
    34.     }
    And this is the shader:


    Code (CSharp):
    1. Shader "Hidden/OverlayShader"
    2. {
    3.     HLSLINCLUDE
    4.  
    5.         #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    6.         #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    7.  
    8.         #define MAX_GROUP_COUNT 16
    9.         #define COMPUTE_EYEDEPTH(o) o = -TransformWorldToView( v.vertex ).z
    10.  
    11.    
    12. #if Pattern_Diamond
    13.         // - - x - -
    14.         // - x - x -
    15.         // x - c - x
    16.         // - x - x -
    17.         // - - x - -
    18.         static const int samplePattern_Count = 8;
    19.         static const float2 samplePattern[8] =
    20.         {
    21.             float2( 2, 0 ),
    22.             float2(-2, 0 ),
    23.             float2( 1, 1 ),
    24.             float2(-1,-1 ),
    25.             float2( 0, 2 ),
    26.             float2( 0,-2 ),
    27.             float2(-1, 1 ),
    28.             float2( 1,-1 )
    29.         };
    30.  
    31. #elif Pattern_Rect
    32.         // - - - - -
    33.         // - x x x -
    34.         // - x c x -
    35.         // - x x x -
    36.         // - - - - -
    37.         static const int samplePattern_Count = 8;
    38.         static const float2 samplePattern[8] =
    39.         {
    40.             float2( 1, 0 ),
    41.             float2(-1, 0 ),
    42.             float2( 1, 1 ),
    43.             float2(-1,-1 ),
    44.             float2( 0, 1 ),
    45.             float2( 0,-1 ),
    46.             float2(-1, 1 ),
    47.             float2( 1,-1 )
    48.         };
    49. #endif
    50.  
    51.         // This provides access to the vertices of the mesh being rendered
    52.         struct appdata
    53.         {
    54.             float4 vertex : POSITION;
    55.             float2 uv : TEXCOORD0;
    56.         };
    57.  
    58.         struct v2f
    59.         {
    60.             float4 vertex : SV_POSITION;
    61.             float eyeDepth : TEXCOORD0;
    62.         };
    63.  
    64.         float4 _FillColor;
    65.         float4 _OutlineColor;
    66.  
    67.         float4 _FillColors[MAX_GROUP_COUNT];
    68.         float4 _OutlineColors[MAX_GROUP_COUNT];
    69.         int _GroupID;
    70.         float _ZBias;
    71.  
    72.         TEXTURE2D(_OverlayIDTexture);
    73.         TEXTURE2D(_CameraDepthTexture);
    74.  
    75.         bool IsEdgePixel(int2 screenPos, const int sampleCount, const float2 offsets[8] )
    76.         {
    77.             // Get overlay id of the pixel currently being rendered
    78.             float center = _OverlayIDTexture.Load(int3(screenPos.xy, 0)).r;
    79.             // Compare it to all neighbors using the sample offsets
    80.             for(int i = 0; i < sampleCount; i++)
    81.             {
    82.                 float neighbor = _OverlayIDTexture.Load(int3(screenPos.xy + offsets[i], 0)).r;
    83.                 if(neighbor != center)
    84.                 {
    85.                     // This is an edge pixel! use outline color
    86.                     return true;
    87.                 }
    88.             }
    89.  
    90.             return false;        
    91.         }
    92.  
    93.         bool IsEdgePixel(float groupID, int2 screenPos, const int sampleCount, const float2 offsets[8])
    94.         {
    95.             // Compare it to all neighbors using the sample offsets
    96.             for(int i = 0; i < sampleCount; i++)
    97.             {
    98.                 float neighbor = _OverlayIDTexture.Load(int3(screenPos.xy + offsets[i], 0)).r;
    99.                 if(neighbor != groupID)
    100.                 {
    101.                     // This is an edge pixel! use outline color
    102.                     return true;
    103.                 }
    104.             }
    105.  
    106.             return false;
    107.         }
    108.  
    109.         // Vertex shader
    110.         v2f Vert(appdata v)
    111.         {
    112.             v2f o;
    113.             o.vertex = TransformObjectToHClip(v.vertex);
    114.             o.eyeDepth = TransformObjectToHClip(v.vertex).z;
    115.             COMPUTE_EYEDEPTH(o.eyeDepth);
    116.            
    117.             return o;
    118.         }
    119.  
    120.         // Vertex shader passthrough
    121.         v2f VertPassthrough(appdata v)
    122.         {
    123.             v2f o;
    124.             o.vertex = v.vertex;
    125.             o.eyeDepth = TransformWorldToView(v.vertex).z;
    126.             COMPUTE_EYEDEPTH(o.eyeDepth);
    127.             return o;
    128.         }
    129.  
    130.         // Fragment shader (first pass)
    131.         float FragWriteOverlayID(float4 screenPos : VPOS, float eyeDepth : TEXCOORD0) : SV_Target
    132.         {
    133. #if EnableDepthTest
    134.             // The depth of the current fragment
    135.             float vDepth = eyeDepth / _ProjectionParams.z;
    136.             // The depth of the fragment in the depth buffer
    137.             float gDepth = Linear01Depth(_CameraDepthTexture.Load(int3(screenPos.xy, 0)).r, _ZBufferParams);
    138.             // Depth test
    139.             if(vDepth - _ZBias > gDepth)
    140.                 discard;
    141. #endif
    142.  
    143.             // Map range [0, 255] to [0.0f, 1.0f]
    144.             return (float)_GroupID / 255.0f;
    145.         }
    146.  
    147.         float4 FragOverlay(float4 screenPos : VPOS, float eyeDepth : TEXCOORD0) : SV_Target
    148.         {
    149.             //return float4(1, 0, 0, 1);
    150.  
    151.             float center = _OverlayIDTexture.Load(int3(screenPos.xy, 0)).r;
    152.             int centerID = round(center * 255.0);
    153.             if(IsEdgePixel(center, screenPos, samplePattern_Count, samplePattern))
    154.             {
    155.                 return _OutlineColors[centerID];
    156.             }
    157.             return _FillColors[centerID];
    158.         }
    159.  
    160.         float4 FragOverlayDirect(float4 screenPos : VPOS, float eyeDepth : TEXCOORD0) : SV_Target
    161.         {
    162.             float center = _OverlayIDTexture.Load(int3(screenPos.xy, 0)).r;
    163.             int centerID = round(center * 255.0);
    164.             if(IsEdgePixel(center, screenPos, samplePattern_Count, samplePattern))
    165.             {
    166.                 return _OutlineColor;
    167.             }
    168.             return _FillColor;
    169.         }
    170.  
    171.     ENDHLSL
    172.  
    173.     SubShader
    174.     {
    175.         Tags { "Queue" = "Transparent" "RenderPipeline" = "UniversalRenderPipeline" }
    176.        
    177.         Pass // 0
    178.         {
    179.             Stencil {
    180.                 Ref 1
    181.                 Comp always
    182.                 Pass replace
    183.             }
    184.  
    185.             Name "Pass_WriteID"
    186.             Tags { "LightMode" = "SRPDefaultUnlit" }
    187.             ZTest LEqual
    188.             ZWrite On
    189.             Cull Back
    190.             Blend Off
    191.  
    192.             HLSLPROGRAM
    193.                 #pragma target 3.0
    194.                 #pragma multi_compile Pattern_Diamond Pattern_Rect
    195.                 #pragma multi_compile_local __ EnableDepthTest
    196.                 #pragma vertex Vert
    197.                 #pragma fragment FragWriteOverlayID
    198.             ENDHLSL
    199.         }
    200.  
    201.         Pass // 1
    202.         {
    203.             Stencil {
    204.                 Ref 1
    205.                 Comp equal
    206.             }
    207.  
    208.             Name "Pass_RenderOverlay"
    209.             Tags { "LightMode" = "UniversalForward" }
    210.             ZTest LEqual
    211.             ZWrite Off
    212.             Cull Off
    213.             //Blend Off
    214.             Blend SrcAlpha OneMinusSrcAlpha
    215.  
    216.             HLSLPROGRAM
    217.                 #pragma target 3.0
    218.                 #pragma multi_compile Pattern_Diamond Pattern_Rect
    219.                 #pragma vertex Vert
    220.                 #pragma fragment FragOverlayDirect
    221.             ENDHLSL
    222.         }
    223.     }
    224. }
     

    Attached Files:

  2. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
  3. KYL3R

    KYL3R

    Joined:
    Nov 16, 2012
    Posts:
    128
    You could try Window->Analysis->Frame-Debugger to see if your Pass is executed.