Search Unity

Horizontal wave distortion

Discussion in 'Shaders' started by enhawk, Feb 4, 2015.

  1. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
    does anyone know of a shader that can be put on a quad and make this happen to things behind it / seen through it:



    All the better if it could be animated and use layers too. Simple horizontal pixel shifting.


    (this is a duplicate thread because I can't edit my old one, can a mod merge these?)
     
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    This effect is most often referred to as distortion. google for something like unity distortion shader, it should yield useful results.
     
  3. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I put an example together for you (see below for the download link).

    Here is how it looks:

    (sorry for the bad hiccups in the video, my recorder obviously sucks)

    The idea is to have a texture that describes how strong the distortion is at a certain pixel (black=full distortion to the left, white=full distortion to the right. In the following example, the Red channel represents horizontal and Green channel the vertical distortion. The Blue channel represents a mask (black=no distortion, white=full distortion). The distortion texture is scrolled using the built-in _Time variable, so you get motion into it.

    Code (CSharp):
    1.  
    2. [code=CSharp]//
    3. // Created with Unity 5.1
    4. // Example code to help answer the forum post at:
    5. // http://forum.unity3d.com/threads/horizontal-wave-distortion.295769/
    6. //
    7. // This source code is not a full fledged distortion solution.
    8. // It's just an example and hopefully proves useful for someone.
    9. //
    10. Shader "Custom/GrabPass Disortion" {
    11. Properties {
    12.         _MainTex ("Texture (R,G=X,Y Distortion; B=Mask; A=Unused)", 2D) = "white" {}
    13.         _IntensityAndScrolling ("Intensity (XY); Scrolling (ZW)", Vector) = (0.1,0.1,1,1)
    14.         [Toggle(MASK)] _MASK ("Texture Blue channel is Mask", Float) = 0
    15.         [Toggle(DEBUGUV)] _DEBUGUV ("Debug Texture Coordinates", Float) = 0
    16. }
    17.  
    18. SubShader {
    19.         Tags {"Queue" = "Transparent" "IgnoreProjector" = "True"}
    20.         Lighting Off
    21.         Fog { Mode Off }
    22.         ZWrite Off
    23.         LOD 200
    24.    
    25.         // See http://docs.unity3d.com/Manual/SL-GrabPass.html
    26.         GrabPass { "_GrabTexture" }
    27.  
    28.     Pass {
    29.         CGPROGRAM
    30.             //#pragma target 3.0
    31.             #pragma vertex vert
    32.             #pragma fragment frag
    33.             #pragma shader_feature MASK
    34.             #pragma shader_feature DEBUGUV
    35.             #include "UnityCG.cginc"
    36.  
    37.             // _MainTex is our distortion texture and
    38.             // should use "Bypass sRGB Sampling" import setting.
    39.             sampler2D _MainTex;
    40.             float4 _MainTex_ST; // texture tiling and offset
    41.        
    42.             // _GrabTexture contains the contents of the screen
    43.             // where the object is about to be drawn.
    44.             sampler2D _GrabTexture;
    45.        
    46.             // x=horizontal intensity, y=vertical intensity
    47.             // z=horizontal scrolling speed, w=vertical scrolling speed
    48.             float4 _IntensityAndScrolling;
    49.                
    50.             struct appdata_t {
    51.                 float4 vertex  : POSITION;
    52.                 half2 texcoord : TEXCOORD0;
    53.             };
    54.  
    55.             struct v2f {
    56.                 float4 vertex  : SV_POSITION;
    57.                 half2 texcoord : TEXCOORD0;
    58.                 half2 screenuv : TEXCOORD1;
    59.             #if MASK
    60.                 half2 maskuv   : TEXCOORD2;
    61.             #endif
    62.             };
    63.        
    64.             v2f vert (appdata_t v)
    65.             {
    66.                 v2f o;
    67.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    68.            
    69.                 o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); // Apply texture tiling and offset.
    70.                 o.texcoord += _Time.gg * _IntensityAndScrolling.zw; // Apply texture scrolling.
    71.  
    72.             #if MASK
    73.                 // We don't scroll this texture lookup, because we want the mask to be static.
    74.                 o.maskuv = v.texcoord;
    75.             #endif
    76.                            
    77.                 half4 screenpos = ComputeGrabScreenPos(o.vertex);
    78.                 o.screenuv = screenpos.xy / screenpos.w;
    79.                 return o;
    80.             }
    81.                
    82.             fixed4 frag (v2f i) : COLOR
    83.             {      
    84.                 half2 distort = tex2D(_MainTex, i.texcoord).xy;
    85.            
    86.                 // distort*2-1 transforms range from 0..1 to -1..1.
    87.                 // negative values move to the left, positive to the right.
    88.                 half2 offset = (distort.xy * 2 - 1) * _IntensityAndScrolling.xy;
    89.                        
    90.             #if MASK
    91.                 // _MainTex stores in the blue channel the mask.
    92.                 // The mask intensity represents how strong the distortion should be.
    93.                 // black=no distortion, white=full distortion
    94.                 half  mask = tex2D(_MainTex, i.maskuv).b;          
    95.                 offset *= mask;
    96.             #endif                      
    97.                                                                            
    98.                 // get screen space position of current pixel
    99.                 half2 uv = i.screenuv + offset;
    100.                 half4 color = tex2D(_GrabTexture, uv);
    101.                 UNITY_OPAQUE_ALPHA(color.a);
    102.            
    103.            
    104.             #if DEBUGUV
    105.                 color.rg = uv;
    106.                 color.b = 0;
    107.             #endif
    108.            
    109.  
    110.                 return color;
    111.             }
    112.         ENDCG
    113.     }
    114. }
    115. }
    116.  

    Code (CSharp):
    1. // This source code is NOT a full fledged distortion solution.
    2. // It's just an example and hopefully proves useful for someone.
    3. //
    4. // I'm not sure if Unity Pro is required due to the usage of "GrabPass".
    5. Shader "Custom/DistortionExample" {
    6.     Properties {
    7.         _MainTex ("Base (RGB)", 2D) = "white" {}
    8.         _IntensityAndScrolling ("Intensity (XY), Scrolling (ZW)", Vector) = (0.1,0.1,1,1)
    9.     }
    10.     SubShader {
    11.         Tags {"Queue" = "Transparent" "IgnoreProjector" = "True"}
    12.         Lighting Off
    13.         LOD 200
    14.  
    15.         // See http://docs.unity3d.com/Manual/SL-GrabPass.html
    16.         GrabPass { "_GrabTexture" }
    17.  
    18.         CGPROGRAM
    19.         #pragma surface surf Lambert
    20.  
    21.         sampler2D _MainTex;
    22.         sampler2D _GrabTexture;
    23.  
    24.         // x=horizontal intensity, y=vertical intensity
    25.         // z=horizontal scrolling speed, w=vertical scrolling speed
    26.         float4 _IntensityAndScrolling;
    27.  
    28.         struct Input
    29.         {
    30.             float2 uv_MainTex;
    31.             float4 screenPos;
    32.         };
    33.  
    34.         void surf (Input IN, inout SurfaceOutput o)
    35.         {
    36.             // get screen space position of current pixel
    37.             half2 screenUV = IN.screenPos.xy / IN.screenPos.w;
    38.         #if UNITY_UV_STARTS_AT_TOP
    39.             screenUV.y = 1-screenUV.y;
    40.         #endif
    41.  
    42.             // _MainTex should use "Bypass sRGB Sampling" import setting.
    43.             // d.x = horizontal offset 0..1
    44.             // d.y = vertical offset 0..1
    45.             float4 d = tex2D (_MainTex, IN.uv_MainTex+_Time.gg*_IntensityAndScrolling.zw);
    46.  
    47.             // d.x*2-1 transforms range from 0..1 to -1..1.
    48.             // negative values move to the left, positive to the right.
    49.             screenUV.x += (d.x*2-1) * _IntensityAndScrolling.x;
    50.             screenUV.y += (d.y*2-1) * _IntensityAndScrolling.y;
    51.  
    52.             half4 c = tex2D (_GrabTexture, screenUV);
    53.             o.Emission = c.rgb;
    54.             o.Alpha = 1;
    55.         }
    56.         ENDCG
    57.     }
    58.     FallBack "Diffuse"
    59. }
    60.  

    You can download the Unity project of this example at:
    http://www.console-dev.de/bin/UnityGrabPassDistortion.zip

    EDIT, April 15th 2017: Package updated to allow to tint distortion areas. Project uses Unity 5.4.

    EDIT, September 18th 2015: Package updated with a couple of more features, such as distance fade, culling mode and a particle shader. The package also contains examples that show what causes artifacts/problems with the shaders or perhaps distortion effects in general.
     
    Last edited: Apr 15, 2017
    scarletsnake likes this.
  5. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
    Thanks Peter, you're a legend :D
     
  6. Unreal-Vision

    Unreal-Vision

    Joined:
    May 6, 2013
    Posts:
    58
    Hi Peter,

    Thanks for the shader :)

    Since Unity Grab Pass would be not so cheap about performance, you know any trick without grabpass?

    Thanks,
     
  7. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I believe it depends on what kind of effect you try to achieve, I don't think there is a generic recipe.

    If you try to get things fast, you often end up faking in very creative ways that will just work in specific places. Thinking about the water refraction in Super Mario Galaxy:
    See http://www.codersnotes.com/graphics/mario-refraction for the entire text.
     
  8. zuizuimei

    zuizuimei

    Joined:
    Aug 15, 2013
    Posts:
    16
    I found problem in our project under unity3d 5.2. the DistortionPlane_Masking move with the screen size. it is very werid. when i import that to one new probject, still under unity3d 5.2, it is okay. you can see my screenshots.
     

    Attached Files:

  9. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I tried to reproduce the problem, but it does not occur over here. I uploaded a new version (couple of new features and more examples) a minute ago (see post above for the link), you could give it a try if it changes anything for you (I don't think it will though).
     
  10. zuizuimei

    zuizuimei

    Joined:
    Aug 15, 2013
    Posts:
    16
    Thank you for your kindness, i know how to reproduce that. the problem just occurs after i switch to android platform. 100% occurs. i don't know if it is related to unity3d version or some api. hope you can help me about that.
     
  11. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I was able to reproduce it now as well. It's a new problem they introduced with Unity 5.2, it works well in Unity 5.1 though.

    I submitted a bug-report to Unity:
    (Case 728833) Regression: GrabPass offsets when resizing the screen

    I'll leave a note here when I get a response from them.
     
  12. zuizuimei

    zuizuimei

    Joined:
    Aug 15, 2013
    Posts:
    16
    Thank you. :)
     
  13. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Unity just replied to the bug-report with:
    The next patch release would be Unity 5.2.0p2. If they stick to their patch release plan, it could be available around September 23rd.
     
    Last edited: Sep 20, 2015
  14. CF-Games

    CF-Games

    Joined:
    Jun 2, 2013
    Posts:
    134
    Hi Peter and thanks for the shader. I'm however having some problems with the mask not working properly. Even with the mask on, it still looks like the first example where the edges are visible instead of it being a smooth transition. It works fine when I open your project as is, but when I import your shaders and use it in my existing project, the mask doesn't seem to work properly. It use to work fine in 5.1, but I started having this problem when I upgraded to 5.2. Is there something special I have to set in my project settings?

    EDIT: Installed 5.2.1 which came out today and it seems to have fixed the issue.
     
    Last edited: Sep 23, 2015
  15. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
    Original reply really good solution for waves. Eventually I found an example of what I was after here: http://haxeflixel.com/demos/FlxWaveSprite/



    (a really simple horizontal wave)

    Any clues on how to do this? Maybe it just applies this effect to anything behind it, or even a culling selection based on layer? (needs to work with sprites and meshes)
     
  16. josessito

    josessito

    Joined:
    Feb 14, 2014
    Posts:
    57
    Hi Peter, I hate to ask more help from you, your shader was awesome, until I updated to unity 5.3. Now it is not working anymore. I tried to look into it by its waaay over my head. Maybe is a quick fix but I don't know where to begin. If you can take a look I would be really grateful, but I would understand if you can get to it.

    thanks!

    Edit: The shader looks fine in the editor window, but not in the game (there seems to be some sort of offset and the mask is not working, I believe)
     
  17. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I tested a windows standalone build but it works just fine here, proper offset and mask is working too. If you can throw together an example, where it's not working and send me the project, I can take a look at it.
     
  18. josessito

    josessito

    Joined:
    Feb 14, 2014
    Posts:
    57
    Hi Peter, I did a few test and the problem was in my camera. I switch off hdr and everything is working now...
    Thanks again!
     
  19. mitsoswu

    mitsoswu

    Joined:
    Dec 5, 2015
    Posts:
    6
    Hello Peter !!! ;)

    Is it posible to extract this shader from unity5 and use it in a "direct x 9" game?
    I wanna use this effect in my engine exhaust.to make heat distortion.

    If yes, which files do i need to extract ... and what needs to be done then, to combine them?
     
  20. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    If you downloaded the provided zip archive already, you can find the relevant or interesting part in "Assets/GrabPassDistortion/GrabPassDistortion.cginc".
     
  21. mitsoswu

    mitsoswu

    Joined:
    Dec 5, 2015
    Posts:
    6
    Yes Peter, i did download the files, thank you man !! :D

    So, you mean that i only need, this GrabPassDistortion.cginc file?
    Thats all?..
    You know, this game i'm talking about mostly uses bmp textures, for example: to create smoke effect particles.
    As far as i've seen, this "GrabPass" fiĺe, is a text file....... Right? I did right click with my mouse and i opened it with wordpad and there was text.
    You think i should try as it is first?
    (Sorry for my noobish questions man, but i am very new to this.)
     
    Last edited: Dec 18, 2015
  22. mitsoswu

    mitsoswu

    Joined:
    Dec 5, 2015
    Posts:
    6
    :( that didn't work out yet..... but i am trying to find my way, on this .....

    ..hope someone would help me some day... would realy appreciate it .
    thanks for that package anyway Peter.
     
    Last edited: Dec 23, 2015
  23. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Shaders in the provided package are specifically created for Unity 5. They make use of features that are not supported in Unity 4, such as "shader_feature".

    All files under the "Assets/GrabPassDistortion/" directory are relevant, but what I tried to say is that GrabPassDistortion.cginc contains the interesting shader source code. If you want to use it outside Unity 5, you could look at this file to figure out what it's doing and try to back-port it to Unity 4 or rewrite it for another engine.

    Hope it helps.
     
  24. mitsoswu

    mitsoswu

    Joined:
    Dec 5, 2015
    Posts:
    6
    Oh... i see... yes i saw that page.

    Yes the truth is that i want to use it in a simulator, (not in unity5), that works in "directx 9"
    and most of the effects there, are using bmp textures to represent, for example: a smoke effect. And a wordpad file, with the parameters for that particular effect.

    (plus the fact that i don't know S*** about coding) .... LOL :p
    i just started to read some xml tutorials and some C++

    thank you Peter ..... i'll see what i can do then

    Dimitri.
     
  25. Bamboy

    Bamboy

    Joined:
    Sep 4, 2012
    Posts:
    64
    This is very useful, Peter. Are we allowed to use this for commercial purposes?
     
  26. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Sure!
     
  27. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    When we use grabpass to make distortion shader,it goes well on windows edtior and android devices,but it makes the whole screen black on ios platform.Any one has some insight about this?
     
  28. DARKHAWX

    DARKHAWX

    Joined:
    Apr 15, 2017
    Posts:
    15
    Hi Peter,

    Just a quick question, in your example the distortion affect changes over time, but when I used the script you provided it doesn't change over time. I noticed there were no references to _Time at all in the code and I'm not sure where to add them. Do you know what to do?

    Another thing, is it possible to give the distortion effect a color? As in everything being distorted get a slight shade of blue?
     
  29. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    The animation is entirely done in shader code, there is no C# code involved. If you open GrabPassDistortion.cginc you should find the following line in the vertex shader:
    Code (CSharp):
    1. o.texcoord.xy += _Time.gg * _IntensityAndScrolling.zw; // Apply texture scrolling.
    This line is responsible scroll the texture coordinates and _Time.gg is an Unity built-in shader variable.

    I just tested the project with Unity 5.4 and it does animate the distortion here. Perhaps you use a different Unity version? Another reason could be that you didn't press Play, because if you're in edit mode only, you need to enable the Animated Materials option in Unity's Scene View, which tells Unity whether to advance the _Time.gg variable while the game is not playing.


    I updated the example to be able to tint the distortion. See this post for the download link (it's the same link as before though). I hope that's what you're looking for.
     
  30. majstudio

    majstudio

    Joined:
    Feb 11, 2016
    Posts:
    19
    Hey @Peter77 thank you so much for this easy to use distorsion shader. I'm really happy to use it in my current game project. Works very well and the FX iwanted s perfect !
    I'm using it with 2D sprites and there is a slight problem regarding it. When I use it on 2 objects at same time (for example 2 sprites) and the Shader distorsion texture is overlaping another distorsion texture, there is ugly cut line where the 2 textures intersects and I'm wondering if it is possible to make them disappear. upload_2017-5-4_16-21-18.png

    I saw that has to do with the Sprite Sorting layer itself and I need to tweak it to a value that is under the first distorsion rendered, but when there are 3 objects things get complicated and don't work out.

    upload_2017-5-4_16-23-11.png

    Have you any solution to this ? I would appreciate it alot.
    Thank you for your support !
     
  31. majstudio

    majstudio

    Joined:
    Feb 11, 2016
    Posts:
    19
    @Peter77 Oh, sorry. I'm dumb, I didn't see the new shader that works with Layers. Thank you so much, sorry for any annoyance !

    Is it taking a huge performance cost for fewer number or layers, or it's fine with only max 5 distorsion at screen at same time ?
     
  32. ctek

    ctek

    Joined:
    Sep 5, 2017
    Posts:
    3
    Thanks for the shader, i am trying to test this but cannot seem to see it in the camera view, it does show however in the scene view and seems to do what i would like but do not understand why it behaves this way. (Target platform is Android)

    EDIT : Seems playing with the Distance Fade values fixed it , i leave this here just in case someone else has this issue.
     
    Last edited: Dec 7, 2017
  33. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    What Unity version do you use?

    EDIT: OK, I just checked the example. The reason why you probably don't see anything in the "Game View" other than a text saying "Press PLAY and switch to Scene View" is because I didn't implement functionality to move the camera around in playmode.

    If that's not what you meant, a step-by-step list how to reproduce the issue would be appreciated in order to help.
     
    Last edited: Dec 7, 2017
  34. BMM7

    BMM7

    Joined:
    Sep 20, 2017
    Posts:
    54
    How can I use this effect in a 2D project?
    Would I have to modify the Shader only?