Search Unity

Unity Standard Water (wave geometry + realtime reflections)

Discussion in 'Shaders' started by Gooren, May 2, 2017.

  1. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    Hi,

    I used "FX/Water" shader and "Water" script combination from Unity Standard Assets. I chose the 'Reflective' mode in the "Water" component and the results were great. It looks nice and even performs great on my Galaxy S4. So I have decided to add just a little bonus feature to make it look even better - somewhat bigger waves by modifying 'vert' function in the "FX/Water" shader.
    It is almost perfect - except for two minor (probably connected) issues.
    Both issues are illustrated in this screenshot.
    Issue #1 - Indicated by the red arrow. Near top of the ascended wave we can observe a "seam"/hole. I guess that is here because nothing can be projected from below the terrain, because it is not two-sided? How to solve this?
    Issue #2 - Reflections are being presented by a texture that is projected on the water surface in a perfectly flat manner. Waves do not affect reflections at all, the reflections behave as the water stands completely still. I have no idea how to solve this.

    Full shader source code (note the 'displacement' stuff in the 'vert' function):
    Code (CSharp):
    1. Shader "FX/Water" {
    2. Properties {
    3.     _WaveScale ("Wave scale", Range (0.02,0.15)) = 0.063
    4.     _SinAmplitude ("Sin Amplitude", Range (0.0,10.0)) = 1
    5.     _SinFrequency ("Sin Frequency", Range (0.0,10.0)) = 1
    6.     _SinPhase ("Sin Phase", Range (0.0,10.0)) = 1
    7.     _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.44
    8.     _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.40
    9.     _RefrColor ("Refraction color", COLOR)  = ( .34, .85, .92, 1)
    10.     [NoScaleOffset] _Fresnel ("Fresnel (A) ", 2D) = "gray" {}
    11.     [NoScaleOffset] _BumpMap ("Normalmap ", 2D) = "bump" {}
    12.     WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (19,9,-16,-7)
    13.     [NoScaleOffset] _ReflectiveColor ("Reflective color (RGB) fresnel (A) ", 2D) = "" {}
    14.     _HorizonColor ("Simple water horizon color", COLOR)  = ( .172, .463, .435, 1)
    15.     [HideInInspector] _ReflectionTex ("Internal Reflection", 2D) = "" {}
    16.     [HideInInspector] _RefractionTex ("Internal Refraction", 2D) = "" {}
    17. }
    18.  
    19.  
    20. // -----------------------------------------------------------
    21. // Fragment program cards
    22.  
    23.  
    24. Subshader {
    25.     Tags { "WaterMode"="Refractive" "RenderType"="Opaque" }
    26.     Pass {
    27. CGPROGRAM
    28. #pragma vertex vert
    29. #pragma fragment frag
    30. #pragma multi_compile_fog
    31. #pragma multi_compile WATER_REFRACTIVE WATER_REFLECTIVE WATER_SIMPLE
    32.  
    33. #if defined (WATER_REFLECTIVE) || defined (WATER_REFRACTIVE)
    34. #define HAS_REFLECTION 1
    35. #endif
    36. #if defined (WATER_REFRACTIVE)
    37. #define HAS_REFRACTION 1
    38. #endif
    39.  
    40.  
    41. #include "UnityCG.cginc"
    42.  
    43. uniform float4 _WaveScale4;
    44. uniform float4 _WaveOffset;
    45.  
    46. uniform float _SinAmplitude;
    47. uniform float _SinFrequency;
    48. uniform float _SinPhase;
    49.  
    50. #if HAS_REFLECTION
    51. uniform float _ReflDistort;
    52. #endif
    53. #if HAS_REFRACTION
    54. uniform float _RefrDistort;
    55. #endif
    56.  
    57. struct appdata {
    58.     float4 vertex : POSITION;
    59.     float3 normal : NORMAL;
    60. };
    61.  
    62. struct v2f {
    63.     float4 pos : SV_POSITION;
    64.     #if defined(HAS_REFLECTION) || defined(HAS_REFRACTION)
    65.         float4 ref : TEXCOORD0;
    66.         float2 bumpuv0 : TEXCOORD1;
    67.         float2 bumpuv1 : TEXCOORD2;
    68.         float3 viewDir : TEXCOORD3;
    69.     #else
    70.         float2 bumpuv0 : TEXCOORD0;
    71.         float2 bumpuv1 : TEXCOORD1;
    72.         float3 viewDir : TEXCOORD2;
    73.     #endif
    74.     UNITY_FOG_COORDS(4)
    75. };
    76.  
    77. v2f vert(appdata v)
    78. {
    79.     v2f o;
    80.  
    81.     float displacement = sin (v.vertex.x + _Time.y * _SinFrequency + _SinPhase) * _SinAmplitude;
    82.     v.vertex.y += displacement;
    83.  
    84.     o.pos = UnityObjectToClipPos (v.vertex);
    85.  
    86.     // scroll bump waves
    87.     float4 temp;
    88.     float4 wpos = mul (unity_ObjectToWorld, v.vertex);
    89.     temp.xyzw = wpos.xzxz * _WaveScale4 + _WaveOffset;
    90.     o.bumpuv0 = temp.xy;
    91.     o.bumpuv1 = temp.wz;
    92.  
    93.     // object space view direction (will normalize per pixel)
    94.     o.viewDir.xzy = WorldSpaceViewDir(v.vertex);
    95.  
    96.     #if defined(HAS_REFLECTION) || defined(HAS_REFRACTION)
    97.     o.ref = ComputeScreenPos(o.pos);
    98.     #endif
    99.  
    100.     UNITY_TRANSFER_FOG(o,o.pos);
    101.     return o;
    102. }
    103.  
    104. #if defined (WATER_REFLECTIVE) || defined (WATER_REFRACTIVE)
    105. sampler2D _ReflectionTex;
    106. #endif
    107. #if defined (WATER_REFLECTIVE) || defined (WATER_SIMPLE)
    108. sampler2D _ReflectiveColor;
    109. #endif
    110. #if defined (WATER_REFRACTIVE)
    111. sampler2D _Fresnel;
    112. sampler2D _RefractionTex;
    113. uniform float4 _RefrColor;
    114. #endif
    115. #if defined (WATER_SIMPLE)
    116. uniform float4 _HorizonColor;
    117. #endif
    118. sampler2D _BumpMap;
    119.  
    120. half4 frag( v2f i ) : SV_Target
    121. {
    122.     i.viewDir = normalize(i.viewDir);
    123.  
    124.     // combine two scrolling bumpmaps into one
    125.     half3 bump1 = UnpackNormal(tex2D( _BumpMap, i.bumpuv0 )).rgb;
    126.     half3 bump2 = UnpackNormal(tex2D( _BumpMap, i.bumpuv1 )).rgb;
    127.     half3 bump = (bump1 + bump2) * 0.5;
    128.  
    129.     // fresnel factor
    130.     half fresnelFac = dot( i.viewDir, bump );
    131.  
    132.     // perturb reflection/refraction UVs by bumpmap, and lookup colors
    133.  
    134.     #if HAS_REFLECTION
    135.     float4 uv1 = i.ref; uv1.xy += bump * _ReflDistort;
    136.     half4 refl = tex2Dproj( _ReflectionTex, UNITY_PROJ_COORD(uv1) );
    137.     #endif
    138.     #if HAS_REFRACTION
    139.     float4 uv2 = i.ref; uv2.xy -= bump * _RefrDistort;
    140.     half4 refr = tex2Dproj( _RefractionTex, UNITY_PROJ_COORD(uv2) ) * _RefrColor;
    141.     #endif
    142.  
    143.     // final color is between refracted and reflected based on fresnel
    144.     half4 color;
    145.  
    146.     #if defined(WATER_REFRACTIVE)
    147.     half fresnel = UNITY_SAMPLE_1CHANNEL( _Fresnel, float2(fresnelFac,fresnelFac) );
    148.     color = lerp( refr, refl, fresnel );
    149.     #endif
    150.  
    151.     #if defined(WATER_REFLECTIVE)
    152.     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
    153.     color.rgb = lerp( water.rgb, refl.rgb, water.a );
    154.     color.a = refl.a * water.a;
    155.     #endif
    156.  
    157.     #if defined(WATER_SIMPLE)
    158.     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
    159.     color.rgb = lerp( water.rgb, _HorizonColor.rgb, water.a );
    160.     color.a = _HorizonColor.a;
    161.     #endif
    162.  
    163.     UNITY_APPLY_FOG(i.fogCoord, color);
    164.     return color;
    165. }
    166. ENDCG
    167.  
    168.     }
    169. }
    170.  
    171. }
    172.  
    EDIT: Example reflection texture which helps with illustrating the Issue #1 here.

    I will be glad for any suggestions,
    Thanks,
    Stepan
     
    Last edited: May 3, 2017