Search Unity

Need fresnel in this shader, but not enough interpolators :( Please help.

Discussion in 'Shaders' started by Hjeldnes, Mar 16, 2014.

  1. Hjeldnes

    Hjeldnes

    Joined:
    Jul 22, 2012
    Posts:
    116
    Ok, so I have made a fairly lightweight river/water shader.
    I want this to be affected by lights, so I would like to use surfaces shaders for this.

    It looks pretty good now, but if I want proper depth calculation, then I can't have the viewDir inside the Input struct.

    Without the viewdir, I can't get fresnel. I tried transferring a per vertex fresnelfactor, but I run out of interpolators. There is not even room for a single float. Surface shaders are incredibly limiting because of this, and I wonder if there is a way calculating viewDir inside the pixel shader.

    here's the shader:

    Code (csharp):
    1. Shader "Dreamfall/FX/Reflect River"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.         _SpecColor ("Specular Color", Color) = (0.5,0.5,0.5,1)
    7.         _ReflectColor ("Reflect Color", Color) = (0.5,0.5,0.5,1)
    8.         _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
    9.         _Fresnel("Specular Fresnel Exponent",Range(0,16)) = 1
    10.        
    11.         _MainTex ("Base (RGB) RefStrGloss (A)", 2D) = "white" {}
    12.         _BumpMap ("Normalmap", 2D) = "bump" {}
    13.         _Cube ("Reflection Cubemap", Cube) = "" { TexGen CubeReflect }
    14.         _ScrollSpeed ("Scroll Speed", Float) = 1.0
    15.         _WaterVisibility ("Water Visibility", Float) = 1.0
    16.         _DistortAmt ("Distort Amount", Float) = 0.1
    17.     }
    18.  
    19.     SubShader
    20.     {
    21.         GrabPass
    22.             {
    23.                 "_GrabTexture"
    24.                 Tags
    25.                 {
    26.                     "Queue"="Background"
    27.                 }      
    28.             }
    29.    
    30.         Tags { "RenderType"="Opaque" "Queue"="Geometry+999" }
    31.          
    32.         LOD 400
    33.         CGPROGRAM
    34.         #pragma surface surf Lambert
    35.         #pragma target 3.0
    36.        
    37.         sampler2D _MainTex;
    38.         sampler2D _BumpMap;
    39.         samplerCUBE _Cube;
    40.         sampler2D _CameraDepthTexture;
    41.         sampler2D _GrabTexture;
    42.        
    43.        
    44.         fixed4 _Color;
    45.         fixed4 _ReflectColor;
    46.         half _Shininess;
    47.         half _Fresnel;
    48.         half _ScrollSpeed;
    49.         half _WaterVisibility;
    50.         half _DistortAmt;
    51.        
    52.         struct Input
    53.         {
    54.             float2 uv_BumpMap;
    55.             float3 worldRefl;
    56.             float4 screenPos;
    57.             INTERNAL_DATA
    58.         };
    59.        
    60.         inline float Schlick2(float Rzero,float3 lightDir,float3 normal,float exponent)
    61.         {
    62.             return Rzero + (1 - Rzero) * pow((1 - dot(lightDir,normal)),exponent);
    63.         }
    64.         /*
    65.         void vert(inout appdata_full v, out Input data)
    66.         {
    67.             UNITY_INITIALIZE_OUTPUT(Input,data);
    68.             float3 vDir = ObjSpaceViewDir(v.vertex);
    69.             data.fresnelFact = Schlick2(0,normalize(vDir),v.normal,_Fresnel);;//1 - saturate(dot(v.normal, vDir));
    70.         }
    71.         */
    72.        
    73.        
    74.         void surf (Input IN, inout SurfaceOutput o)
    75.         {
    76.             float depth = LinearEyeDepth(tex2D(_CameraDepthTexture, IN.screenPos.xy / IN.screenPos.w).r) - IN.screenPos.z;
    77.             depth *= 1 / _WaterVisibility;
    78.          
    79.            
    80.             float2 uv1 = IN.uv_BumpMap.xy;
    81.             uv1.y = uv1.y +  _Time * _ScrollSpeed;
    82.             float2 uv2 = IN.uv_BumpMap.xy;
    83.             uv2.y = uv2.y +  _Time * _ScrollSpeed * 2;
    84.            
    85.             fixed4 tex = tex2D(_MainTex, uv1);
    86.             fixed4 c = tex * _Color;
    87.             o.Albedo = c.rgb;
    88.             o.Specular = _Shininess;
    89.             o.Gloss = tex.a;
    90.            
    91.            
    92.             float4 n1 =float4(UnpackNormal(tex2D(_BumpMap, uv1)).xyz, 1.0);
    93.             float4 n2 =float4(UnpackNormal(tex2D(_BumpMap, uv2 * 2)).xyz, 1.0);
    94.            
    95.             float4 n = (n1 + n2) * 0.5f;
    96.             o.Normal = n.xyz;
    97.             float4 distort = n * _DistortAmt;
    98.             float3 worldRefl  = WorldReflectionVector (IN, o.Normal);
    99.            
    100.             fixed4 reflcol = texCUBE (_Cube, worldRefl);
    101.             half fresnel =  1.0f;//Schlick2(0,normalize(vDir),o.Normal,_Fresnel);
    102.            
    103.            
    104.             float4 distortedUV = ((IN.screenPos.xy/IN.screenPos.w).xyxy) + distort;        
    105.             float4 screen = tex2D(_GrabTexture,distortedUV.xy);
    106.            
    107.             o.Albedo = lerp(c.rgb, screen.rgb, saturate(1-depth));
    108.             o.Emission = reflcol.rgb * tex.a * fresnel  * _ReflectColor + screen.rgb * saturate(1-depth);
    109.            
    110.            
    111.         }
    112.         ENDCG
    113.     }
    114.    
    115.     //FallBack "Reflective/Bumped Diffuse"
    116. }
    117.  

    Here's a screengrab. So, it looks quite okay, but it would be much better with a fresnel modification of the refleciton.
    $Screen Shot 2014-03-16 at 21.56.58.png
     
  2. Marco-Sperling

    Marco-Sperling

    Joined:
    Mar 5, 2012
    Posts:
    620
    You might be able to grab the view dir from one of Unity's builtin matrices. Not sure which one and if you need to transform the vector you pull out of that matrix into a specific space for your shader to work.
    That's one reason I've given up on using surface shaders - they have too much "magic stuff" happening in the background. They are nice for those generic shaders that ship with Unity. But as soon as you want to do some more sophisticated effects/shading you run into these issues.
     
  3. Hjeldnes

    Hjeldnes

    Joined:
    Jul 22, 2012
    Posts:
    116
    Yeah, I've looked a bit into the documentation, and it's a bit fuzzy. Also my math skills are not what they once were :p I guuess it could be possible to calculate worldspace pos from the depth buffer, and then get viewspace from worldcamera, and that worldpos.

    But yeah, the surface shaders drives me crazy..even if I remove something I know I won't need from the input struct, like uv's for the bumpmap, I still don't have enough interpolators for a single float, or even a color input. It does not make sense. :/