URP Custom Sprite Shader

I’m expermenting with Unity 2020.1’s URP to see if it’s worth upgrading my project but so far I have had some difficulties trying to get my custom shader to work with the URP.


This is the shader effect I have, where each unit (2D SpriteRenderers) are colored silhouettes when occluded by objects/3D meshes, colors based on whichever alliance they belong to. The shader itself is a customized version of Unity’s Sprite Shader, I wrote an extra pass with custom fields to create the X-Ray effect (with a lot of tinkering around with ZDepth and Stencil to get this to work). The colors are set during the initialization state of the game and can be changed via events.

As far as I know, my shader doesn’t work in URP since it uses forward rather than deferred rendering. So my only option was to follow this tutorial by Brackey’s:

In order to get this:

But this doesn’t really cut it for me as it simply uses a shared shader and renders all occluded parts of a sprite using said shader, which doesn’t allow for any customization whatsoever. The only way I could think of to somehow achieve the effect of my custom shader is to somehow have the shader I made for URP take in a variable of the current object being rendered as the alliance color to and render the silhouette with it. But I don’t think there is anyway for me to do this.

If anyone has any ideas, it’ll be much appreciated.

Here’s the custom shader if anyone’s interested:

Shader "Custom/Sprite(Unit)"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
      
        PixelSnap ("Pixel snap", Float) = 0
        _AlphaTex ("External Alpha", 2D) = "white" {}
        _EnableExternalAlpha ("Enable External Alpha", Float) = 0
      
        _ZWrite ("Depth Write", Float) = 0.0
        _Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.0
        _ShadowAlphaCutoff ("Shadow alpha cutoff", Range(0,1)) = 0.3
        _CustomRenderQueue ("Custom Render Queue", Float) = 0.0
      
        _OverlayColor ("Overlay Color", Color) = (0,0,0,0)
        _Hue("Hue", Range(-0.5,0.5)) = 0.0
        _Saturation("Saturation", Range(0,2)) = 1.0  
        _Brightness("Brightness", Range(0,2)) = 1.0  
      
        _BlendTex ("Blend Texture", 2D) = "white" {}
        _BlendAmount ("Blend", Range(0,1)) = 0.0
      
        _EmissionMap("Emission Map", 2D) = "black" {}
        [HDR] _EmissionColor("Emission Color", Color) = (0, 0, 0)

        [HideInInspector] _SrcBlend ("__src", Float) = 1.0
        [HideInInspector] _DstBlend ("__dst", Float) = 0.0
        [HideInInspector] _RenderQueue ("__queue", Float) = 0.0
        [HideInInspector] _Cull ("__cull", Float) = 0.0

        _RenderQueue("Render Queue", Float) = 0.0

        _Matrix1("matrix", vector) = (1,1,1,1)
        _Matrix2("matrix", vector) = (1,1,1,1)
        _Matrix3("matrix", vector) = (1,1,1,1)

        // Custom
        [Toggle] _Frozen ("Frozen Status", Int) = 0


        _OutlineMode ("Outline Mode", Int) = 0
        _AllianceColor ("Alliance Color", Color) = (0, 0, 0, 1)
    }
  

    SubShader
    {
        Tags
        {
            "Queue" = "Transparent"
            "RenderType" = "Sprite"
            "AlphaDepth" = "False"
            "CanUseSpriteAtlas" = "True"
            "IgnoreProjector" = "True"
        }
        LOD 100

        // Main Pass
        Pass
        {
            Blend[_SrcBlend][_DstBlend]
            Lighting Off
            ZWrite[_ZWrite]
            ZTest LEqual
            Cull[_Cull]
            Lighting Off

            // Write to stencil
            Stencil
            {
                Ref 4
                Comp always
                Pass replace
                ZFail keep
                Fail replace
            }

            CGPROGRAM
                #pragma shader_feature _ _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON _ADDITIVEBLEND _ADDITIVEBLEND_SOFT _MULTIPLYBLEND _MULTIPLYBLEND_X2
                #pragma shader_feature _ALPHA_CLIP
                #pragma shader_feature _TEXTURE_BLEND
                #pragma shader_feature _COLOR_ADJUST
                #pragma shader_feature _FOG

                #pragma fragmentoption ARB_precision_hint_fastest
                #pragma multi_compile_fog
                #pragma multi_compile_instancing
                #pragma multi_compile _ PIXELSNAP_ON
                #pragma multi_compile _ ETC1_EXTERNAL_ALPHA

                #pragma vertex vert
                #pragma fragment frag

                #include "../Shaders/shaders_includes/SpriteShaders/CGIncludes/SpriteUnlit.cginc"
            ENDCG
        }
          
        // Shadow
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
            Offset 1, 1

            Fog { Mode Off }
            ZWrite On
            ZTest LEqual
            Cull Off
            Lighting Off

            CGPROGRAM
                #pragma fragmentoption ARB_precision_hint_fastest
                #pragma multi_compile_shadowcaster
                #pragma multi_compile_instancing
                #pragma multi_compile _ PIXELSNAP_ON
                #pragma multi_compile _ ETC1_EXTERNAL_ALPHA

                #pragma vertex vert
                #pragma fragment frag

                #include "../Shaders/shaders_includes/SpriteShaders/CGIncludes/SpriteShadows.cginc"

            ENDCG
        }
      
        // X-Ray Shader Pass
        Pass
        {
            Tags{
                 "Queue" = "Transparent"
                 "AlphaDepth" = "True"
            }

            Cull Off
            ZWrite off
            ZTest always
            Stencil
            {
                Ref 4
                Comp notequal
                Pass keep
                Fail keep
            }
            Blend SrcAlpha OneMinusSrcAlpha
          
          
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "../Shaders/shaders_includes/SpriteShaders/CGIncludes/ShaderShared.cginc"

            float4 _MainTex_TexelSize;
            float4 _AllianceColor;
            int _OutlineMode;

            struct v_in {
                float4 vertex : POSITION;
                float4 texcoord : TEXCOORD0;
            };

            struct v_out {
                float4 pos : SV_POSITION;
                float2 texcoord : TEXCOORD0;
                fixed4 color : COLOR;
            };

            v_out vert(v_in input) {
                v_out output;

                output.pos = calculateLocalPos(input.vertex);
                output.texcoord = calculateTextureCoord(input.texcoord);

                return output;
            }

            float4 frag(v_out input) : SV_TARGET
            {
                // Dead unit, then skips this pass
                if (_OutlineMode == 2)
                    discard;

                fixed4 textureColor = calculateTexturePixel(input.texcoord.xy);
                ALPHA_CLIP_COLOR(texureColor, input.color);

                if (textureColor.a < 0.1f)
                    discard;

                if (_OutlineMode == 0) {
                    if (textureColor.a < 0.2f)
                        discard;
                    return _AllianceColor;
                }

                // Outline only
                if (textureColor.a != 0) {
                    // Get the neighbouring four pixels.
                    fixed4 pixelUp        =    tex2D(_MainTex, input.texcoord.xy + float2(0, _MainTex_TexelSize.y));
                    fixed4 pixelDown    =    tex2D(_MainTex, input.texcoord.xy - float2(0, _MainTex_TexelSize.y));
                    fixed4 pixelRight    =    tex2D(_MainTex, input.texcoord.xy + float2(_MainTex_TexelSize.x, 0));
                    fixed4 pixelLeft    =    tex2D(_MainTex, input.texcoord.xy - float2(_MainTex_TexelSize.x, 0));

                    // If one of the neighbouring pixels is invisible, render outline.
                    if (pixelUp.a * pixelDown.a * pixelRight.a * pixelLeft.a == 0) {
                        textureColor.rgba = fixed4(1, 1, 1, textureColor.a) * _AllianceColor;
                    }
                    else {
                        discard;
                    }
                }


                return textureColor;
            }

            ENDCG
        }
    }

    CustomEditor "SpriteShaderGUI"
}

Hi anthonytrianh,
If I understand your problem correctly, you wish to be able to set, for instance, the player colors to different colors than the enemies when occluded?
One solution could be to build on top of the RenderObjects/RenderObjectsPass code with a custom render pass and have multiple layers masks (Player1, Player2, Enemies etc.) which each have a a different color(or other properties) passed into an instance of the material you wish to use.
For example like this: