Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Help convert Shader to be supported in URP

Discussion in 'Shaders' started by UserNobody, Sep 24, 2020.

  1. UserNobody

    UserNobody

    Joined:
    Oct 3, 2019
    Posts:
    144
    Hello there,
    I have this shader which I used in many previous projects. It's a blur shader that I used for my UI background. It used to work, but now I am working on a new project and I use URP and it doesn't work anymore.

    I am unfortunately, not experienced with shaders, so I am unable to fix this issue.
    Can someone with shader experience convert this shader to be supported in URP? Also I don't know about performance but can this shader be optimized a bit or is it performant already? Thank you!

    Shader:
    Code (CSharp):
    1. Shader "Custom/BLUR" {
    2.     Properties{
    3.         _Color("Main Color", Color) = (1,1,1,1)
    4.         _BumpAmt("Distortion", Range(0,128)) = 10
    5.         _MainTex("Tint Color (RGB)", 2D) = "white" {}
    6.     _BumpMap("Normalmap", 2D) = "bump" {}
    7.     _Size("Size", Range(0, 20)) = 1
    8.     }
    9.  
    10.         Category{
    11.  
    12.         Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
    13.  
    14.  
    15.         SubShader{
    16.  
    17.         GrabPass{
    18.         Tags{ "LightMode" = "Always" }
    19.     }
    20.         Pass{
    21.         Tags{ "LightMode" = "Always" }
    22.  
    23.         CGPROGRAM
    24. #pragma vertex vert
    25. #pragma fragment frag
    26. #pragma fragmentoption ARB_precision_hint_fastest
    27. #include "UnityCG.cginc"
    28.  
    29.         struct appdata_t {
    30.         float4 vertex : POSITION;
    31.         float2 texcoord: TEXCOORD0;
    32.     };
    33.  
    34.     struct v2f {
    35.         float4 vertex : POSITION;
    36.         float4 uvgrab : TEXCOORD0;
    37.     };
    38.  
    39.     v2f vert(appdata_t v) {
    40.         v2f o;
    41.         o.vertex = UnityObjectToClipPos(v.vertex);
    42. #if UNITY_UV_STARTS_AT_TOP
    43.         float scale = -1.0;
    44. #else
    45.         float scale = 1.0;
    46. #endif
    47.         o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
    48.         o.uvgrab.zw = o.vertex.zw;
    49.         return o;
    50.     }
    51.  
    52.     sampler2D _GrabTexture;
    53.     float4 _GrabTexture_TexelSize;
    54.     float _Size;
    55.  
    56.     half4 frag(v2f i) : COLOR{
    57.  
    58.         half4 sum = half4(0,0,0,0);
    59. #define GRABPIXEL(weight,kernelx) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx*_Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight
    60.         sum += GRABPIXEL(0.05, -4.0);
    61.         sum += GRABPIXEL(0.09, -3.0);
    62.         sum += GRABPIXEL(0.12, -2.0);
    63.         sum += GRABPIXEL(0.15, -1.0);
    64.         sum += GRABPIXEL(0.18,  0.0);
    65.         sum += GRABPIXEL(0.15, +1.0);
    66.         sum += GRABPIXEL(0.12, +2.0);
    67.         sum += GRABPIXEL(0.09, +3.0);
    68.         sum += GRABPIXEL(0.05, +4.0);
    69.  
    70.         return sum;
    71.     }
    72.         ENDCG
    73.     }
    74.  
    75.         GrabPass{
    76.         Tags{ "LightMode" = "Always" }
    77.     }
    78.         Pass{
    79.         Tags{ "LightMode" = "Always" }
    80.  
    81.         CGPROGRAM
    82. #pragma vertex vert
    83. #pragma fragment frag
    84. #pragma fragmentoption ARB_precision_hint_fastest
    85. #include "UnityCG.cginc"
    86.  
    87.         struct appdata_t {
    88.         float4 vertex : POSITION;
    89.         float2 texcoord: TEXCOORD0;
    90.     };
    91.  
    92.     struct v2f {
    93.         float4 vertex : POSITION;
    94.         float4 uvgrab : TEXCOORD0;
    95.     };
    96.  
    97.     v2f vert(appdata_t v) {
    98.         v2f o;
    99.         o.vertex = UnityObjectToClipPos(v.vertex);
    100. #if UNITY_UV_STARTS_AT_TOP
    101.         float scale = -1.0;
    102. #else
    103.         float scale = 1.0;
    104. #endif
    105.         o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
    106.         o.uvgrab.zw = o.vertex.zw;
    107.         return o;
    108.     }
    109.  
    110.     sampler2D _GrabTexture;
    111.     float4 _GrabTexture_TexelSize;
    112.     float _Size;
    113.  
    114.     half4 frag(v2f i) : COLOR{
    115.  
    116.         half4 sum = half4(0,0,0,0);
    117. #define GRABPIXEL(weight,kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely*_Size, i.uvgrab.z, i.uvgrab.w))) * weight
    118.  
    119.         sum += GRABPIXEL(0.05, -4.0);
    120.         sum += GRABPIXEL(0.09, -3.0);
    121.         sum += GRABPIXEL(0.12, -2.0);
    122.         sum += GRABPIXEL(0.15, -1.0);
    123.         sum += GRABPIXEL(0.18,  0.0);
    124.         sum += GRABPIXEL(0.15, +1.0);
    125.         sum += GRABPIXEL(0.12, +2.0);
    126.         sum += GRABPIXEL(0.09, +3.0);
    127.         sum += GRABPIXEL(0.05, +4.0);
    128.  
    129.         return sum;
    130.     }
    131.         ENDCG
    132.     }
    133.  
    134.         GrabPass{
    135.         Tags{ "LightMode" = "Always" }
    136.     }
    137.         Pass{
    138.         Tags{ "LightMode" = "Always" }
    139.  
    140.         CGPROGRAM
    141. #pragma vertex vert
    142. #pragma fragment frag
    143. #pragma fragmentoption ARB_precision_hint_fastest
    144. #include "UnityCG.cginc"
    145.  
    146.         struct appdata_t {
    147.         float4 vertex : POSITION;
    148.         float2 texcoord: TEXCOORD0;
    149.     };
    150.  
    151.     struct v2f {
    152.         float4 vertex : POSITION;
    153.         float4 uvgrab : TEXCOORD0;
    154.         float2 uvbump : TEXCOORD1;
    155.         float2 uvmain : TEXCOORD2;
    156.     };
    157.  
    158.     float _BumpAmt;
    159.     float4 _BumpMap_ST;
    160.     float4 _MainTex_ST;
    161.  
    162.     v2f vert(appdata_t v) {
    163.         v2f o;
    164.         o.vertex = UnityObjectToClipPos(v.vertex);
    165. #if UNITY_UV_STARTS_AT_TOP
    166.         float scale = -1.0;
    167. #else
    168.         float scale = 1.0;
    169. #endif
    170.         o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
    171.         o.uvgrab.zw = o.vertex.zw;
    172.         o.uvbump = TRANSFORM_TEX(v.texcoord, _BumpMap);
    173.         o.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
    174.         return o;
    175.     }
    176.  
    177.     fixed4 _Color;
    178.     sampler2D _GrabTexture;
    179.     float4 _GrabTexture_TexelSize;
    180.     sampler2D _BumpMap;
    181.     sampler2D _MainTex;
    182.  
    183.     half4 frag(v2f i) : COLOR{
    184.  
    185.         half2 bump = UnpackNormal(tex2D(_BumpMap, i.uvbump)).rg;
    186.         float2 offset = bump * _BumpAmt * _GrabTexture_TexelSize.xy;
    187.         i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
    188.  
    189.         half4 col = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
    190.         half4 tint = tex2D(_MainTex, i.uvmain) * _Color;
    191.  
    192.         return col * tint;
    193.     }
    194.         ENDCG
    195.     }
    196.     }
    197.     }
    198. }
     
  2. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,521
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    That shader makes use of two features which the URP does not support. Grab pass and multi pass shaders.

    Grab Pass has been replaced with the SRP’s Opaque Texture. This is similar to the Grab Pass in that it provides a texture of the scene, but very different in that it's a one time copy per frame that happens after all opaque materials, the skybox, and opaque image effects have been rendered. This is much different than the Grab Pass where the copy of the scene to a texture happens when that object renders.

    Multi pass can be worked around if your shader only needs two passes, as the SRPs will render one "unlit" pass and one "lit" pass per shader. Note, the "lit" pass doesn't actually need to do any lighting, the shader pass just needs to say it does via the
    LightMode
    tag.

    The above shader has 3 grab passes and 3 rendered passes. The first grab pass copies the current contents of the screen, the rendered pass outputs a blurred version of that, and the next grab pass makes a copy of the blurred output of the previous pass. It then blurs and copies a second time, with the last pass reading from the grab pass that contains the twice blurred screen copy. You can't do any of that with a shader when using an SRP.

    With what's built in to the SRPs, the closest you can get is you can sample the Opaque Texture multiple times to blur it in the same pass that you render it out. There's no point in a two pass shader doing a blur pass and a render pass since you can't sample from the blurred output of the previous pass. But this means any transparent objects or effects in the scene won't be visible through transparent UI, and for sure other UI elements won't be visible through transparent UI. Again, the Opaque Texture is only a copy of the screen after all opaque stuff has been rendered, so nothing transparent will be included.


    The solution to all of this is you'd have to manually make a copy of the final rendered image, blur that in multiple passes, and set the blurred texture as a global texture you sample in your UI, assuming you're rendering your UI using a "Screen Space - Overlay" render mode Canvas. If your Canvas is using Camera or World mode, or you're doing UI with objects placed manually in the scene, then there's not really anything you can do apart from use the Opaque Texture and live with transparent stuff not being visible. You could also pre blur the Opaque Texture using a command buffer which could be a bit faster than doing it in the shader on the UI element if they take up a large part of the screen.
     
    Lars-Steenhoff and UserNobody like this.
  4. UserNobody

    UserNobody

    Joined:
    Oct 3, 2019
    Posts:
    144
    Hey, thanks for the great answer! :) I use the "Screen Space - Overlay" canvas, so I will try to fix it, but I have barely no experience with shaders so I am not sure if I can make this to be honest. It sounds kind of complex