Search Unity

How to blur a 2d sprite with transparency?

Discussion in 'General Graphics' started by Waliactico, Apr 9, 2019.

  1. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    Hello,
    I'm developing a 2D game, and I want to blur some sprite layers to show them blurred on top of an un-blurred background. I can't find a way to achieve that.

    Here's an example image to illustrate what I want:
    desired.png
     
  2. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    anyone?
     
  3. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    Have you considered importing said sprites already blurred? This obviously has a limitation that it will only work for foreground objects that never shift into focus.

    Otherwise you'll have to dive into the world of blurring shaders. Google Kawase blur and Gaussian blur shaders for some reference.
     
  4. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    I've considered it, but discarded it, as there's times when I would want to un-blur it. A solution I've thought is to have every sprite imported blurred and unblurred, and fade between them. But this would mean to double the size of all the sprites.

    About blur shaders, I've tested a bit with them, but I've never seen a blur shader that does the borders correctly, alpha-wise I mean. The sprite is blurred in the center, but the borders keep the hard edges that they had when not blurred, so it looks ugly.
    So still not a good solution for the problem...
     
  5. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    This may not be the shaders' fault, it's possibly related to Unity generating a silhouette mesh for each sprite as an optimization move. You can test this theory by importing your sprite as a texture and using it to texture a regular quad facing camera. If the shader works fine with a quad then there you have it - Unity did stuff. Not sure how this optimization can be disabled, or whether you even want to disable it, considering the performance side-effects.

    The blending between two versions of a sprite sounds like the best solution performance-wise.

    When I suggested blurring shaders I meant it as a post-processing effect. Come to think of it, could the post-processing Depth of Field effect solve your problems? https://docs.unity3d.com/Manual/PostProcessing-DepthOfField.html
     
  6. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    It's not a tight mesh problem, sprite is set to full rect, and I've tested it with quads. Problem here is the alpha, which the blur shaders I've tried don't take into account. They just blur the color which makes the output alpha the same as the input alpha, thus the hard edges.

    I've actually tried depth of field fx, but couldn't make it to work with sprites. Even tried some asset store depth of field shader and they don't work with sprites, not sure why.
     
  7. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    Ok, if you've isolated the problem down to alpha it should be possible to make the shader blur the alpha channel as well, could you post the shader?
     
  8. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    I've tried with the standard legacy Blur Optimized Image Effect, this is the shader itself:

    Code (CSharp):
    1.  
    2. Shader "Hidden/FastBlur" {
    3.     Properties {
    4.         _MainTex ("Base (RGB)", 2D) = "white" {}
    5.         _Bloom ("Bloom (RGB)", 2D) = "black" {}
    6.     }
    7.    
    8.     CGINCLUDE
    9.  
    10.         #include "UnityCG.cginc"
    11.  
    12.         sampler2D _MainTex;
    13.         sampler2D _Bloom;
    14.                
    15.         uniform half4 _MainTex_TexelSize;
    16.         half4 _MainTex_ST;
    17.  
    18.         half4 _Bloom_ST;
    19.  
    20.         uniform half4 _Parameter;
    21.  
    22.        
    23.  
    24.         struct v2f_tap
    25.         {
    26.             float4 pos : SV_POSITION;
    27.             half2 uv20 : TEXCOORD0;
    28.             half2 uv21 : TEXCOORD1;
    29.             half2 uv22 : TEXCOORD2;
    30.             half2 uv23 : TEXCOORD3;
    31.         };          
    32.  
    33.         v2f_tap vert4Tap ( appdata_img v )
    34.         {
    35.             v2f_tap o;
    36.  
    37.             o.pos = UnityObjectToClipPos(v.vertex);
    38.             o.uv20 = UnityStereoScreenSpaceUVAdjust(v.texcoord + _MainTex_TexelSize.xy, _MainTex_ST);
    39.             o.uv21 = UnityStereoScreenSpaceUVAdjust(v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h,-0.5h), _MainTex_ST);
    40.             o.uv22 = UnityStereoScreenSpaceUVAdjust(v.texcoord + _MainTex_TexelSize.xy * half2(0.5h,-0.5h), _MainTex_ST);
    41.             o.uv23 = UnityStereoScreenSpaceUVAdjust(v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h,0.5h), _MainTex_ST);
    42.  
    43.             return o;
    44.         }                  
    45.        
    46.         fixed4 fragDownsample ( v2f_tap i ) : SV_Target
    47.         {              
    48.             fixed4 color = tex2D (_MainTex, i.uv20);
    49.             color += tex2D (_MainTex, i.uv21);
    50.             color += tex2D (_MainTex, i.uv22);
    51.             color += tex2D (_MainTex, i.uv23);
    52.             return color / 4;
    53.         }
    54.    
    55.         // weight curves
    56.  
    57.         static const half curve[7] = { 0.0205, 0.0855, 0.232, 0.324, 0.232, 0.0855, 0.0205 };  // gauss'ish blur weights
    58.  
    59.         static const half4 curve4[7] = { half4(0.0205,0.0205,0.0205,0), half4(0.0855,0.0855,0.0855,0), half4(0.232,0.232,0.232,0),
    60.             half4(0.324,0.324,0.324,1), half4(0.232,0.232,0.232,0), half4(0.0855,0.0855,0.0855,0), half4(0.0205,0.0205,0.0205,0) };
    61.  
    62.         struct v2f_withBlurCoords8
    63.         {
    64.             float4 pos : SV_POSITION;
    65.             half4 uv : TEXCOORD0;
    66.             half2 offs : TEXCOORD1;
    67.         };  
    68.        
    69.         struct v2f_withBlurCoordsSGX
    70.         {
    71.             float4 pos : SV_POSITION;
    72.             half2 uv : TEXCOORD0;
    73.             half4 offs[3] : TEXCOORD1;
    74.         };
    75.  
    76.         v2f_withBlurCoords8 vertBlurHorizontal (appdata_img v)
    77.         {
    78.             v2f_withBlurCoords8 o;
    79.             o.pos = UnityObjectToClipPos(v.vertex);
    80.            
    81.             o.uv = half4(v.texcoord.xy,1,1);
    82.             o.offs = _MainTex_TexelSize.xy * half2(1.0, 0.0) * _Parameter.x;
    83.  
    84.             return o;
    85.         }
    86.        
    87.         v2f_withBlurCoords8 vertBlurVertical (appdata_img v)
    88.         {
    89.             v2f_withBlurCoords8 o;
    90.             o.pos = UnityObjectToClipPos(v.vertex);
    91.            
    92.             o.uv = half4(v.texcoord.xy,1,1);
    93.             o.offs = _MainTex_TexelSize.xy * half2(0.0, 1.0) * _Parameter.x;
    94.            
    95.             return o;
    96.         }  
    97.  
    98.         half4 fragBlur8 ( v2f_withBlurCoords8 i ) : SV_Target
    99.         {
    100.             half2 uv = i.uv.xy;
    101.             half2 netFilterWidth = i.offs;
    102.             half2 coords = uv - netFilterWidth * 3.0;
    103.            
    104.             half4 color = 0;
    105.               for( int l = 0; l < 7; l++ )
    106.               {
    107.                 half4 tap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(coords, _MainTex_ST));
    108.                 color += tap * curve4[l];
    109.                 coords += netFilterWidth;
    110.               }
    111.             return color;
    112.         }
    113.  
    114.  
    115.         v2f_withBlurCoordsSGX vertBlurHorizontalSGX (appdata_img v)
    116.         {
    117.             v2f_withBlurCoordsSGX o;
    118.             o.pos = UnityObjectToClipPos(v.vertex);
    119.            
    120.             o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST);
    121.  
    122.             half offsetMagnitude = _MainTex_TexelSize.x * _Parameter.x;
    123.             o.offs[0] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(-3.0h, 0.0h, 3.0h, 0.0h), _MainTex_ST);
    124.             o.offs[1] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(-2.0h, 0.0h, 2.0h, 0.0h), _MainTex_ST);
    125.             o.offs[2] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(-1.0h, 0.0h, 1.0h, 0.0h), _MainTex_ST);
    126.  
    127.             return o;
    128.         }
    129.        
    130.         v2f_withBlurCoordsSGX vertBlurVerticalSGX (appdata_img v)
    131.         {
    132.             v2f_withBlurCoordsSGX o;
    133.             o.pos = UnityObjectToClipPos(v.vertex);
    134.            
    135.             o.uv = half4(UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST),1,1);
    136.  
    137.             half offsetMagnitude = _MainTex_TexelSize.y * _Parameter.x;
    138.             o.offs[0] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(0.0h, -3.0h, 0.0h, 3.0h), _MainTex_ST);
    139.             o.offs[1] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(0.0h, -2.0h, 0.0h, 2.0h), _MainTex_ST);
    140.             o.offs[2] = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + offsetMagnitude * half4(0.0h, -1.0h, 0.0h, 1.0h), _MainTex_ST);
    141.  
    142.             return o;
    143.         }
    144.  
    145.         half4 fragBlurSGX ( v2f_withBlurCoordsSGX i ) : SV_Target
    146.         {
    147.             half2 uv = i.uv.xy;
    148.            
    149.             half4 color = tex2D(_MainTex, i.uv) * curve4[3];
    150.            
    151.               for( int l = 0; l < 3; l++ )
    152.               {
    153.                 half4 tapA = tex2D(_MainTex, i.offs[l].xy);
    154.                 half4 tapB = tex2D(_MainTex, i.offs[l].zw);
    155.                 color += (tapA + tapB) * curve4[l];
    156.               }
    157.  
    158.             return color;
    159.  
    160.         }  
    161.                    
    162.     ENDCG
    163.    
    164.     SubShader {
    165.       ZTest Off Cull Off ZWrite Off Blend Off
    166.  
    167.     // 0
    168.     Pass {
    169.    
    170.         CGPROGRAM
    171.        
    172.         #pragma vertex vert4Tap
    173.         #pragma fragment fragDownsample
    174.        
    175.         ENDCG
    176.        
    177.         }
    178.  
    179.     // 1
    180.     Pass {
    181.         ZTest Always
    182.         Cull Off
    183.        
    184.         CGPROGRAM
    185.        
    186.         #pragma vertex vertBlurVertical
    187.         #pragma fragment fragBlur8
    188.        
    189.         ENDCG
    190.         }  
    191.        
    192.     // 2
    193.     Pass {      
    194.         ZTest Always
    195.         Cull Off
    196.                
    197.         CGPROGRAM
    198.        
    199.         #pragma vertex vertBlurHorizontal
    200.         #pragma fragment fragBlur8
    201.        
    202.         ENDCG
    203.         }  
    204.  
    205.     // alternate blur
    206.     // 3
    207.     Pass {
    208.         ZTest Always
    209.         Cull Off
    210.        
    211.         CGPROGRAM
    212.        
    213.         #pragma vertex vertBlurVerticalSGX
    214.         #pragma fragment fragBlurSGX
    215.        
    216.         ENDCG
    217.         }  
    218.        
    219.     // 4
    220.     Pass {      
    221.         ZTest Always
    222.         Cull Off
    223.                
    224.         CGPROGRAM
    225.        
    226.         #pragma vertex vertBlurHorizontalSGX
    227.         #pragma fragment fragBlurSGX
    228.        
    229.         ENDCG
    230.         }  
    231.     }  
    232.  
    233.     FallBack Off
    234. }
     
  9. IainCarr

    IainCarr

    Joined:
    Mar 9, 2018
    Posts:
    5
  10. IGEUNITY

    IGEUNITY

    Joined:
    Aug 2, 2021
    Posts:
    4
    Well.. Just do what you done to the ball.
     
  11. Aaron_Wong

    Aaron_Wong

    Joined:
    Aug 11, 2020
    Posts:
    1
    I think OP wanted a procedural blur shader, not pre-blurred sprites.
     
    ExtraCat likes this.