Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Pro water with 3 bump maps

Discussion in 'Shaders' started by Proto, Oct 28, 2008.

  1. Proto

    Proto

    Joined:
    Aug 20, 2007
    Posts:
    79
    This is a modification of the pro water shader that uses three shader bump maps instead of the standard two. Two of the shader bumps are scrolling wave bumps (same as the built-in pro shader) and the third shader bump is a static map that can be used for real time bump effects. I'm sure there are better ways to do this as this is my first attempt at shader mods, so feel free to comment.



    Code (csharp):
    1. Shader "FX/Water RT Scroll" {
    2. Properties {
    3.     _WaveScale ("Wave scale", Range (0.005,0.15)) = 0.063
    4.     _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.44
    5.     _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.40
    6.     _RefrColor ("Refraction color", COLOR)  = ( .34, .85, .92, 1)
    7.     _Fresnel ("Fresnel (A) ", 2D) = "gray" {}
    8.     _BumpMap ("Bumpmap (RGB) ", 2D) = "bump" {}
    9.     WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (19,9,-16,-7)
    10.     _ReflectiveColor ("Reflective color (RGB) fresnel (A) ", 2D) = "" {}
    11.     _ReflectiveColorCube ("Reflective color cube (RGB) fresnel (A)", Cube) = "" { TexGen CubeReflect }
    12.     _HorizonColor ("Simple water horizon color", COLOR)  = ( .172, .463, .435, 1)
    13.     _MainTex ("Fallback texture", 2D) = "" {}
    14.     _ReflectionTex ("Internal Reflection", 2D) = "" {}
    15.     _RefractionTex ("Internal Refraction", 2D) = "" {}
    16.     _RippleMap ("RippleMap (RGB) ", 2D) = "ripple" {}
    17.     RipplePosition ("Ripple (x,y offset; x,y scale)", Vector) = (0.5, 0.5, 0.05, 0.05)
    18. }
    19.  
    20.  
    21. // -----------------------------------------------------------
    22. // Fragment program cards
    23.  
    24.  
    25. Subshader {
    26.     Tags { "WaterMode"="Refractive" "RenderType"="Opaque" }
    27.     Pass {
    28. CGPROGRAM
    29. #pragma vertex vert
    30. #pragma fragment frag
    31. #pragma fragmentoption ARB_precision_hint_fastest
    32. #pragma fragmentoption ARB_fog_exp2
    33. #pragma multi_compile WATER_REFRACTIVE WATER_REFLECTIVE WATER_SIMPLE
    34.  
    35. #if defined WATER_REFLECTIVE || defined WATER_REFRACTIVE
    36. #define HAS_REFLECTION 1
    37. #endif
    38. #if defined WATER_REFRACTIVE
    39. #define HAS_REFRACTION 1
    40. #endif
    41.  
    42.  
    43. #include "UnityCG.cginc"
    44.  
    45. uniform float4 WaveSpeed;
    46. uniform float4 RipplePosition;
    47. uniform float _WaveScale;
    48.  
    49. #ifdef HAS_REFLECTION
    50. uniform float _ReflDistort;
    51. #endif
    52. #ifdef HAS_REFRACTION
    53. uniform float _RefrDistort;
    54. #endif
    55.  
    56. struct appdata {
    57.     float4 vertex : POSITION;
    58.     float3 normal : NORMAL;
    59. };
    60.  
    61. struct v2f {
    62.     V2F_POS_FOG;
    63.     #if defined HAS_REFLECTION || defined HAS_REFRACTION
    64.     float3 ref;
    65.     #endif
    66.     float2 bumpuv[2];
    67.     float2 rippleuv[1];
    68.     float3 viewDir;
    69. };
    70.  
    71. v2f vert(appdata v)
    72. {
    73.     v2f o;
    74.     PositionFog( v.vertex, o.pos, o.fog );
    75.    
    76.     // scroll bump waves
    77.     float4 temp;
    78.     temp.xyzw = (v.vertex.xzxz + _Time.x * WaveSpeed.xyzw) * _WaveScale;
    79.     o.bumpuv[0] = temp.xy * float2(.4, .45);
    80.     o.bumpuv[1] = temp.wz;
    81.     o.rippleuv[0] = v.vertex.xz * float2(RipplePosition.w, RipplePosition.z) + float2(RipplePosition.x, RipplePosition.y);
    82.    
    83.     // object space view direction (will normalize per pixel)
    84.     o.viewDir.xzy = ObjSpaceViewDir(v.vertex);
    85.    
    86.     #if defined HAS_REFLECTION || defined HAS_REFRACTION
    87.     // calculate the reflection vector
    88.     float3x4 mat = float3x4 (
    89.         0.5, 0, 0, 0.5,
    90.         0, 0.5 * _ProjectionParams.x, 0, 0.5,
    91.         0, 0, 0, 1
    92.     ); 
    93.     o.ref = mul (mat, o.pos);
    94.     #endif
    95.    
    96.     return o;
    97. }
    98.  
    99. #if defined WATER_REFLECTIVE || defined WATER_REFRACTIVE
    100. sampler2D _ReflectionTex;
    101. #endif
    102. #if defined WATER_REFLECTIVE || defined WATER_SIMPLE
    103. sampler2D _ReflectiveColor;
    104. #endif
    105. #if defined WATER_REFRACTIVE
    106. sampler2D _Fresnel;
    107. sampler2D _RefractionTex;
    108. uniform float4 _RefrColor;
    109. #endif
    110. #if defined WATER_SIMPLE
    111. uniform float4 _HorizonColor;
    112. #endif
    113. sampler2D _BumpMap;
    114. sampler2D _RippleMap;
    115.  
    116. half4 frag( v2f i ) : COLOR
    117. {
    118.     i.viewDir = normalize(i.viewDir);
    119.    
    120.     // combine two scrolling bumpmaps into one
    121.     half3 bump1 = tex2D( _BumpMap, i.bumpuv[0] ).rgb;
    122.     half3 bump2 = tex2D( _BumpMap, i.bumpuv[1] ).rgb;
    123.     half3 bump3 = tex2D( _RippleMap, i.rippleuv[0] ).rgb;
    124.     half3 bump = bump1 + bump2 + bump3 - 1.5;
    125.    
    126.     // fresnel factor
    127.     half fresnelFac = dot( i.viewDir, bump );
    128.    
    129.     // perturb reflection/refraction UVs by bumpmap, and lookup colors
    130.    
    131.     #ifdef HAS_REFLECTION
    132.     float3 uv1 = i.ref; uv1.xy += bump * _ReflDistort;
    133.     half4 refl = tex2Dproj( _ReflectionTex, uv1 );
    134.     #endif
    135.     #ifdef HAS_REFRACTION
    136.     float3 uv2 = i.ref; uv2.xy -= bump * _RefrDistort;
    137.     half4 refr = tex2Dproj( _RefractionTex, uv2 ) * _RefrColor;
    138.     #endif
    139.    
    140.     // final color is between refracted and reflected based on fresnel 
    141.     half4 color;
    142.    
    143.     #ifdef WATER_REFRACTIVE
    144.     half fresnel = tex2D( _Fresnel, float2(fresnelFac,fresnelFac) ).a;
    145.     color = lerp( refr, refl, fresnel );
    146.     #endif
    147.    
    148.     #ifdef WATER_REFLECTIVE
    149.     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
    150.     color.rgb = lerp( water.rgb, refl.rgb, water.a );
    151.     color.a = refl.a * water.a;
    152.     #endif
    153.    
    154.     #ifdef WATER_SIMPLE
    155.     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
    156.     color.rgb = lerp( water.rgb, _HorizonColor.rgb, water.a );
    157.     color.a = _HorizonColor.a;
    158.     #endif
    159.    
    160.     return color;
    161. }
    162. ENDCG
    163.  
    164.     }
    165. }
    166.  
    167.  
    168. // -----------------------------------------------------------
    169. // Radeon 9000 cards
    170.  
    171.  
    172. Subshader {
    173.     Tags { "WaterMode"="Reflective" "RenderType"="Opaque" }
    174.     Pass {
    175.    
    176. CGPROGRAM
    177. #pragma vertex vert
    178.  
    179. #include "UnityCG.cginc"
    180.  
    181. uniform float4 WaveSpeed;
    182. uniform float4 RipplePosition;
    183. uniform float _WaveScale;
    184. uniform float _ReflDistort;
    185.  
    186. struct appdata {
    187.     float4 vertex : POSITION;
    188.     float3 normal : NORMAL;
    189. };
    190.  
    191. struct v2f {
    192.     V2F_POS_FOG;
    193.     float2 bumpuv[2] : TEXCOORD0;
    194.     float3 viewDir : TEXCOORD2;
    195.     float4 ref : TEXCOORD3;
    196.     float2 rippleuv[1] : TEXCOORD4;
    197. };
    198.  
    199. v2f vert(appdata v)
    200. {
    201.     v2f o;
    202.     PositionFog( v.vertex, o.pos, o.fog );
    203.    
    204.     // scroll bump waves
    205.     float4 temp;
    206.     temp.xyzw = (v.vertex.xzxz + _Time.x * WaveSpeed.xyzw) * _WaveScale;
    207.     o.bumpuv[0] = temp.xy * float2(.4, .45);
    208.     o.bumpuv[1] = temp.wz;
    209.     o.rippleuv[0] = v.vertex.xz * float2(RipplePosition.w, RipplePosition.z) + float2(RipplePosition.x, RipplePosition.y);
    210.    
    211.     // object space view direction
    212.     o.viewDir.xzy = normalize( ObjSpaceViewDir(v.vertex) );
    213.    
    214.     // calculate the reflection vector
    215.     float4x4 mat = float4x4 (
    216.         .5, 0, 0,.5,
    217.          0,.5 * _ProjectionParams.x, 0,.5,
    218.          0, 0,.5,.5,
    219.          0, 0, 0, 1
    220.     ); 
    221.     o.ref = mul (mat, o.pos);
    222.    
    223.     return o;
    224. }
    225. ENDCG
    226.  
    227. Program "" {
    228. SubProgram {
    229.     Keywords { "WATER_REFLECTIVE" "WATER_REFRACTIVE" }
    230.     SetTexture [_BumpMap] { 2D }
    231.     SetTexture [_BumpMap] { 2D }
    232.     SetTexture [_RippleMap] { 2D }
    233.     SetTexture [_ReflectiveColor] { 2D }
    234.     SetTexture [_ReflectionTex] { 2D }
    235.     Local 0, ([_ReflDistort],0,0,0)
    236.  
    237. "!!ATIfs1.0
    238. StartConstants;
    239.     CONSTANT c0 = program.local[0];
    240. EndConstants;
    241.  
    242. StartPrelimPass;
    243.     PassTexCoord r3, t3.stq_dq; # reflection vector
    244.     SampleMap r0, t0.str;   # bump1
    245.     SampleMap r1, t1.str;   # bump2
    246.     PassTexCoord r2, t2.str;
    247.    
    248.     ADD r1.half, r0.bias, r1.bias;  # bump = bump1 + bump2 - 1
    249.     DOT3 r2, r1.2x, r2;             # fresnel: dot (bump, viewer-pos)
    250.     # add less offset because it's purely screenspace; big ones look bad
    251.     MAD r3.rg, r1, c0.r, r3;        # uv += bump * strength; add less because it's not perspective
    252. EndPass;
    253.  
    254. StartOutputPass;
    255.     SampleMap r3, r3.str;       # reflection color
    256.     SampleMap r2, r2.str;       # water color/fresnel
    257.  
    258.     LERP r0.rgb, r2.a, r3, r2;  # between water and reflected based on fresnel
    259.     MUL r0.a, r3.a, r2.a;
    260. EndPass;
    261. "
    262. }
    263. SubProgram {
    264.     Keywords { "WATER_SIMPLE" }
    265.     SetTexture [_BumpMap] { 2D }
    266.     SetTexture [_BumpMap] { 2D }
    267.     SetTexture [_RippleMap] { 2D }
    268.     SetTexture [_ReflectiveColor] { 2D }
    269.     Local 0, [_HorizonColor]
    270.  
    271. "!!ATIfs1.0
    272. StartConstants;
    273.     CONSTANT c0 = program.local[0];
    274. EndConstants;
    275.  
    276. StartPrelimPass;
    277.     SampleMap r0, t0.str;
    278.     SampleMap r1, t1.str;
    279.     PassTexCoord r2, t2.str;
    280.    
    281.     ADD r1, r0.bias, r1.bias;   # bump = bump1 + bump2 - 1
    282.     DOT3 r2, r1, r2;            # fresnel: dot (bump, viewer-pos)
    283. EndPass;
    284.  
    285. StartOutputPass;
    286.     SampleMap r2, r2.str;
    287.  
    288.     LERP r0.rgb, r2.a, c0, r2;  # fade in reflection
    289.     MOV r0.a, c0.a;
    290. EndPass;
    291. "
    292. }
    293. }
    294.     }
    295. }
    296.  
    297.  
    298. // -----------------------------------------------------------
    299. //  Old cards
    300.  
    301. // three texture, cubemaps
    302. Subshader {
    303.     Tags { "WaterMode"="Simple" "RenderType"="Opaque" }
    304.     Pass {
    305.         Color (0.5,0.5,0.5,0.5)
    306.         SetTexture [_MainTex] {
    307.             Matrix [_WaveMatrixLow]
    308.             combine texture * primary
    309.         }
    310.         SetTexture [_MainTex] {
    311.             Matrix [_WaveMatrixLow]
    312.             combine texture * primary + previous
    313.         }
    314.         SetTexture [_ReflectiveColorCube] {
    315.             combine texture +- previous, primary
    316.             Matrix [_Reflection]
    317.         }
    318.     }
    319. }
    320.  
    321. // dual texture, cubemaps
    322. Subshader {
    323.     Tags { "WaterMode"="Simple" "RenderType"="Opaque" }
    324.     Pass {
    325.         Color (0.5,0.5,0.5,0.5)
    326.         SetTexture [_MainTex] {
    327.             Matrix [_WaveMatrixLow]
    328.             combine texture
    329.         }
    330.         SetTexture [_ReflectiveColorCube] {
    331.             combine texture +- previous, primary
    332.             Matrix [_Reflection]
    333.         }
    334.     }
    335. }
    336.  
    337. // single texture
    338. Subshader {
    339.     Tags { "WaterMode"="Simple" "RenderType"="Opaque" }
    340.     Pass {
    341.         Color (0.5,0.5,0.5,0)
    342.         SetTexture [_MainTex] {
    343.             Matrix [_WaveMatrixLow]
    344.             combine texture, primary
    345.         }
    346.     }
    347. }
    348.  
    349.  
    350. }
    351.  
    The setup is a bit tricky so I've included an example project : (needs pro)
     

    Attached Files:

  2. bigkahuna

    bigkahuna

    Joined:
    Apr 30, 2006
    Posts:
    5,434
    Very interesting and educational, thank you for sharing this. I'm assuming you've seen Yoggy's "boat" demo?
     
  3. Proto

    Proto

    Joined:
    Aug 20, 2007
    Posts:
    79
    Yeah I couldn't get Yoggy's Boat demo working after 2.0, hence the rewrite. It occurred to me that it might be advantageous to do both the scrolling and the texture blending in the shader rather than in gameObjects, though exactly what (if any) efficiencies have been been gained I have no idea. This 3 bump shader remains largely untested, though I'm hoping it'll behave the same as the in-built pro water as it is essentially the same.

    That reminds me, if anyone has some older ATI cards I'd be interested to see how this degrades.
     
  4. bigkahuna

    bigkahuna

    Joined:
    Apr 30, 2006
    Posts:
    5,434
    I've got a working copy of it, just gave it a try in 2.1 and it works. Can't remember who fixed it or how I got it, but IIRC someone posted that they had fixed it some months back (before 2.1 was released). The project folder is 71 MB, so kind of big to post, but if you can't find it somewhere else let me know.
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Look at page 4 of that topic.

    --Eric
     
  6. Warp boy2

    Warp boy2

    Joined:
    Nov 12, 2010
    Posts:
    216
    ah well.. this is very old so nobody will se this anymore but.. i cant get it to work

    maybe is something wrong with the version im using but.. the water does not do the little waves when the cube moves arround
     
  7. Warp boy2

    Warp boy2

    Joined:
    Nov 12, 2010
    Posts:
    216
    oh.. i dont have pro.. thats problaby the reason