• API
• FAQ
• Tools
• Trends
• Archive
SHARE
TWEET

ensiferum888 Feb 23rd, 2014 87 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1.
2. //
3. // Fragment shader, Tiled Directional Flow
4. //
5. // (c) 2010 frans van hoesel, university of groningen
6. //
7. //
8. // this shader creates animated water by transforming normalmaps
9. // the scaling and rotation of the normalmaps is done per tile
10. // and is constant per tile. Each tile can have its own parameters
11. // for rotation, scaling, and speed of translation
12. // To hide the seams between the tiles, all seams have another tile
13. // centered over the seam. The opacity of the tiles decreases towards the
14. // edge of the tiles, so the edge isn't visible at all.
15. // Basically, all points have four tiles (A,B,C and D), mixed together
16. // (although at the edges the contribution of a tile to this mix is
17. // reduced to zero).
18. // The mixing of the tiles each with different parameters gives a nice
19. // animated look to the water. It is no longer just sliding in one direction, but
20. // appears to move more like real water.
21.
22. // The resulting sum of normalmaps, is used to calculate the refraction of the clouds
23. // in a cube map and can also be used for other nice effects. In this example the
24. // colormap of the material under water is distorted to fake some kind of refraction
25. // (for this example the water is a bit too transparent, but it shows this refraction
26. // better)
27.
28. // A flowmap determines in the red and green channel the normalized direction of the
29. // flow and in the blue channel wavelength.
30. // The alpha channel is used for the transparency of the water. Near the edge, the
31. // water becomes less deep and more transparent. Also near the edge, the waves tend
32. // to be smaller, so the same alpha channel also scales the height of the waves.
33. // Currently the wavelength is in its own channel (blue), but could be premultiplied
34. // to the red and green channels. This makes this channel available for changing the
35. // speed of the waves per tile.
36.
37.
38. // Further improvements
39. // Besides the obvious improvements mentioned in the code (such as premultiplying
40. // the direction of the waves with the scale, or moving the texscale multiplication
41. // to the texture coordinates), one could get rid of tiling in this code and pass it
42. // tiled geometry. This way the whole lookup of the flowmap (which is constant over
43. // each tile) could be moved to the vertexshader, removing the the construction of
44. // the flow rotation matrix. As this is done 4 times per pixel, it might give a big
45. // performance boost (one does need to pass on 4 constant matrices to the fragment
46. // shader, which will cost you a bit of performance).
47. //
48. //////////////////////////////////////////////////////////////////////////////////
49. //                     This software is Creditware:
50. //
51. // you can do whatever you want with this shader except claiming rights
52. // you may sell it, but you cannot prevent others from selling it, giving it away
53. // or use it as they please.
54. //
55. // Having said that, it would be nice if you gave me some credit for it, when you
56. // use it.
57. //
58. //                     Frans van Hoesel, (c) 2010
59. //////////////////////////////////////////////////////////////////////////////////
60.
61.
62. // movie at youtube: http://www.youtube.com/watch?v=TeSuNYvXAiA?hd=1 (in Germany this is blocked by youtube)
63. // making of at http://www.youtube.com/watch?v=wdcvPegJ1lw&hd=1 (works even in Germany)
64.
65. // Thanks to Bart Campman, Pjotr Svetachov and Martijn Kragtwijk for their help.
66.
68. {
69.         Properties
70.         {
71.                 _MainTex ("Base (RGB)", 2D) = "white" {}
72.                 _FlowMap ("Flow", 2D) = "red" {}
73.                 _WaterNormalMap("Water normal", 2D) = "blue" {}
74.                 _SkyBox("SkyBox", CUBE) = "" {}
75.                 _FlowSpeed("Flow speed", float) = 1.0
76.                 _FlowTileScale("Flow tile scale", float) = 35.0
77.                 _NormalTileScale("Normal tile scale", float) = 10.0
78.         }
80.         {
81.                 Tags { "RenderType"="Opaque" }
82.                 LOD 200
83.
84.                 CGPROGRAM
85.                 #pragma surface surf Lambert
86.                 #pragma target 3.0
87.
88.                 sampler2D _MainTex, _FlowMap, _WaterNormalMap;
89.                 samplerCUBE _SkyBox;
90.                 float _FlowSpeed, _FlowTileScale, _NormalTileScale;
91.
92.                 struct Input
93.                 {
94.                         float2 uv_MainTex;
95.                         float2 uv_FlowMap;
96.                         float2 uv_WaterNormalMap;
97.                         float3 viewDir;
98.                 };
99.
100.                 void surf (Input IN, inout SurfaceOutput o)
101.                 {
102.
103.                         // texScale determines the amount of tiles generated.
104.                         float texScale = _FlowTileScale;
105.                         // texScale2 determines the repeat of the water texture (the normalmap) itself
106.                         float texScale2 = _NormalTileScale;
107.                         float myangle;
108.                         float transp;
109.                         float3 myNormal;
110.
111.                         float2 mytexFlowCoord = IN.uv_FlowMap * texScale;
112.                         // ff is the factor that blends the tiles.
113.                         float2 ff =  abs(2.0*(frac(mytexFlowCoord)) - 1.0) -0.5;
114.                         // take a third power, to make the area with more or less equal contribution
115.                         // of more tile bigger
116.                         ff = 0.5-4.0*ff*ff*ff;
117.                         // ffscale is a scaling factor that compensates for the effect that
118.                         // adding normal vectors together tends to get them closer to the average normal
119.                         // which is a visible effect. For more or less random waves, this factor
120.                         // compensates for it
121.                         float2 ffscale = sqrt(ff*ff + (1-ff)*(1-ff));
122.                         float2 Tcoord = IN.uv_WaterNormalMap  * texScale2;
123.
124.                         // offset makes the water move
125.                         float2 _offset = float2(_Time.x * _FlowSpeed,0);
126.
127.                         // I scale the texFlowCoord and floor the value to create the tiling
128.                     // This could have be replace by an extremely lo-res texture lookup
129.                     // using NEAREST pixel.
130.                     float3 flow = tex2D(_FlowMap, floor(mytexFlowCoord)/ texScale).rgb;
131.
132.                     // flowdir is supposed to go from -1 to 1 and the line below
133.                     // used to be sample.xy * 2.0 - 1.0, but saves a multiply by
134.                     // moving this factor two to the sample.b
135.                     float2 flowdir = flow.xy -0.5;
136.
137.                     // sample.b is used for the inverse length of the wave
138.                     // could be premultiplied in sample.xy, but this is easier for editing flowtexture
139.                     flowdir *= flow.b;
140.
141.                     // build the rotation matrix that scales and rotates the complete tile
142.                     float2x2 rotmat = float2x2(flowdir.x, -flowdir.y, flowdir.y ,flowdir.x);
143.
144.                     // this is the normal for tile A
145.                     float2 NormalT0 = tex2D(_WaterNormalMap, mul(rotmat, Tcoord) - _offset).rg;
146.
147.                     // for the next tile (B) I shift by half the tile size in the x-direction
148.                     flow = tex2D( _FlowMap, floor((mytexFlowCoord + float2(0.5,0)))/ texScale ).rgb;
149.
150.                     flowdir = flow.b * (flow.xy - 0.5);
151.                     rotmat = float2x2(flowdir.x, -flowdir.y, flowdir.y ,flowdir.x);
152.                         // and the normal for tile B...
153.                         // multiply the offset by some number close to 1 to give it a different speed
154.                         // The result is that after blending the water starts to animate and look
155.                         // realistic, instead of just sliding in some direction.
156.                         // This is also why I took the third power of ff above, so the area where the
157.                         // water animates is as big as possible
158.                         // adding a small arbitrary constant isn't really needed, but helps to show
159.                         // a bit less tiling in the beginning of the program. After a few seconds, the
160.                         // tiling cannot be seen anymore so this constant could be removed.
161.                         // For the quick demo I leave them in. In a simulation that keeps running for
162.                         // some time, you could just as well remove these small constant offsets
163.                         float2 NormalT1 = tex2D(_WaterNormalMap, mul(rotmat, Tcoord) - _offset*1.06+0.62).rg ;
164.
165.                         // blend them together using the ff factor
166.                         // use ff.x because this tile is shifted in the x-direction
167.                         float2 NormalTAB = ff.x * NormalT0 + (1.0-ff.x) * NormalT1;
168.
169.                         // the scaling of NormalTab and NormalTCD is moved to a single scale of
170.                         // NormalT later in the program, which is mathematically identical to
171.                         // NormalTAB = (NormalTAB - 0.5) / ffscale.x + 0.5;
172.
173.                         // tile C is shifted in the y-direction
174.                         flow = tex2D( _FlowMap, floor((mytexFlowCoord + float2(0.0,0.5)))/ texScale ).rgb;
175.
176.                         flowdir = flow.b * (flow.xy - 0.5);
177.                         rotmat = float2x2(flowdir.x, -flowdir.y, flowdir.y ,flowdir.x);
178.                         NormalT0 = tex2D(_WaterNormalMap, mul(rotmat, Tcoord) - _offset*1.33+0.27).rg;
179.
180.                         // tile D is shifted in both x- and y-direction
181.                         flow = tex2D( _FlowMap, floor((mytexFlowCoord + float2(0.5,0.5)))/ texScale ).rgb;
182.
183.                         flowdir = flow.b * (flow.xy - 0.5);
184.                         rotmat = float2x2(flowdir.x, -flowdir.y, flowdir.y ,flowdir.x);
185.                         NormalT1 = tex2D(_WaterNormalMap, mul(rotmat, Tcoord) - _offset*1.24).rg ;
186.
187.                         float2 NormalTCD = ff.x * NormalT0 + (1.0-ff.x) * NormalT1;
188.                         // NormalTCD = (NormalTCD - 0.5) / ffscale.x + 0.5;
189.
190.                         // now blend the two values together
191.                         float2 NormalT = ff.y * NormalTAB + (1.0-ff.y) * NormalTCD;
192.
193.                         // this line below used to be here for scaling the result
194.                         //NormalT = (NormalT - 0.5) / ffscale.y + 0.5;
195.
196.                         // below the new, direct scaling of NormalT
197.                         NormalT = (NormalT - 0.5) / (ffscale.y * ffscale.x);
198.                         // scaling by 0.3 is arbritrary, and could be done by just
199.                         // changing the values in the normal map
200.                         // without this factor, the waves look very strong
201.                         NormalT *= 0.3;
202.                         // to make the water more transparent
203.                         transp = tex2D( _FlowMap, IN.uv_FlowMap ).a;
204.                         // and scale the normals with the transparency
205.                         NormalT *= transp*transp;
206.
207.                         // assume normal of plane is 0,0,1 and produce the normalized sum of adding NormalT to it
208.                         myNormal = float3(NormalT,sqrt(1.0-NormalT.x*NormalT.x - NormalT.y*NormalT.y));
209.
210.                         float3 reflectDir = reflect(IN.viewDir, myNormal);
211.                         float3 envColor = texCUBE(_SkyBox, reflectDir).rgb;
212.
213.                         // very ugly version of fresnel effect
214.                         // but it gives a nice transparent water, but not too transparent
215.                         myangle = dot(myNormal,normalize(IN.viewDir));
216.                         myangle = 0.95-0.6*myangle*myangle;
217.
218.                         // blend in the color of the plane below the water
219.
220.                         // add in a little distortion of the colormap for the effect of a refracted
221.                         // view of the image below the surface.
222.                         // (this isn't really tested, just a last minute addition
223.                         // and perhaps should be coded differently
224.
225.                         // the correct way, would be to use the refract routine, use the alpha channel for depth of
226.                         // the water (and make the water disappear when depth = 0), add some watercolor to the colormap
227.                         // depending on the depth, and use the calculated refractdir and the depth to find the right
228.                         // pixel in the colormap.... who knows, something for the next version
229.                         float4 base = tex2D(_MainTex, IN.uv_MainTex + myNormal.xy/texScale2*0.03*transp);
230.
231.                         base = float4(lerp(base.rgb,envColor,myangle*transp),1.0 );
232.
233.                         // note that smaller waves appear to move slower than bigger waves
234.                         // one could use the tiles and give each tile a different speed if that
235.                         // is what you want
236.
237.                         o.Albedo = base.rgb;
238.                         o.Alpha = base.a;
239.
240.
241.
242.
243.                 }
244.                 ENDCG
245.         }
246.         FallBack "Diffuse"
247. }
RAW Paste Data
Top