Search Unity

GrabPass distortion problem

Discussion in 'Shaders' started by Phantomx, Nov 23, 2013.

  1. Phantomx

    Phantomx

    Joined:
    Oct 30, 2012
    Posts:
    202
    Hi,
    I want to make a water shader and distort UV of what's behind the surface of the water.
    So far I did the grabPass and distort UV with a normalmap, but I have one problem.

    The border of the objects that are in front of the surface get distort too, like if the grabpass was taking not only what's on the back of the surface but what's in the front too.

    $distortion.jpg

    here's my code so far:

    Code (csharp):
    1.  
    2.  
    3. SubShader
    4. {
    5.         Tags { "Queue" = "Transparent" }
    6.  
    7.         GrabPass {"_GrabTexture"}
    8.  
    9.      
    10.         Pass {
    11.             Name "GrabOffset"
    12.             Cull Back
    13.             ZWrite Off
    14.             Blend Off
    15.            
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             #pragma fragmentoption ARB_precision_hint_fastest
    20.  
    21.             #include "UnityCG.cginc"
    22.  
    23.             sampler2D _GrabTexture;
    24.            
    25.             sampler2D _NormalMap;
    26.             float4 _NormalMap_ST;
    27.            
    28.             float _Distortion;
    29.             fixed4 _Color;
    30.            
    31.  
    32.             struct appdata {
    33.                 float4 vertex : POSITION;
    34.                 float2 texcoord : TEXCOORD0;
    35.             };
    36.            
    37.  
    38.             struct v2f {
    39.                 float4 pos : POSITION;
    40.                 float2 texcoord : TEXCOORD0;
    41.                 float4 GrabUV : TEXCOORD2;
    42.             };
    43.  
    44.             v2f vert (appdata v)
    45.             {
    46.                 v2f o;
    47.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    48.                 o.texcoord = TRANSFORM_TEX(v.texcoord, _NormalMap);
    49.  
    50.                 o.GrabUV = ComputeGrabScreenPos(o.pos);
    51.                
    52.                 return o;
    53.             }
    54.            
    55.  
    56.             fixed4 frag (v2f i) : COLOR
    57.             {
    58.            
    59.                 fixed3 bump = UnpackNormal(tex2D(_NormalMap, i.texcoord));
    60.                
    61.                 i.GrabUV.xy += bump * _Distortion;
    62.                
    63.                 fixed4 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.GrabUV));
    64.  
    65.                 return fixed4(refraction.rgb,1) * _Color;
    66.                
    67.             }
    68.             ENDCG
    69.         }  
    70.  
    71.  

    If someone can help me with that it would be appreciated!

    Thanks!
     
  2. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Code (csharp):
    1.     SubShader {
    2.  
    3.             Tags { "Queue" = "Transparent" }
    4.      
    5.             GrabPass {"_GrabTexture"}
    6.      
    7.          
    8.             Pass {
    9.                 Name "GrabOffset"
    10.                 Cull Back
    11.                 ZWrite Off
    12.                 Blend Off
    13.                
    14.                 CGPROGRAM
    15.                 #pragma vertex vert
    16.                 #pragma fragment frag
    17.                 #pragma fragmentoption ARB_precision_hint_fastest
    18.      
    19.                 #include "UnityCG.cginc"
    20.      
    21.                 sampler2D _GrabTexture;
    22.                
    23.                 sampler2D _NormalMap;
    24.                 float4 _NormalMap_ST;
    25.                
    26.                 float _Distortion;
    27.                 fixed4 _Color;
    28.                
    29.                 sampler2D _CameraDepthTexture;
    30.                
    31.                 struct appdata {
    32.                     float4 vertex : POSITION;
    33.                     float2 texcoord : TEXCOORD0;
    34.                 };
    35.                
    36.      
    37.                 struct v2f {
    38.                     float4 pos : POSITION;
    39.                     float2 texcoord : TEXCOORD0;
    40.                     float4 GrabUV : TEXCOORD2;
    41.                 };
    42.      
    43.                 v2f vert (appdata v)
    44.                 {
    45.                     v2f o;
    46.                     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    47.                     o.texcoord = TRANSFORM_TEX(v.texcoord, _NormalMap);
    48.      
    49.                     o.GrabUV = ComputeGrabScreenPos(o.pos);
    50.                    
    51.                     return o;
    52.                 }
    53.                
    54.      
    55.                 fixed4 frag (v2f i) : COLOR
    56.                 {
    57.                
    58.                     fixed4 bump = fixed4(UnpackNormal(tex2D(_NormalMap, i.texcoord)),0);
    59.                     bump = normalize(bump);
    60.                    
    61.                     fixed4 DistUV = i.GrabUV + (bump * _Distortion);
    62.                    
    63.                     fixed4 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(DistUV));
    64.                     fixed4 refractionN = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.GrabUV));
    65.      
    66.                     fixed refrFix = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(DistUV)));
    67.                      
    68.                      if(LinearEyeDepth(refrFix) < i.GrabUV.z)
    69.                          refraction = refractionN;
    70.                      
    71.                     return fixed4(refraction.rgb,1) * _Color;
    72.                    
    73.                 }
    74.                 ENDCG
    75.             }
    76.     }
    77.  
     
  3. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    I came across this thread with the exact same problem, however the solution posted by @rea doesn't seem to completely fix the issue for me. It does reduce the amount of distortion when an object is in front of the plane, however the object still seems to be influencing the surrounding pixels.

    I made sure my camera has

    Code (csharp):
    1. camera.depthTextureMode = DepthTextureMode.Depth;
    enabled and the depth texture seems correct when debug rendering it to the screen. I'm running on a Windows 8.1 machine with Unity 4.5.1f3 on an NVidia GTX770.

    At this point I'm pretty stuck. Any help would be great, thanks!
     
    Last edited: Jul 15, 2014
  4. Phantomx

    Phantomx

    Joined:
    Oct 30, 2012
    Posts:
    202
  5. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    Thanks for the quick reply Phantomx! I'll give that article a read. Here are some screenshots to better explain what I'm seeing. I was going for a heat haze effect using a 3D camera-facing plane in the world, as opposed to a post process.







    As you can see from the last image, the pillar is still affecting the plane (albeit less), even though the plane is always behind the pillar.
     
  6. Phantomx

    Phantomx

    Joined:
    Oct 30, 2012
    Posts:
    202
    I see, I must say in my case that it fixes it much better than this.I think the orientation of the plane has something to do with it, try an horizontal plane to see if it helps.
     
  7. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    Digging this thread up from the grave, but I wanted to report that the problem seems to have mostly fixed itself after six months of development changes...

    Not sure exactly what did it, but the biggest changes we made (in order of most likely) over the past couple months were:
    • Upgrading to Unity 4.6 (this did have other small side effects for our project so I wouldn't be surprised)
    • Disabling default AA and replacing with Unity's ImageEffect AA
    • Lots of game-specific camera code changes (ie, the distortion plane is now a distortion sphere with inward-facing normals that's childed to the camera with some custom rotation-restriction logic)
    • Upgrading my graphics card drivers, finding a new distortion normal map texture, tweaking the shader values, etc.

    (exaggerated normal map for demonstration purposes. some artifacts can still be seen when zoomed)
     
  8. TimNedvyga

    TimNedvyga

    Joined:
    May 18, 2015
    Posts:
    96
    Has anyone found a solution to this problem?
     
  9. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    246
    The solution proposed in the second post here works perfectly well, dont know whats youre problem other than that
     
  10. Iucounu

    Iucounu

    Joined:
    Oct 24, 2017
    Posts:
    19


    The solution in the second post doesn't work. While it removes most of refraction, it inevitably leaves ghost lines around borders. The cube on the screenshot is completely above the green plane with the refraction shader, and these artifacts are clearly visible.

    I'm looking for solution of this issue, too. I spent about two months trying every single refraction and distortion shader I found online (as well as trying to write my own solution), but all of them inevitably ended up with the "ghost lines" issue as seen in the picture...
     
  11. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Afaik that is how grabpass always work, if you don't want to deal with grabpass artifact you can use render texture with custom clipping plane (this is only work with planar shape)

    Oh just in case you guys having problem with unity 5.5+.
    Due unity using reverse z-buffer
    change this line
    Code (csharp):
    1.  
    2. if(LinearEyeDepth(refrFix) < i.GrabUV.z)
    3.  
    to this
    Code (csharp):
    1.  
    2.  if(LinearEyeDepth(refrFix) < i.GrabUV.w)
    3.  
     
    Last edited: Mar 16, 2018
  12. Iucounu

    Iucounu

    Joined:
    Oct 24, 2017
    Posts:
    19
    Tried right now. Doesn't make any difference. The same border issues.

    On my computer a lake with a render texture used for its surface to show refractions drops FPS to like 5-10, so it's not usable for any real applications. Grabpass refraction shader from above (or a similar one) produces around 40 FPS for the same scene (but with border refraction bugs).

    Since the shader correctly removes most of unwanted refractions above surface and leaves only very thin (but very annoying) artifacts around borders, maybe there is some solution on how to increase area around objects clearing unwanted refractions?
     
  13. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Depend on your GPU and how you setup your render texture.
    I use render texture for my water mostly, using the same shared refraction buffer
    upload_2018-3-23_14-55-9.png
    also there's an advantage of using RTT in my opinion,
    - i can use it on Opaque Shader, to receive shadow and SSR
    - can be downsampled
    - can be post processed before applied to the material, mostly i used blur to get murky water
     
  14. Iucounu

    Iucounu

    Joined:
    Oct 24, 2017
    Posts:
    19
    Of course it depends on GPU. Two times better GPU = two times better fps. Using grab pass instead of render textures = two times better fps. I can't install two times better GPU for every person playing my game, so I was hoping to go for the second route - which is using grab pass instead of render textures.

    Since there are only very thin outlines remaining, I suppose there is some kind of imprecision in calculations of pixels to be replaced with non-distorted versions. Maybe other people can provide further ideas for potential solutions. My own technical knowledge is not sufficient to even understand properly why this bug happens, unfortunately.
     
  15. jmarcos007

    jmarcos007

    Joined:
    Mar 2, 2017
    Posts:
    11
    This video shows how to solve the problem partially.