Search Unity

Considering depth on a distortion/ refraction shader?

Discussion in 'Shaders' started by Botaurus, Jan 17, 2016.

  1. Botaurus

    Botaurus

    Joined:
    Feb 20, 2013
    Posts:
    81
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    This might help:
    http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter19.html

    Alternatively you can sampling the _CameraDepthTexture and compare it to the fragment depth and reject any sample that's closer to the camera in a similar fashion. Look at particle shaders for an example of getting the current fragment depth as well as sampling the depth buffer. The camera will need to be creating a depth buffer for this to work. This can be enabling by turning on soft particles in the quality settings, using a directional light with shadows, or a script that enables the depth texture on your camera.

    Yet another option is to render the scene again using a special camera setup that only renders the scene past the plane. The mirror example here is similar, but you'd need a projection matrix that isn't flipped. http://wiki.unity3d.com/index.php/MirrorReflection4
    The comment in the script on that page suggests that you should be able to find the relevant code in one of the standard assets packages along side the water shader.
     
  3. Botaurus

    Botaurus

    Joined:
    Feb 20, 2013
    Posts:
    81
    Thanks! Ill try out multiple cameras. I suspected thats what I needed to do, but I didnt want to be kicking myself if there was a simple tag I was missing.
     
  4. Botaurus

    Botaurus

    Joined:
    Feb 20, 2013
    Posts:
    81
    Ok, got it working. Figure I'd post my results here. Its a pixel perfect distortion sprite shader.
    heres what it looks like:

    https://gfycat.com/EarnestBruisedAmericanbittern

    You duplicate the scene camera and render it to a Render Texture with the same resolution as your pixel screen. Use the duplicated camera to selectively choose what gets distorted. The distortion map should be red on top, green on bottom, and blue to the right. If you reverse that, it will pinch. The pixel size is your 1/ your final resolution. Im using a square resolution so you'd have to modify if you have a rectangular screen. You can use the screen padding if you are getting clamped edges.

    Code (CSharp):
    1. Shader "Sprites/Refraction" {
    2. Properties {
    3.     _MainTex ("Sprite Texture", 2D) = "white" {}
    4.     _Refraction ("Refraction", Range (0.00, 100.0)) = .1
    5.     _DistortTex ("Distortion Map (RGB)", 2D) = "white" {}
    6.     _RefractionLayer ("Refraction Render Texture (RGB)", 2D) = "white" {}
    7.     _ScreenPadding ("Screen Padding", Range(0.00, 0.5)) = .1
    8.     _PixelSize("Pixel Size", float) = 0.004166
    9. }
    10.  
    11. SubShader {
    12. Tags
    13.         {
    14.             "Queue"="Transparent"
    15.             "IgnoreProjector"="True"
    16.             "RenderType"="Transparent"
    17.             "PreviewType"="Plane"
    18.             "CanUseSpriteAtlas"="True"
    19.         }
    20.         Cull Off
    21.         Lighting Off
    22.         ZWrite Off
    23.         Blend One OneMinusSrcAlpha
    24.  
    25. CGPROGRAM
    26. #pragma surface surf NoLighting keepalpha
    27. #pragma vertex vert
    28.  
    29. fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, fixed atten){
    30.         fixed4 c;
    31.         c.rgb = s.Albedo;
    32.         c.a = s.Alpha;
    33.         return c;
    34.   }
    35.  
    36. sampler2D _DistortTex;
    37. sampler2D _RefractionLayer;
    38. sampler2D _MainTex;
    39.  
    40. float _Refraction;
    41. float _ScreenPadding;
    42. float _PixelSize;
    43.  
    44. struct Input {
    45.     float2 uv_DistortTex;
    46.     float2 uv_MainTex;
    47.     fixed4 color;
    48.     float3 worldRefl;
    49.     float4 screenPos;
    50.     INTERNAL_DATA
    51. };
    52.  
    53. void vert (inout appdata_full v, out Input o) {
    54.   UNITY_INITIALIZE_OUTPUT(Input,o);
    55.   o.color = v.color;
    56. }
    57.  
    58. void surf (Input IN, inout SurfaceOutput o) {
    59.     fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    60.     float3 distort = tex2D(_DistortTex, IN.uv_DistortTex).rgb;
    61.     distort = (distort*float3(1.0, 1.0, 2.0)) - float3(0.0, 0.0, 1.0);
    62.     distort = distort*_Refraction;
    63.     float2 offset = float2(distort.b, distort.r-distort.g);
    64.     offset = round(offset)*float2(_PixelSize, _PixelSize);
    65.     IN.screenPos.xy = IN.screenPos.xy*float2(1-(_ScreenPadding+_ScreenPadding), 1-(_ScreenPadding+_ScreenPadding));
    66.     IN.screenPos.xy = IN.screenPos.xy+float2(_ScreenPadding, _ScreenPadding);
    67.     IN.screenPos.xy = offset + IN.screenPos.xy;
    68.     float4 refrColor = tex2Dproj(_RefractionLayer, IN.screenPos);
    69.  
    70.     o.Emission = refrColor.rgb * c.a;
    71.      o.Alpha = c.a;
    72. }
    73. ENDCG
    74. }
    75. Fallback "Transparent/VertexLit"
    76. }
    77.  
     
  5. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Open the Water4 advanced shader that came with standard packages, there's a better sample in there to do depth differences for distortion masking.