Guest User

Vtastek water shader

a guest
Aug 26th, 2016
3,335
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // XE Water.fx
  2. // MGE XE 0.9
  3. // Water functions (included by XE Main)
  4.  
  5.  
  6. //------------------------------------------------------------
  7. // Samplers, clamping mode
  8.  
  9. sampler sampReflect = sampler_state { texture = <tex0>; minfilter = linear; magfilter = linear; mipfilter = none; addressu = clamp; addressv = clamp; };
  10. sampler sampRefract = sampler_state { texture = <tex2>; minfilter = linear; magfilter = linear; mipfilter = none; addressu = clamp; addressv = clamp; };
  11.  
  12. //------------------------------------------------------------
  13. // Water constants
  14.  
  15. static const float kDistantZBias = 5e-6;
  16. static const float _lightfactor = 1 - pow(1 - SunVis, 2);
  17. static const float3 _depthcolor = _lightfactor * SunCol * float3(0.03, 0.04, 0.05) + (2 * SkyCol + FogCol2) * float3(0.094, 0.22, 0.19);
  18. static const float3 _SunCollf = SunCol * _lightfactor;
  19. static const float _windfactor = (length (WindVec) + 1.5) / 140;
  20. static const float waterlevel = world[3][2];
  21. static const float cauststr = 0.05 * alpharef * saturate(0.75 * _lightfactor + 0.35 * length(FogCol2));
  22.  
  23. shared texture tex4, tex5;
  24. shared float3 rippleOrigin;
  25. shared float waveHeight;
  26.  
  27. sampler sampRain = sampler_state { texture = <tex4>; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; };
  28. sampler sampWave = sampler_state { texture = <tex5>; minfilter = linear; magfilter = linear; mipfilter = linear; bordercolor = 0x80808080; addressu = border; addressv = border; };
  29.  
  30. static const float waveTexResolution = 512;
  31. static const float waveTexWorldSize = waveTexResolution * 2.5;
  32. static const float waveTexRcpRes = 1.0 / (waveTexResolution-1);
  33. static const float playerWaveSize = 12.0 / waveTexWorldSize; // 12 world units radius
  34.  
  35. //------------------------------------------------------------
  36. // Static functions
  37.  
  38. float3 getFinalWaterNormal(float2 texcoord1, float2 texcoord2, float dist, float2 vertXY) : NORMAL
  39. {
  40. // Calculate the W texture coordinate based on the time that has passed
  41. float t = 0.4 * time;
  42. float3 w1 = float3(texcoord1, t);
  43. float3 w2 = float3(texcoord2, t);
  44. float3 w3 = float3(texcoord2 * 0.5, t);
  45.  
  46. // Blend together the normals from different sized areas of the same texture
  47. float2 far_normal = tex3D(sampWater3d, w1).rg;
  48. float2 close_normal = tex3D(sampWater3d, w2).rg;
  49. close_normal += tex3D(sampWater3d, w3).rg;
  50. close_normal *= 0.5;
  51.  
  52.  
  53.  
  54. #ifdef DYNAMIC_RIPPLES
  55. // Add rain and player ripples
  56. close_normal.rg += tex2D(sampRain, texcoord2).ba - 0.5;
  57. close_normal.rg += tex2D(sampWave, (vertXY - rippleOrigin) / waveTexWorldSize).ba * 2 - 1;
  58. #endif
  59.  
  60. float2 normal_R = 2 * lerp(close_normal, far_normal, saturate(dist / 8000)) - 1;
  61. return normalize(float3(normal_R, 0.3));
  62. }
  63.  
  64. #ifndef FILTER_WATER_REFLECTION
  65.  
  66. float3 getProjectedReflection(float4 tex)
  67. {
  68. return tex2Dproj(sampReflect, tex).rgb;
  69. }
  70.  
  71. #else
  72.  
  73. float3 getProjectedReflection(float4 tex)
  74. {
  75. float4 radius = 0.006 * saturate(0.11 + tex.w/6000) * tex.w * float4(1, rcpres.y/rcpres.x, 0, 0);
  76.  
  77. float3 reflected = tex2Dproj(sampReflect, tex);
  78. reflected += tex2Dproj(sampReflect, tex + radius*float4(0.60, 0.10, 0, 0));
  79. reflected += tex2Dproj(sampReflect, tex + radius*float4(0.30, -0.21, 0, 0));
  80. reflected += tex2Dproj(sampReflect, tex + radius*float4(0.96, -0.03, 0, 0));
  81. reflected += tex2Dproj(sampReflect, tex + radius*float4(-0.40, 0.06, 0, 0));
  82. reflected += tex2Dproj(sampReflect, tex + radius*float4(-0.70, 0.18, 0, 0));
  83. reflected /= 6.0;
  84.  
  85. return reflected.rgb;
  86. }
  87.  
  88. #endif
  89.  
  90. //------------------------------------------------------------
  91. // Water shader
  92.  
  93. struct WaterVertOut
  94. {
  95. float4 position : POSITION;
  96. float4 pos : TEXCOORD0;
  97. float4 texcoords : TEXCOORD1;
  98. float4 screenpos : TEXCOORD2;
  99. #ifdef DYNAMIC_RIPPLES
  100. float4 screenposclamp : TEXCOORD3;
  101. #endif
  102. };
  103.  
  104. #ifndef DYNAMIC_RIPPLES
  105.  
  106. WaterVertOut WaterVS (in float4 pos : POSITION)
  107. {
  108. WaterVertOut OUT;
  109.  
  110. // Add z bias to avoid fighting with MW ripples quads
  111. OUT.pos = mul(pos, world);
  112. OUT.pos.z -= 0.1;
  113.  
  114. // Calculate various texture coordinates
  115. OUT.texcoords.xy = OUT.pos.xy / 3900;
  116. OUT.texcoords.zw = OUT.pos.xy / 527;
  117.  
  118. OUT.position = mul(OUT.pos, view);
  119. OUT.position = mul(OUT.position, proj);
  120.  
  121. // Match bias in distant land projection
  122. OUT.position.z *= 1.0 + kDistantZBias * step(nearViewRange, OUT.position.w);
  123.  
  124. OUT.screenpos = float4(0.5 * (1 + rcpres) * OUT.position.w + float2(0.5, -0.5) * OUT.position.xy, OUT.position.zw);
  125.  
  126. return OUT;
  127. }
  128.  
  129. #else
  130.  
  131. WaterVertOut WaterVS (in float4 pos : POSITION)
  132. {
  133. WaterVertOut OUT;
  134.  
  135. // Move to world space
  136. OUT.pos = mul(pos, world);
  137.  
  138. // Calculate various texture coordinates
  139. OUT.texcoords.xy = OUT.pos.xy / 1950;
  140. OUT.texcoords.zw = OUT.pos.xy / 258;
  141.  
  142. // Apply vertex displacement
  143. float t = 0.4 * time;
  144. float height = tex3Dlod(sampWater3d, float4(OUT.pos.xy / 1104, t, 0)).a;
  145. float height2 = tex3Dlod(sampWater3d, float4(OUT.pos.xy / 3900, t, 0)).a;
  146. float dist = length(EyePos.xyz - OUT.pos.xyz);
  147.  
  148. float addheight = waveHeight * (lerp(height, height2, saturate(dist/8000)) - 0.5) * saturate(1 - dist/6400) * saturate(dist/200);
  149. OUT.pos.z += addheight;
  150.  
  151. // Match bias in distant land projection
  152. OUT.position = mul(OUT.pos, view);
  153. OUT.position = mul(OUT.position, proj);
  154. OUT.position.z *= 1.0 + kDistantZBias * step(nearViewRange, OUT.position.w);
  155. OUT.screenpos = float4(0.5 * (1 + rcpres) * OUT.position.w + float2(0.5, -0.5) * OUT.position.xy, OUT.position.zw);
  156.  
  157. // Clamp reflection point to be above surface
  158. float4 clampedPos = OUT.pos - float4(0, 0, abs(addheight), 0);
  159. clampedPos = mul(clampedPos, view);
  160. clampedPos = mul(clampedPos, proj);
  161. clampedPos.z *= 1.0 + kDistantZBias * step(nearViewRange, clampedPos.w);
  162. OUT.screenposclamp = float4(0.5 * (1 + rcpres) * clampedPos.w + float2(0.5, -0.5) * clampedPos.xy, clampedPos.zw);
  163.  
  164. return OUT;
  165. }
  166. #endif
  167.  
  168. float4 WaterPS(in WaterVertOut IN): COLOR0
  169. {
  170. // Calculate eye vector
  171. float3 EyeVec = IN.pos.xyz - EyePos.xyz;
  172. float dist = length(EyeVec);
  173. EyeVec /= dist;
  174.  
  175. // Define fog
  176. float4 fog = fogColour(EyeVec, dist);
  177. float3 depthcolor = fogApply(_depthcolor, fog);
  178. //float3 depthcolor = fogApply(exp(-float3(1.22, 1.2, 1.8)*1), fog); // + float3(0.169,0.346,0.52)*0.1;
  179.  
  180. // Calculate water normal
  181. float3 normal = getFinalWaterNormal(IN.texcoords.xy, IN.texcoords.zw, dist, IN.pos.xy);
  182.  
  183. // Reflection/refraction pixel distortion factor, wind strength increases distortion
  184. float2 reffactor = (_windfactor * dist + 0.1) * normal.xy;
  185.  
  186. // Distort refraction dependent on depth
  187. float4 newscrpos = IN.screenpos + float4(reffactor.yx, 0, 0);
  188. float depth = max(0, tex2Dproj(sampDepth, newscrpos).r - IN.screenpos.w);
  189.  
  190. // Refraction
  191. float3 refracted = depthcolor;
  192. float shorefactor = 0;
  193. float2 aber = reflect(EyeVec, normal).xy;
  194. float dpcop = 0;
  195. float3 ssw = 0;
  196. float depthscale2 = 0;
  197. // Avoid sampling deep water
  198. if(depth < 8000)
  199. {
  200. // Sample refraction texture
  201. newscrpos = IN.screenpos + saturate(depth / 100) * float4(reffactor.yx, 0.0, 0.0);
  202. refracted.r = tex2Dproj(sampRefract, newscrpos).r;
  203. refracted.g = tex2Dproj(sampRefract, newscrpos - float4(aber * 0.04, 0.0, 0.0)).g;
  204. refracted.b = tex2Dproj(sampRefract, newscrpos - float4(aber * 2 * 0.04, 0.0, 0.0)).b;
  205. // Get distorted depth
  206. depth = max(0, tex2Dproj(sampDepth, newscrpos).r - IN.screenpos.w);
  207. depth /= dot(EyeVec, float3(view[0][2], view[1][2], view[2][2]));
  208.  
  209. // Small scale shoreline animation
  210. depth += 300 * (0.95 - normal.z);
  211. ssw = saturate(((IN.pos.z+10) / waveHeight)) * float3(0.32,0.51,0.3);
  212. float depthscale = saturate(exp(-depth / (1600)));
  213. depthscale2 = saturate(exp(-depth / (3200)));
  214.  
  215.  
  216. depthscale2 = (depthscale + ssw * 5);
  217.  
  218. dpcop = depthscale;
  219. shorefactor = pow(depthscale, 90);
  220.  
  221. // Make transition between actual refraction image and depth color depending on water depth
  222. refracted = lerp(depthcolor, refracted, 0.8 * depthscale + 0.2 * shorefactor);
  223. }
  224.  
  225. //return refracted.rgbr;
  226. // Sample reflection texture
  227. #ifndef DYNAMIC_RIPPLES
  228. float4 screenpos = IN.screenpos;
  229. #else
  230. float4 screenpos = IN.screenposclamp;
  231. #endif
  232. float3 reflected = getProjectedReflection(screenpos - float4(2.1 * reffactor.x, -abs(reffactor.y), 0, 0));
  233.  
  234. // Dull reflection to avoid being too bright relative to sky,
  235. // except for fading into an inscatter dominated horizon
  236. reflected *= 1 - 0.16 * saturate(2 * fog.a);
  237.  
  238. // Smooth out high frequencies at a distance
  239. float3 adjustnormal = lerp(float3(0, 0, 0.1), normal, pow(saturate(1.05 * fog.a), 2));
  240. adjustnormal = lerp(adjustnormal, float3(0, 0, 1.0), (1 + EyeVec.z) * (1 - saturate(1 / (dist / 1000 + 1))));
  241.  
  242. // Fresnel equation determines reflection/refraction
  243. float fresnel = dot(-EyeVec, pow(adjustnormal,4));
  244. fresnel = 0.02 + pow(saturate(0.9988 - 0.38 * fresnel), 16);
  245. //fresnel = 1 - 0.02 + pow((2*(fresnel-0.23 - 0.5)),5)*0.2 * -1.0;
  246. //1 - 0.02 + (2*(x-0.23))^5 *0.2
  247.  
  248. float lum = dot(float3(0.27, 0.54, 0.19), refracted.rgb);
  249. float topbright = 1.0 - (1.0 - lum) * (1.0 - dpcop);
  250.  
  251. //return depthscale2.xxxx;
  252. float3 dark1 = float3(0.039,0.074,0.101);
  253. float3 light1 = float3(0.13,0.18,0.16);
  254. float3 dark2 = float3(0.01,0.08,0.16);
  255. float3 light2 = float3(0.09,0.18,0.203)*6;
  256. light2 = lerp(light2, 3.00, dpcop);
  257.  
  258. float3 refracteddark = lerp(dark1, light1, lum)*3;
  259. float3 refractedlight = lerp(dark2, light2, dpcop);
  260. refracteddark = saturate(refracteddark);
  261. refractedlight = saturate(refractedlight);
  262. float3 tint = lerp(refracteddark, refractedlight, SunAmb * 0.13 + _SunCollf);
  263. //return refracted.rgbr;
  264. refracted *= tint;
  265.  
  266. //refracted += ssw * refracted * 3.3;
  267.  
  268. //return float4(refracted, 1);
  269. //reflected = pow(reflected,1.2) * 1.33;
  270. // float3 result = refracted * 1.1 + saturate((pow(reflected,2) * 4 - 0.2) * fresnel);
  271.  
  272. // float lum = dot(float3(0.27, 0.54, 0.19), result.rgb);
  273.  
  274. // Mix with luminance to avoid oversaturated single channels
  275. //reflected = saturate(lerp(lum, reflected, 0.8) - 0.3) * 3 ;
  276. refracted = pow(saturate(refracted), 2.2);
  277. reflected = pow(saturate(reflected * 1.1), 2.2);
  278.  
  279. float3 result = lerp(refracted, reflected, fresnel);
  280. //float3 result = lerp(0, 1, fresnel);
  281. result = exp( -1.0 / ( 2.72 * result + 0.08 ) );
  282.  
  283. result = pow(result, 1/2.2);
  284.  
  285. //return float4(refracted, 1);
  286. //float3 result = lerp(refracted, reflected * 0.98, 0.02 + 1.1 * saturate(fresnel + 0.3 * (pow(reflected, 3) * 3 - 0.8)));
  287. //return fresnel.xxxx;
  288. //float lum = dot(float3(0.27, 0.54, 0.19), result.rgb);
  289. //result = result * (1.0 - exp(lum * 8.0))/(lum);
  290.  
  291.  
  292. // + saturate(1-fresnel) * SkyCol * 0.05);
  293. //return float4(result, 1);
  294. //result = max(0.0, result - 0.004);
  295. //result = (result * (6.2 * result + 0.5)) / (result * (6.2 * result + 1.7) + 0.06);
  296.  
  297. // Specular lighting
  298. // This should use Blinn-Phong, but it doesn't work so well for area lights like the sun
  299. // Instead multiply and saturate to widen a Phong specular lobe which better simulates an area light
  300. float vdotr = dot(-EyeVec, reflect(-SunPos, normal));
  301. vdotr = saturate(1.0025 * vdotr);
  302. float3 spec = _SunCollf * (pow(vdotr, 170)); //+ 0.07 * pow(vdotr, 4));
  303. //spec = 1 / (1 + spec*16);
  304. result += spec * 2 * fog.a;
  305.  
  306.  
  307.  
  308. // Smooth transition at shore line
  309. result = lerp(result, refracted, shorefactor * fog.a);
  310.  
  311. // Note that both refraction and reflection textures were rendered fogged already
  312. result = fogApply(result.rgb, fog);
  313. return float4(result.rgb, 1);
  314. }
  315.  
  316. float4 UnderwaterPS(in WaterVertOut IN): COLOR0
  317. {
  318. // Calculate eye vector
  319. float3 EyeVec = IN.pos.xyz - EyePos.xyz;
  320. float dist = length(EyeVec);
  321. EyeVec /= dist;
  322.  
  323. // Special case fog, avoid fog offset
  324. float fog = saturate(exp(-dist / 4096));
  325.  
  326. // Calculate water normal
  327. float3 normal = -getFinalWaterNormal(IN.texcoords.xy, IN.texcoords.zw, dist, IN.pos.xy);
  328.  
  329. // Reflection / refraction pixel distortion factor, wind strength increases distortion
  330. float2 reffactor = 2 * (_windfactor * dist + 0.1) * normal.xy;
  331.  
  332. // Distort refraction
  333. float4 newscrpos = IN.screenpos + float4(2 * -reffactor.xy, 0, 0);
  334. float3 refracted = tex2Dproj(sampRefract, newscrpos).rgb;
  335. refracted = lerp(FogCol2, refracted, exp(-dist / 500));
  336.  
  337. // Sample reflection texture
  338. float3 reflected = getProjectedReflection(IN.screenpos - float4(2.1 * reffactor.x, -abs(reffactor.y), 0, 0));
  339.  
  340. // Fresnel equation, including total internal reflection
  341. float fresnel = pow(saturate(1.12 - 0.65 * dot(-EyeVec, normal)), 8);
  342. float3 result = lerp(refracted, reflected, fresnel);
  343.  
  344. // Sun refraction
  345. float refractsun = dot(-EyeVec, normalize(-SunPos + normal));
  346. float3 spec = _SunCollf * pow(refractsun, 6) * fog;
  347.  
  348. return float4(result + spec, 1);
  349. }
  350.  
  351. //------------------------------------------------------------
  352. // Caustics post-process
  353.  
  354. DeferredOut CausticsVS(float4 pos : POSITION, float2 tex : TEXCOORD0, float2 ndc : TEXCOORD1)
  355. {
  356. DeferredOut OUT;
  357.  
  358. // Fix D3D9 half pixel offset
  359. OUT.pos = float4(ndc.x - rcpres.x, ndc.y + rcpres.y, 0, 1);
  360. OUT.tex = float4(tex, 0, 0);
  361.  
  362. // World space reconstruction vector
  363. OUT.eye = float3(view[0][2], view[1][2], view[2][2]);
  364. OUT.eye += (ndc.x / proj[0][0]) * float3(view[0][0], view[1][0], view[2][0]);
  365. OUT.eye += (ndc.y / proj[1][1]) * float3(view[0][1], view[1][1], view[2][1]);
  366. return OUT;
  367. }
  368.  
  369. float4 CausticsPS(DeferredOut IN) : COLOR0
  370. {
  371. float3 c = tex2Dlod(sampBaseTex, IN.tex).rgb;
  372. float depth = tex2Dlod(sampDepthPoint, IN.tex).r;
  373. float fog = fogMWScalar(depth);
  374.  
  375. clip(nearViewRange - depth);
  376.  
  377. float3 uwpos = EyePos + IN.eye * depth;
  378. uwpos.z -= waterlevel;
  379. clip(-uwpos.z);
  380.  
  381. float3 sunray = uwpos - SunVec * (uwpos.z / SunVec.z);
  382. float caust = cauststr * 5 * tex3D(sampWater3d, float3(sunray.xy / 1104, 0.4 * time)).b;
  383. caust *= saturate(125 / depth * min(fwidth(sunray.x), fwidth(sunray.y)));
  384. c *= 1 + (caust - 0.3) * saturate(exp(uwpos.z / 400)) * saturate(uwpos.z / -30) * fog;
  385.  
  386. return float4(c, 1);
  387. }
  388.  
  389.  
  390. //------------------------------------------------------------
  391. // Dynamic waves
  392.  
  393. struct WaveVertOut
  394. {
  395. float4 pos : POSITION;
  396. float2 texcoord : TEXCOORD0;
  397. };
  398.  
  399. WaveVertOut WaveVS(float4 pos : POSITION, float2 texcoord : TEXCOORD0)
  400. {
  401. WaveVertOut OUT;
  402. OUT.pos = mul(pos, proj);
  403. OUT.texcoord = texcoord;
  404. return OUT;
  405. }
  406.  
  407. //------------------------------------------------------------
  408.  
  409. float4 WaveStepPS(float2 Tex : TEXCOORD0) : COLOR0
  410. {
  411. float4 c = 2 * tex2D(sampRain, Tex) - 1;
  412. float4 ret = {0, c.r, 0, 0};
  413.  
  414. float4 n = {
  415. tex2D(sampRain, Tex + float2(waveTexRcpRes, 0)).r,
  416. tex2D(sampRain, Tex + float2(-waveTexRcpRes, 0)).r,
  417. tex2D(sampRain, Tex + float2(0, waveTexRcpRes)).r,
  418. tex2D(sampRain, Tex + float2(0, -waveTexRcpRes)).r
  419. };
  420. float4 n2 = {
  421. tex2D(sampRain, Tex + float2(1.5 * waveTexRcpRes, 0)).r,
  422. tex2D(sampRain, Tex + float2(-1.5 * waveTexRcpRes, 0)).r,
  423. tex2D(sampRain, Tex + float2(0, 1.5 * waveTexRcpRes)).r,
  424. tex2D(sampRain, Tex + float2(0, -1.5 * waveTexRcpRes)).r
  425. };
  426.  
  427. // expand normal
  428. n = 2 * n - 1;
  429.  
  430. // dampened discrete two-dimensional wave equation
  431. // red channel: u(t)
  432. // green channel: u(t - 1)
  433. // u(t + 1) = (1 - udamp) * u(t) + a * (nsum - 4 * u(t)) + (1 - vdamp) * (u(t) - u(t - 1))
  434. // = a * nsum + ((2 - udamp - vdamp) - 4 * a) * u(t) - (1 - vdamp) * u(t - 1);
  435. float nsum = n.x + n.y + n.z + n.w;
  436. ret.r = 0.14 * nsum + (1.96 - 0.56) * c.r - 0.98 * c.g;
  437.  
  438. // calculate normal map
  439. ret.ba = 2 * (n.xy - n.zw) + (n2.xy - n2.zw);
  440. ret = 0.5 * ret + 0.5;
  441.  
  442. return ret;
  443. }
  444.  
  445. float4 PlayerWavePS(float2 Tex : TEXCOORD0) : COLOR0
  446. {
  447. float4 ret = tex2D(sampRain, Tex);
  448. float wavesize = (1.0 + 0.055 * sin(16 * time) + 0.065 * sin(12.87645 * time)) * playerWaveSize;
  449. ret.rg *= saturate(2 * abs(length(Tex - rippleOrigin) / wavesize - 1));
  450. return ret;
  451. }
RAW Paste Data