Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Blurred 2D sprites

Discussion in 'General Graphics' started by smetzzz, Dec 29, 2018.

  1. smetzzz

    smetzzz

    Joined:
    Mar 24, 2014
    Posts:
    137
    Hi,

    I am trying to achieve blurred 2D sprites. I want the blurred sprites to run fast on mobile so they don't need to be translucent or dynamic. The workflow would be to add a sprite to the scene and have the ability to blur it with a shader variable.
    Any thought on this is appreciated, thank you!
     
  2. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Hello!

    I'm not entirely sure how efficient a Gaussian blur would be on a mobile device, but I suspect you could easily get away with it, especially if your sprites are of a reasonable resolution.

    Gaussian blurs work by sampling the surrounding pixels in what is referred to as a kernel. Each pixel is assigned a weighted value and these are added up to give the initial pixel its new color value. Now, the smallest kernel you can work with for a Gaussian blur has a size of 9, so that means 9 texture look-ups per pixel in an image (doing some basic math shows this adds up really quickly. A 100x100 sprite would require ~90,000 texture look ups to do a one pass blur!). Thankfully, however, Gaussian blurs have this really cool property of being separable. That means that you only need to sample 6 pixels (Which cuts down that ~90,000 to ~60,000). 3 horizontally, and another 3 vertically. This ends up with the exact same results as if you were to sample all 9 per pixel.

    Here's the Gaussian filter. You'll want to note that the direction of the filter is denoted by the input parameter "stride".

    Code (CSharp):
    1. // 9-tap Gaussian filter with linear sampling
    2. // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
    3. half4 gaussian_filter(float2 uv, float2 stride)
    4. {
    5.     half4 s = tex2D(_MyDepthTex, float4(uv, 0, 0)) * 0.2270270270;
    6.  
    7.     float2 d1 = stride * 1.3846153846;
    8.     s += tex2D(_MyDepthTex, uv + d1) * 0.3162162162;
    9.     s += tex2D(_MyDepthTex, uv - d1) * 0.3162162162;
    10.  
    11.     float2 d2 = stride * 3.2307692308;
    12.     s += tex2D(_MyDepthTex, uv + d2) * 0.0702702703;
    13.     s += tex2D(_MyDepthTex, uv - d2) * 0.0702702703;
    14.  
    15.     return s;
    16. }
    From there you want to define two fragment programs. Each to be used in a separate pass. These will cover the horizontal and vertical direction of the filter for each kernel pass.

    Code (CSharp):
    1. half4 frag_blur_h(v2f_img i) : SV_Target
    2. {
    3.     return gaussian_filter(i.uv, float2(_MyDepthTex_TexelSize.x, 0));
    4. }
    5.  
    6. half4 frag_blur_v(v2f_img i) : SV_Target
    7. {
    8.     return gaussian_filter(i.uv, float2(0, _MyDepthTex_TexelSize.y));;
    9. }
    Now I suppose you could let the shader automatically go over each pass and be done with the blur. But, if you you want control over how blurred an image is, you could write a C# controller script that uses the Gaussian blur material to repeatedly send an image through the blur pipeline via Blit(). Funny enough, the repeated process of sending an image through the pipeline is actually the equivalent of working with a larger kernel size for a cheaper cost.

    Let me know if you have any questions.
     
    Last edited: Dec 29, 2018
    smetzzz likes this.
  3. smetzzz

    smetzzz

    Joined:
    Mar 24, 2014
    Posts:
    137
    Amazing, a great start, thank you I'll give it a shot in the morning.
    I downloaded an asset that works ok but has a few issues and looks overbuilt. This looks like a more elegant solution.
     
  4. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Awesome. Glad I could help out!

    Starting off barebones and bootstrapping your way up tends to work best when it comes to shaders - especially for optimization I've found (granted, I'm just starting off myself!). Definitely be sure to let me know if you get stuck or need some pointers. I'd also love to see your final output when you get it working! Don't think I've seen blurred sprites before.