Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  5. Nominations have been announced for this years Unity Awards. Celebrate the wonderful projects made by your peers this year and get voting! Vote here!
    Dismiss Notice
  6. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  7. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Making a local pixelation image effect shader

Discussion in 'Shaders' started by lmgginspace, May 22, 2013.

  1. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    Good day everyone. For the last few days i've been trying to make a pixelation image effect for unity pro, with a pixel shader, but without success.

    I want to make a defined rectangular area of the screen to go pixelated. The exact effect is like the one shows in the sims games, when the game needs to censor them. Like this.
    $MTS_grimreefer24601-1216792-NakedSleep.jpg

    I've been trying a lot of things and searched over the web for hlsl tutorials, reference and whatever, but i cannot make it. The only i got to work is making the effect by converting RenderTexture to Texture2D and using SetPixels() in the selected area, but it is obviously very slow. I need a pixel shader for this.

    Any help is very appreciated. A link to a tutorial, a piece of code, slight advice, whatever is useful.

    Thanks in advance. :)
     
  2. Elehe

    Elehe

    Joined:
    May 19, 2013
    Posts:
    14
  3. gaustwick

    gaustwick

    Joined:
    May 23, 2009
    Posts:
    237
    The easiest way to do this for all targets is to look at the SSAO C# source code, which shows you how to downsample the rendertexture into a temporary, and then set it as a texture variable for your image effect. (Remember to set the RenderTexture.filterMode to FilterMode.Point so you get a pixelation effect as opposed to a blurring effect)

    In your Image Effect shader, simply use the vert_img vertex shader, which uses the v2f_img struct to send information to the fragment shader (The source of these is in UnityCG.cginc, which you should refer to for the syntax). In the fragment shader, Use the uv in the v2f_img as a position for simplicity,which you may have to invert the y value of if UNITY_UV_STARTS_AT_TOP is set(look at the vignette shader for how to do this), or the position value, depending on how you want to specify the pixelated area. Then simply set the colour from the main texture in the non-pixelated area, and the colour from the downsampled texture in the pixelated area.

    That should work :)
     
  4. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    First, thanks a lot for fast answers :)

    I've been experimenting with the down-sampling of the texture (without going into shaders) and it's going perfect. I'm now trying to make the shader, but I'm still very unexperienced, yet I think I have the bare-bones of the shader.

    Code (csharp):
    1.  
    2. Shader "Hidden/Pixelation Effect"
    3. {
    4.   Properties
    5.   {
    6.     _MainTexture ("Main Texture", 2D) = "white" {}
    7.     _DownsampledTexture ("Downsampled Texture", 2D) = "white" {}
    8.   }
    9.  
    10.   SubShader
    11.   {
    12.     Pass
    13.     {
    14.       ZTest Always Cull Off ZWrite Off
    15.       Fog { Mode off }
    16.      
    17.       CGPROGRAM
    18.       #pragma vertex vert_img
    19.       #pragma fragment frag
    20.       #pragma fragmentoption ARB_precision_hint_fastest
    21.      
    22.       #include "UnityCG.cginc"
    23.      
    24.       uniform float4 _RectangleArea;
    25.      
    26.       float4 frag(v2f_img i) : COLOR
    27.       {
    28.         // Do pixelation effect
    29.       }
    30.       ENDCG
    31.     }
    32.   }
    33.  
    34.   Fallback off
    35. }
    36.  
    My code is prepared to pass both textures to the material. I'd like to ask how do you combine the two textures by a defined area in the shader code, i don't now how to at this time. And ask why Unity complains for a syntax error at the line "CGPROGRAM".:confused:

    PS: The DX11 examples were very good, but i have to make this in DX10 and DX9. Sorry, my fault for not saying.
    :DThanks a lot:D
     
  5. gaustwick

    gaustwick

    Joined:
    May 23, 2009
    Posts:
    237
    You virtually had it. This should work:
    Code (csharp):
    1.  
    2. Shader "Hidden/Pixelation Effect"
    3. {
    4.   Properties
    5.   {
    6.     _MainTex ("Main Texture", 2D) = "white" {}
    7.     _DownsampledTexture ("Downsampled Texture", 2D) = "white" {}
    8.   }
    9.  
    10.      
    11. Subshader {
    12.       ZTest Always Cull Off ZWrite Off
    13.       Fog { Mode off }
    14.  
    15.  Pass {
    16.  
    17.       CGPROGRAM
    18.       #pragma vertex vert_img
    19.       #pragma fragment frag
    20.       #pragma fragmentoption ARB_precision_hint_fastest
    21.      
    22.       #include "UnityCG.cginc"
    23.      
    24.       uniform float4 _RectangleArea;
    25.       sampler2D _MainTex;
    26.       sampler2D _DownsampledTexture;
    27.       float4 _MainTex_TexelSize;
    28.  
    29.       float4 frag(v2f_img i) : COLOR
    30.       {
    31.         // make sure uv is the right way up
    32.         #if UNITY_UV_STARTS_AT_TOP
    33.         if (_MainTex_TexelSize.y < 0)
    34.              i.uv.y = 1.0 - i.uv.y;
    35.         #endif
    36.        
    37.         // start with original render texture
    38.         float4 col = tex2D(_MainTex,i.uv);
    39.        
    40.         // if within rectangle, replace with downsampled version.
    41.         if(i.uv.x > _RectangleArea.x  i.uv.x < _RectangleArea.z)
    42.         {
    43.             if(i.uv.y >_RectangleArea.y  i.uv.y < _RectangleArea.w)
    44.             {
    45.                 col = tex2D(_DownsampledTexture,i.uv);
    46.             }
    47.         }
    48.  
    49.         return col;
    50.       }
    51.      
    52.       ENDCG
    53.      
    54.    }
    55. }
    56.   Fallback off
    57. }
    58.  
    My hands aren't that great at the moment, so there's a lot of cut paste there, so check it makes sense:) (it compiles, and looks right!)
     
  6. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,351
    I think the easiest and fastest approach here is to use a GrabPass and stepped sampling. It can all be done in a single shader this way, and gives you the twinkling aliased effect rather than the smooth one you'd get from averaging:
    Code (csharp):
    1. Shader "Pixelate" {
    2.     Properties {
    3.         _CellSize ("Cell Size", Vector) = (0.02, 0.02, 0, 0)
    4.     }
    5.     SubShader {
    6.         Tags { "RenderType"="Opaque" }
    7.         LOD 200
    8.        
    9.         GrabPass { "_PixelationGrabTexture"}
    10.        
    11.         Pass {
    12.             CGPROGRAM
    13.                 #pragma vertex vert
    14.                 #pragma fragment frag
    15.                 #include "UnityCG.cginc"
    16.            
    17.                 struct v2f {
    18.                     float4 pos : SV_POSITION;
    19.                     float4 grabUV : TEXCOORD0;
    20.                 };
    21.                
    22.                 float4 _CellSize;
    23.                
    24.                 v2f vert(appdata_base v) {
    25.                     v2f o;
    26.                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    27.                     o.grabUV = ComputeGrabScreenPos(o.pos);
    28.                     return o;
    29.                 }
    30.            
    31.                 sampler2D _PixelationGrabTexture;
    32.            
    33.                 float4 frag(v2f IN) : COLOR {
    34.                     float2 steppedUV = IN.grabUV.xy/IN.grabUV.w;
    35.                     steppedUV /= _CellSize.xy;
    36.                     steppedUV = round(steppedUV);
    37.                     steppedUV *= _CellSize.xy;
    38.                     return tex2D(_PixelationGrabTexture, steppedUV);
    39.                 }
    40.             ENDCG
    41.         }
    42.     }
    43. }
    44.  
     
  7. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    Thanks a lot gaustwick!!!:grin: I got it working now the exact way i wanted, and i even got the grasp for making other area effects if i need to.
    Thanks a lot Daniel too, your method works awesome too, but i do not know right now how to modify it so it only affects a rectangular area of the viewport.

    Only a slight question to gaustwick...
    In the vignetting shader, the "UNITY_UV_STARTS_AT_TOP" thingy check is in the vertex function, but in the shader code you showed to me, it's in the fragment function. What's the difference in putting the check in one function or the other? I ask only because i want to learn more.
     
    Last edited: May 23, 2013
  8. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,351
    It's a shader you can put on any object. If you want the effect to move with the camera, put it on a mesh that is a child of your camera.
     
  9. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    So, if i put it in the material of some mesh, it does render whatever is behind pixelated?:confused:
     
  10. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,351
    Yes. Additionally, you could put it on a cube or whatever that fully surrounds your object, ensuring that it is pixelated appropriately from every angle.
     
  11. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    I'm testing it right now, and it's awesome, it lets me have even finer control of the effect. Thanks a lot!!! :D
     
  12. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,351
    I'm glad it works for you. Note that you can control the cell size in the material, but Z and W don't do anything.
     
  13. gaustwick

    gaustwick

    Joined:
    May 23, 2009
    Posts:
    237
    A bit late, as you're using Daniel's far more versatile method, but the only difference is speed, as it is being called every pixel as opposed to only 4 times if it was in the vertex shader (image effects make a single quad for the screen, iirc). I thought that for simplicity's sake, it might as well go in the pixel shader, as on modern graphics cards it wouldn't really be a performance problem and may even be simplified by the shader optimizer in the driver. If you did ever use that method and you found it to be a bottleneck, moving it to the vertex shader would be fine, as the algorithm would be the same.

    Nonetheless, I would use Daniel's version :D
     
  14. lmgginspace

    lmgginspace

    Joined:
    Nov 22, 2012
    Posts:
    33
    A bit late too, but thanks for explaining so clear to me.
     
  15. spectre1989

    spectre1989

    Joined:
    Oct 6, 2009
    Posts:
    80
    That's awesome, I was trying to do something just like this but I was dividing by grabUV.w after I applied the stepping to the uv, so it looked weird when viewing from an angle. I don't really understand why this happens though, like I know that ComputeGrabScreenPos puts hpos.w into grabUV.w which I think means it's the distance from the camera to the vertex, but why am I dividing the uv by that? I also tried looking at ComputeGrabScreenPos, this is the gist of it:
    Code (csharp):
    1. float4 o = pos * 0.5f;
    2. o.xy = float2(o.x, o.y) + o.w;
    3. o.zw = pos.zw;
    I don't really understand how that works though, why is it adding o.w (pos.w/2)?

    Sorry for the word-vomit, I'm not very good with shader-math :confused:
     
  16. spectre1989

    spectre1989

    Joined:
    Oct 6, 2009
    Posts:
    80
    Also, I adjusted my version of the shader to have a universal _PixelSize float rather than a vector, and you can make the pixels the same size regardless of screen resolution with something like this:
    Code (csharp):
    1.  
    2. float4 frag( frag_in f ) : COLOR
    3. {
    4.     float2 uv = f.grabUV.xy;
    5.  
    6.     uv /= _PixelSize / _ScreenParams.xy;
    7.     uv = round( uv );
    8.     uv *= _PixelSize / _ScreenParams.xy;
    9.  
    10.         return tex2D( _GrabTexture, uv );
    11. }
    12.  
    Alternatively when you set _CellSize just incorporate Screen.width and Screen.height via a script.
     
  17. Marcelo-Viana

    Marcelo-Viana

    Joined:
    Jun 29, 2013
    Posts:
    11
    Tried to adapt Daniel's shader and it works beautifully on the PC, but the shader doesn't seem to work on a Mac with integrated Intel graphics. I've very little knowledge of shaders so I'm not sure what's causing the issue. Any ideas?
     
  18. GravityGamesDan

    GravityGamesDan

    Joined:
    Jul 29, 2013
    Posts:
    2
    Is it possible to make a shader that does this that doesn't use post processing?
     
  19. Aelcyx

    Aelcyx

    Joined:
    Jun 13, 2014
    Posts:
    5
    I had a problem with this shader where when I re-opened Unity 5, the shader ceased to function. However, it would function upon creation. Turns out there was a problem with the Render Queue. Here's my update to the shader which works beautifully.


    Code (CSharp):
    1. Shader "Custom\Pixelate"
    2. {
    3.     Properties
    4.     {
    5.         _CellSize ("Cell Size", Vector) = (0.02, 0.02, 0, 0)
    6.     }
    7.     SubShader {
    8.         Tags { "RenderType"="Opaque" "Queue" = "Transparent" }
    9.         LOD 200
    10.      
    11.         GrabPass { "_PixelationGrabTexture"}
    12.      
    13.         Pass {
    14.             CGPROGRAM
    15.                 #pragma vertex vert
    16.                 #pragma fragment frag
    17.                 #include "UnityCG.cginc"
    18.          
    19.                 struct v2f {
    20.                     float4 pos : SV_POSITION;
    21.                     float4 grabUV : TEXCOORD0;
    22.                 };
    23.              
    24.                 float4 _CellSize;
    25.              
    26.                 v2f vert(appdata_base v) {
    27.                     v2f o;
    28.                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    29.                     o.grabUV = ComputeGrabScreenPos(o.pos);
    30.                     return o;
    31.                 }
    32.          
    33.                 sampler2D _PixelationGrabTexture;
    34.          
    35.                 float4 frag(v2f IN) : COLOR
    36.                 {
    37.                     float2 steppedUV = IN.grabUV.xy/IN.grabUV.w;
    38.                     steppedUV /= _CellSize.xy;
    39.                     steppedUV = round(steppedUV);
    40.                     steppedUV *= _CellSize.xy;
    41.                     return tex2D(_PixelationGrabTexture, steppedUV);
    42.                 }
    43.             ENDCG
    44.         }
    45.     }
    46. }
     
  20. Sir-Keyzinburga

    Sir-Keyzinburga

    Joined:
    Aug 8, 2011
    Posts:
    10
    I use this shader in Unity 4.5.5. But I ran into a little detail problem. I basically want to render all objects on all of my sortinglayers as pixelated except for one. The GUI sortingLayer. But it doesn't seem to take it into account.
    if the pixelateShader object with the pixelate_Material on it is physically between the camera and the other object that is on a different layer then default, the object (that is on a different layer) is not rendered at all.
    I hope the sentence makes sense at least.
    I tried setting the sortingLayer of the pixelateshader by code to the GUI layer, while setting the order to something ridiculously low. But that did not help me, except that it didn't matter where in the scene the pixelateObject was placed for pixelating the default sortinglayer.
    Do you have any tips/directions?

    Edit:
    Adding the line
    Code (CSharp):
    1. ZWrite Off Lighting Off Cull Off Fog { Mode Off }
    right under the setting of the renderqueue seemed to do the trick. Sorry I don't know what it does exactly, but I imagine the Cull Off is the important part.
    Now I set the sortinglayer and order in code and it seems to listen to that setting
     
    Last edited: Aug 7, 2015
  21. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    @spectre1989 I'm trying to modify this to get a constant / fixed pixel size as well, but I don't understand shaders good enough to get it working. Any chance you could share your full script for this, so I can better understand how you did it?
     
  22. spectre1989

    spectre1989

    Joined:
    Oct 6, 2009
    Posts:
    80
    Aelcyx's code is probably the best to use, as that should be Unity 5 compatible. To set the pixel size via a script use something like:

    Code (CSharp):
    1. float cellSize = 10;
    2. this.sharedMaterial.SetVector( "_CellSize", new Vector4(Screen.width/cellSize, Screen.height/cellSize));
     
  23. astearon

    astearon

    Joined:
    May 9, 2016
    Posts:
    7
    I tried using the shader on a inverted sphere parented to my main character camera but it does not render.

    In the Scene Editor I can see that the sphere renders only at a certain distance and angle relative to the editor view :(

    Can anyone help me with this ?
     
  24. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    I'd assume the problem is the fact the sphere is inverted. Why are you using an inverted sphere? Does the shader work on non-inverted objects?
     
  25. astearon

    astearon

    Joined:
    May 9, 2016
    Posts:
    7
    Since the shader was not visible on a plane from both sides when I tested it (in editor) I assumed that it might happen the same when on a sphere . Since the sphere envelopes the camera that was the conclusion I arrived at.
    It may be wrong but the fact that is the shader works intermittently regardless of what object it is placed on and it's the same for both edit mode and in play mode. :( I don't think the sphere is the problem.
     
  26. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    A few questions:
    1. What version of Unity are you running?
    2. What platform are you developing on?
    3. Which version of this shader are you using?
    4. Can you actually show us the code if it's custom?
    Here's an improved version of Daniel's shader code above. You might want to give it try and see if it works any better for you.

    Code (CSharp):
    1. Shader "Custom/Pixelate New"
    2. {
    3.     Properties
    4.     {
    5.         _PixelSize("Pixel Size", Float) = 10
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" }
    11.         Blend Off
    12.         Lighting Off
    13.         Fog{ Mode Off }
    14.         ZWrite Off
    15.         LOD 200
    16.         Cull Off
    17.  
    18.         GrabPass{ "_GrabTexture" }
    19.  
    20.         Pass
    21.         {
    22.             CGPROGRAM
    23.  
    24.             #pragma vertex vert
    25.             #pragma fragment frag
    26.             #include "UnityCG.cginc"
    27.  
    28.             struct v2f
    29.             {
    30.                 float4 pos : SV_POSITION;
    31.                 float4 uv : TEXCOORD0;
    32.             };
    33.  
    34.             float _PixelSize;
    35.  
    36.             v2f vert(appdata_base v)
    37.             {
    38.                 v2f o;
    39.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    40.                 o.uv = ComputeGrabScreenPos(o.pos);
    41.                 return o;
    42.             }
    43.  
    44.             sampler2D _GrabTexture;
    45.  
    46.             float4 frag(v2f IN) : COLOR
    47.             {
    48.                 float2 steppedUV = IN.uv.xy / IN.uv.w;
    49.                 steppedUV /= _PixelSize / _ScreenParams.xy;
    50.                 steppedUV = round(steppedUV);
    51.                 steppedUV *= _PixelSize / _ScreenParams.xy;
    52.  
    53.                 return tex2D(_GrabTexture, steppedUV);
    54.             }
    55.          
    56.             ENDCG
    57.         }
    58.     }
    59. }
    This version prevents the pixels from getting distorted by the screen aspect ratio. I've also insured culling mode is off. Which means the effect is always visible, even with inverted meshes/normals.
     

    Attached Files:

    Last edited: May 13, 2016
    skullthug and Almakos like this.
  27. nevaran

    nevaran

    Joined:
    May 21, 2010
    Posts:
    233
    Hey - this is actually quite amazing, but is there a way to make it pixelate only the object the shader is attached to? There is a recent game, Ratchet & Clank that came out and had a pixelizer weapon that pixelates only a targeted object.
     
  28. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    I'm not really sure if that's even possible with this shader. The Ratchet & Clank effect is made with 3D voxels, so it's a completely different technique.
     
  29. nevaran

    nevaran

    Joined:
    May 21, 2010
    Posts:
    233
    Interesting, i would've thought it was using a masking effect similar to the UI ones in Unity...
     
  30. Shutter

    Shutter

    Joined:
    Feb 6, 2016
    Posts:
    22
    Last edited: May 23, 2016
  31. astearon

    astearon

    Joined:
    May 9, 2016
    Posts:
    7

    Thank you for the reply, I did not see it until now.
    I have the latest Unity 5 free version.
    Platform: Win10x64 PC (Nvidia GTX790 Ti)
    I have not modified the shader in any way.
     
  32. MetroidJunkie2015

    MetroidJunkie2015

    Joined:
    Nov 8, 2015
    Posts:
    30
    The effect works but there seems to be a glitch where, save for a couple of angles, the rest of the background of the square is just whatever solid color is the background in the camera.


     
  33. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    265
    Hi,

    It looks like the GrabPass{ "_GrabTexture" } function is ignoring unity sprites and canvas, only 3D objects are pixelated.
    Any idea to include them in the grabbing process ?
     
  34. Peter77

    Peter77

    Joined:
    Jun 12, 2013
    Posts:
    2,827
    You could try to change the rendering order (Queue tag) of the shader/material that is using GrabPass and is responsible to draw the pixelated area. The idea would be to make sure it renders after your sprites.

    If it still does not contain the proper/latest rendering, try using a different _GrabPass texture name or leave the name out entirely (please read this, because it can impact performance). It might not contain the expected content, because Unity grabs it once per frame only.

    You could use the Frame Debugger to verify the pixelated area is rendered with the order you expect.

    If changing the Queue tag in your shader has no impact on the rendering order, it might be caused by this bug.

    PS: I guess UI Canvas's that use "Screen Space Overlay" are rendered last always, thus won't be included in GrabPass ever? (just wild guessing)
     
  35. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    265
    Thanks for the ideas :)

    I tried "Queue" = "Overlay" to "Queue" = "Overlay+999999", same problem :/

    Doesn't help :/

    Everything is rendered at once in the step "Render.TransparentGeometry", with all sprites unpixelated :(


    Changing the rendering order manually doesn't help :(

    It looks like so...

    I think it's a dead end :(
     
  36. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    Did my updated version help at all? I have the same setup as you, except I'm using a GTX 960, and it works just fine for me. So this might be a video card and/or driver issue.

    @MetroidJunkie2015 Which version of this shader are you using? I had the same issue for awhile, but can no longer reproduce it. Maybe this problem is related to the mesh and/or layer your object is using?

    @Alesk What exactly are you trying to do here? Sounds like you're trying to do an entire screen effect. In that case there are better ways to go about it. This shader will pixelate anything behind it, including sprites and the UI. However, the UI is always render in-front of everything, unless you switch the canvas render mode to "Screen Space - Camera" or "World Space" ;)
     
  37. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    265
    Yes, I'm trying a fullscreen pixelation.
    I've already tried to change the canvas render mode, but it doesn't helps :/
    In this case what are the better ways to do it ? Using a rendertexture and applying the effect on it ?

    Thanks
     
  38. MetroidJunkie2015

    MetroidJunkie2015

    Joined:
    Nov 8, 2015
    Posts:
    30
    The latest one in this thread and it's using the default layer. It also seems to have this glitch regardless of the meshes involved. What did you do to no longer get the glitch?
     
  39. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    @Alesk One way to hack it with the current shader would be to apply a materiel that uses it on to a UI image that fills the entire screen. You can then apply the effect to all other UI elements by making sure it's the last element in the canvas hierarchy. But unfortunately I've noticed this technique creates some strange artifacts on the UI elements, text in particular.

    I think the best way to do this would be with a full screen image effect script like the one below. To make it work for UI elements you'll need to set the canvas render mode to something other than "Screen Space - Overlay". And to keep UI elements rendering on top of everything else just create a new depth only camera for the UI and image effects that has a higher depth than the main camera.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [ExecuteInEditMode]
    4. [RequireComponent(typeof(Camera))]
    5. [AddComponentMenu("Image Effects/Pixelization")]
    6. public class ScreenPixelization : MonoBehaviour
    7. {
    8.     [Range(1, 25)]
    9.     public int resolution = 8;
    10.  
    11.  
    12.     void OnRenderImage(RenderTexture source, RenderTexture destination)
    13.     {
    14.         int w = source.width / resolution;
    15.         int h = source.height / resolution;
    16.  
    17.         var lowRez = RenderTexture.GetTemporary(w, h);
    18.         lowRez.filterMode = FilterMode.Point;
    19.         Graphics.Blit(source, lowRez);
    20.         Graphics.Blit(lowRez, destination);
    21.         RenderTexture.ReleaseTemporary(lowRez);
    22.     }
    23. }
     
    Last edited: Jun 24, 2016
    skullthug likes this.
  40. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    265
    Thanks a lot, that's exactly what I needed :)
     
  41. MetroidJunkie2015

    MetroidJunkie2015

    Joined:
    Nov 8, 2015
    Posts:
    30
    Code (CSharp):
    1. Shader "Custom/Pixelate New"
    2. {
    3.     Properties
    4.     {
    5.         _PixelSize("Pixel Size", Float) = 10
    6.     }
    7.     SubShader
    8.     {
    9.         Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" }
    10.         Blend Off
    11.         Lighting Off
    12.         Fog{ Mode Off }
    13.         ZWrite Off
    14.         LOD 200
    15.         Cull Off
    16.         GrabPass{ "_GrabTexture" }
    17.         Pass
    18.         {
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.             #include "UnityCG.cginc"
    23.             struct v2f
    24.             {
    25.                 float4 pos : SV_POSITION;
    26.                 float4 uv : TEXCOORD0;
    27.             };
    28.             float _PixelSize;
    29.             v2f vert(appdata_base v)
    30.             {
    31.                 v2f o;
    32.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    33.                 o.uv = ComputeGrabScreenPos(o.pos);
    34.                 return o;
    35.             }
    36.             sampler2D _GrabTexture;
    37.             float4 frag(v2f IN) : COLOR
    38.             {
    39.                 float2 steppedUV = IN.uv.xy / IN.uv.w;
    40.                 steppedUV /= _PixelSize / _ScreenParams.xy;
    41.                 steppedUV = round(steppedUV);
    42.                 steppedUV *= _PixelSize / _ScreenParams.xy;
    43.                 return tex2D(_GrabTexture, steppedUV);
    44.             }
    45.        
    46.             ENDCG
    47.         }
    48.     }
    49. }
    This is the one I used that's glitching up.
     
  42. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
    @MetroidJunkie2015 I've tested the shader again, but still can't reproduce the bug. Same bug happened to me once before, but it no longer shows up and I have no idea what's causing it. The only other thing I can think of trying would be to update your video drivers (if available) and try the shader in a new scene\project.

    As a workaround you might try applying it to a UI canvas image instead, as in the technique I posted above.
     
  43. MetroidJunkie2015

    MetroidJunkie2015

    Joined:
    Nov 8, 2015
    Posts:
    30
    I tried a UI Canvas Image, the glitch still persists.



    My Video Card drivers are fully updated, the card itself is the AMD HD 5670 512MB. Weak by today's standards but still a capable DX11 card.
     
  44. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,353
  45. MetroidJunkie2015

    MetroidJunkie2015

    Joined:
    Nov 8, 2015
    Posts:
    30
    I changed the Render Queue to -1 to match an existing shader (Which I think it was telling me to do) and that seemed to fix it. Thanks, man!
     
    Last edited: Jul 3, 2016
  46. Maras

    Maras

    Joined:
    Dec 11, 2012
    Posts:
    16
    I tried each shader listed above and they all work great except of fullscreen WebGL under Firefox (Edge works in fullscreen).

    All of them have the same issue - the fullscreen have a rectangle (green area 950x600, which is the original resolution) in bottom left corner which is rendered correctly, but the rest of the screen is just the last pixel of the rectangle extended to the end of the screen on all models which are using the shader.

    It seems that the shader is not applying new fullscreen width and height.

    Can you please tell me how to fix it? I am not good with shaders at all.
    Thanks :)
     

    Attached Files:

    Last edited: Feb 10, 2017
  47. Rodolinc

    Rodolinc

    Joined:
    Sep 23, 2013
    Posts:
    53
    Excellent! thanks a lot. Do you think is possible to change the Pixel Size depending on the distance with the camera? Since Im using the effect to censor a text, when the camera gets close to it the text is readable. (the shader is on a plane in front of the text)

    EDIT:
    This keeps the same pixel size no matter how close to the camera. (I'm no shader programmer, and just managed to do that)
    How can I say pixel size 10 for camera distance > X and pixel size 50 for camera distance < Y ? In other words having to pixel sizes one for far camera and another for when its close.

    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    2.  
    3. Shader "Custom/Pixelate New"
    4. {
    5.     Properties
    6.     {
    7.         _PixelSizeFar("Pixel Size Far", Float) = 10
    8.         _PixelSizeClose("Pixel Size Close", Float) = 50
    9.     }
    10.  
    11.         SubShader
    12.     {
    13.         Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" }
    14.         Blend Off
    15.         Lighting Off
    16.         Fog{ Mode Off }
    17.         ZWrite Off
    18.         LOD 200
    19.         Cull Off
    20.  
    21.         GrabPass{ "_GrabTexture" }
    22.  
    23.         Pass
    24.     {
    25.         CGPROGRAM
    26.  
    27. #pragma vertex vert
    28. #pragma fragment frag
    29. #include "UnityCG.cginc"
    30.  
    31.         struct v2f
    32.     {
    33.         float4 pos : SV_POSITION;
    34.         float4 uv : TEXCOORD0;
    35.  
    36.         float4 posWorld : TEXCOORD1;
    37.  
    38.     };
    39.  
    40.     float _PixelSizeFar;
    41.     float _PixelSizeClose;
    42.  
    43.     v2f vert(appdata_base v)
    44.     {
    45.         v2f o;
    46.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    47.         o.uv = ComputeGrabScreenPos(o.pos);
    48.        
    49.         o.posWorld = mul(unity_ObjectToWorld, v.vertex);
    50.         return o;
    51.     }
    52.  
    53.     sampler2D _GrabTexture;
    54.  
    55.     float4 frag(v2f IN) : COLOR
    56.     {
    57.         float2 steppedUV = IN.uv.xy / IN.uv.w;
    58.  
    59.         float cameraDist = length(IN.posWorld.xyz - _WorldSpaceCameraPos.xyz);
    60.  
    61.         steppedUV /= (_PixelSizeFar / cameraDist) / _ScreenParams.xy;
    62.         steppedUV = round(steppedUV);
    63.         steppedUV *= (_PixelSizeFar / cameraDist) / _ScreenParams.xy;
    64.  
    65.        
    66.  
    67.         return tex2D(_GrabTexture, steppedUV);
    68.     }
    69.  
    70.         ENDCG
    71.     }
    72.     }
    73. }
     
    Last edited: Jul 14, 2017
  48. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    246
  49. Rodolinc

    Rodolinc

    Joined:
    Sep 23, 2013
    Posts:
    53
  50. Hash-Buoy

    Hash-Buoy

    Joined:
    Jan 4, 2014
    Posts:
    19
    My mesh renderer has 2 materials in the array - mat_0 and mat_1 . When I apply the additional material using this pixelated shader , it only pixelates the texture of the top most material in the array which is mat_1 . Can some one please guide me on what changes i need to make in Grab Pass. Thanks .