Ocean.fx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. //////////////////////////////////////////////////////////////////////////////
  2. // ©2008 Electronic Arts Inc
  3. //
  4. // FX Shader for Ocean Water Simulation for Red Alert 3
  5. //////////////////////////////////////////////////////////////////////////////
  6. // ----------------------------------------------------------------------------
  7. // Includes and Defines
  8. // ----------------------------------------------------------------------------
  9. #if !defined(DONT_DO_DYNAMIC_DISPLACEMENT)
  10. #define DO_DYNAMIC_DISPLACEMENT
  11. #endif
  12. #define USE_INTERACTIVE_LIGHTS 1
  13. #define SUPPORT_GLOBAL_LIGHTS 1
  14. #include "Common.fxh"
  15. #include "Gamma.fxh"
  16. #include "ShadowMap.fxh"
  17. #if defined(EA_PLATFORM_WINDOWS) && defined(_3DSMAX_)
  18. // ----------------------------------------------------------------------------
  19. // SAMPLER : nhendricks : had to pull these in here for MAX to compile
  20. // ----------------------------------------------------------------------------
  21. #define SAMPLER_2D_BEGIN(samplerName, annotations) \
  22. texture samplerName \
  23. < \
  24. annotations \
  25. >; \
  26. sampler2D samplerName##Sampler = sampler_state \
  27. { \
  28. Texture = < samplerName >;
  29. #define SAMPLER_2D_END };
  30. #define SAMPLER( samplerName ) samplerName##Sampler
  31. #define SAMPLER_CUBE_BEGIN(samplerName, annotations) \
  32. texture samplerName \
  33. < \
  34. annotations \
  35. >; \
  36. samplerCUBE samplerName##Sampler = sampler_state \
  37. { \
  38. Texture = < samplerName >;
  39. #define SAMPLER_CUBE_END };
  40. #endif // defined(EA_PLATFORM_WINDOWS)
  41. SAMPLER_2D_BEGIN( StaticDisplacementTexture,
  42. string SasBindAddress = "Water.StaticDisplacementTexture";
  43. )
  44. MinFilter = Linear;
  45. MagFilter = Linear;
  46. MipFilter = Linear;
  47. AddressU = Wrap;
  48. AddressV = Wrap;
  49. SAMPLER_2D_END
  50. // ----------------------------------------------------------------------------
  51. // Reflection
  52. // ----------------------------------------------------------------------------
  53. SAMPLER_2D_BEGIN( WaterReflectionTexture,
  54. string UIWidget = "None";
  55. string SasBindAddress = "Water.ReflectionTexture";
  56. )
  57. MipFilter = Point;
  58. MinFilter = Linear;
  59. MagFilter = Linear;
  60. AddressU = CLAMP;
  61. AddressV = CLAMP;
  62. SAMPLER_2D_END
  63. SAMPLER_2D_BEGIN( WaterRefractionTexture,
  64. string UIWidget = "None";
  65. string SasBindAddress = "Water.RefractionTexture";
  66. )
  67. MipFilter = Point;
  68. MinFilter = Linear;
  69. MagFilter = Linear;
  70. AddressU = CLAMP;
  71. AddressV = CLAMP;
  72. SAMPLER_2D_END
  73. // ----------------------------------------------------------------------------
  74. // Environment map
  75. // ----------------------------------------------------------------------------
  76. SAMPLER_CUBE_BEGIN( EnvironmentTexture,
  77. string UIWidget = "None";
  78. string SasBindAddress = "Water.LightSpaceEnvironmentMap";
  79. string ResourceType = "Cube";
  80. )
  81. MinFilter = Linear;
  82. MagFilter = Linear;
  83. MipFilter = Linear;
  84. AddressU = Clamp;
  85. AddressV = Clamp;
  86. AddressW = Clamp;
  87. SAMPLER_CUBE_END
  88. // ----------------------------------------------------------------------------
  89. // Shroud
  90. // ----------------------------------------------------------------------------
  91. ShroudSetup Shroud
  92. <
  93. string UIWidget = "None";
  94. string SasBindAddress = "Terrain.Shroud";
  95. > = DEFAULT_SHROUD;
  96. SAMPLER_2D_BEGIN( ShroudSampler,
  97. string UIWidget = "None";
  98. string SasBindAddress = "Terrain.Shroud.Texture";
  99. )
  100. MinFilter = Linear;
  101. MagFilter = Linear;
  102. MipFilter = Linear;
  103. AddressU = Clamp;
  104. AddressV = Clamp;
  105. SAMPLER_2D_END
  106. // ----------------------------------------------------------------------------
  107. // Editable parameters
  108. // ----------------------------------------------------------------------------
  109. // Material parameters
  110. float4 MaterialColorDiffuse <
  111. string UIName = "Diffuse Material Color";
  112. string UIWidget = "Color";
  113. > = float4(1.0, 1.0, 1.0, 0.0);
  114. SAMPLER_2D_BEGIN( Foam,
  115. string UIName = "FoamMap";
  116. )
  117. MinFilter = MinFilterBest;
  118. MagFilter = MagFilterBest;
  119. MipFilter = MipFilterBest;
  120. AddressU = Wrap;
  121. AddressV = Wrap;
  122. SAMPLER_2D_END
  123. float FoamHeight
  124. <
  125. string UIName = "Foam Mask Height";
  126. string UIWidget = "Slider";
  127. float UIMax = 25.0f;
  128. float UIMin = -25;
  129. float UIStep = 0.1f;
  130. > = 0.0;
  131. float FoamBlend
  132. <
  133. string UIName = "Foam Mask Blend";
  134. string UIWidget = "Slider";
  135. float UIMax = 25.0f;
  136. float UIMin = .1;
  137. float UIStep = 0.1f;
  138. > = 1.0;
  139. float Foam1Scalar
  140. <
  141. string UIName = "Foam 1 Scale";
  142. string UIWidget = "Slider";
  143. float UIMax = 50.0f;
  144. float UIMin = 0;
  145. float UIStep = 0.01f;
  146. > = 1.0;
  147. float Foam2Scalar
  148. <
  149. string UIName = "Foam 2 Scale";
  150. string UIWidget = "Slider";
  151. float UIMax = 50.0f;
  152. float UIMin = 0;
  153. float UIStep = 0.01f;
  154. > = 1.0;
  155. float FoamSpeed
  156. <
  157. string UIName = "Foam Speed";
  158. string UIWidget = "Slider";
  159. float UIMax = 50.0f;
  160. float UIMin = -50.0f;
  161. float UIStep = 0.01f;
  162. > = 1.0;
  163. float OctaveScalar
  164. <
  165. string UIName = "Octave Scale";
  166. string UIWidget = "Slider";
  167. float UIMax = 50.0f;
  168. float UIMin = 0;
  169. float UIStep = 0.01f;
  170. > = 1.0;
  171. float OctaveDivergenceAngle
  172. <
  173. string UIName = "Octave Divergence Angle";
  174. string UIWidget = "Slider";
  175. float UIMax = 180.0f;
  176. float UIMin = 0;
  177. float UIStep = 0.5f;
  178. > = 0.0;
  179. float OctaveSpeed
  180. <
  181. string UIName = "Octave Speed";
  182. string UIWidget = "Slider";
  183. float UIMax = 50.0f;
  184. float UIMin = 0;
  185. float UIStep = 0.01f;
  186. > = 1.0;
  187. float OctaveDivergenceSpeed
  188. <
  189. string UIName = "Octave Divergence Speed";
  190. string UIWidget = "Slider";
  191. float UIMax = 10.0f;
  192. float UIMin = 0;
  193. float UIStep = 0.001f;
  194. > = 0.0;
  195. float WaveAmplitude
  196. <
  197. string UIName = "Wave Amplitude";
  198. string UIWidget = "Slider";
  199. float UIMin = 0.0;
  200. float UIMax = 3.0;
  201. float UIStep = 0.1;
  202. > =3.0;
  203. float WaveFrequency
  204. <
  205. string UIName = "Wave frequency";
  206. string UIWidget = "Slider";
  207. float UIMin = 0.00;
  208. float UIMax = 6.0;
  209. float UIStep = 0.01;
  210. > = 0.2;
  211. SAMPLER_2D_BEGIN( DisplacementTexture,
  212. string SasBindAddress = "Water.DisplacementTexture";
  213. )
  214. MinFilter = Linear;
  215. MagFilter = Linear;
  216. MipFilter = Point;
  217. AddressU = Clamp;
  218. AddressV = Clamp;
  219. SAMPLER_2D_END
  220. float DisplacementTextureSize
  221. <
  222. string SasBindAddress = "Water.DisplacementTextureSize";
  223. > = 0;
  224. // ----------------------------------------------------------------------------
  225. // Wave functions
  226. // ----------------------------------------------------------------------------
  227. struct Wave
  228. {
  229. float frequency; // 2*PI / wavelength
  230. float amplitude; // amplitude
  231. float phase; // speed * 2*PI / wavelength
  232. float2 direction;
  233. };
  234. #define NWAVES 3
  235. Wave wave[NWAVES] =
  236. {
  237. { 0.1, 1, 1.0, float2(0.2, -0.7) },
  238. { 0.25, .5, 0.5, float2(-1.0, -0.7) },
  239. { 0.15, .5, 1.5, float2(-1.0, 0.2) }
  240. };
  241. float CalculateWave(Wave w, float2 pos, float t)
  242. {
  243. return w.amplitude*WaveAmplitude * sin( dot(w.direction, pos)*w.frequency*WaveFrequency + t*w.phase);
  244. }
  245. float CalculateWaveNormal(Wave w, float2 pos, float t)
  246. {
  247. return w.amplitude*WaveAmplitude * cos( dot(w.direction, pos)*w.frequency*WaveFrequency + t*w.phase);
  248. }
  249. // ----------------------------------------------------------------------------
  250. // Global Defines
  251. // ----------------------------------------------------------------------------
  252. float4x3 World : World;
  253. #if defined(_WW3D_)
  254. #if !defined(USE_INDIRECT_CONSTANT)
  255. float4x4 ViewProjection
  256. <
  257. string UIWidget = "None";
  258. string SasBindAddress = "Sas.Camera.WorldToProjection";
  259. >;
  260. float3 EyePosition
  261. <
  262. string UIWidget = "None";
  263. string SasBindAddress = "Sas.Camera.Position";
  264. >;
  265. #endif // #if !defined(USE_INDIRECT_CONSTANT)
  266. float4x4 GetViewProjection()
  267. {
  268. return ViewProjection;
  269. }
  270. float3 GetEyePosition()
  271. {
  272. return EyePosition;
  273. }
  274. #else // #if defined(_WW3D_)
  275. float4x4 View : View;
  276. float4x3 ViewI : ViewInverse;
  277. float4x4 Projection : Projection;
  278. float4x4 GetViewProjection()
  279. {
  280. return mul(View, Projection);
  281. }
  282. float3 GetEyePosition()
  283. {
  284. return ViewI[3];
  285. }
  286. #endif // #if defined(_WW3D_)
  287. float Time : Time;
  288. // ----------------------------------------------------------------------------
  289. // Shader Structure
  290. // ----------------------------------------------------------------------------
  291. struct VSOutputHigh
  292. {
  293. float4 Position : POSITION;
  294. float4 Color : COLOR0;
  295. float4 FoamTexCoords : TEXCOORD0;
  296. float4 nDispTexCoords : TEXCOORD1;
  297. float4 ShadowMapTexCoord : TEXCOORD2;
  298. float3 WorldPosition : TEXCOORD3;
  299. float4 Displacement_Refraction : TEXCOORD4;
  300. float4 ShroudTexCoord_FoamScaleOffset : TEXCOORD5;
  301. };
  302. // ----------------------------------------------------------------------------
  303. // Vertex and Pixel/Fragment Shader
  304. // ----------------------------------------------------------------------------
  305. VSOutputHigh VS_HIGH(float2 PositionXY : POSITION)
  306. {
  307. VSOutputHigh Out;
  308. float3 worldPosition = ( mul( float4( PositionXY, 0, 1 ), World ) ).xyz;
  309. float WaterPlaneHeight = worldPosition.z;
  310. // -------------------------------------------------------------------------------
  311. // -- MAX Friendly Stuff --------------------------------------------------------
  312. // -------------------------------------------------------------------------------
  313. // MAX and In-game handle time differently, this will allow a more WYSIWYG in Max
  314. #if defined(_3DSMAX_)
  315. OctaveSpeed *= .2;
  316. OctaveDivergenceSpeed *= .2;
  317. #endif
  318. // -------------------------------------------------------------------------------
  319. // -- Foam Rotation Matrix and Mapping Coords ------------------------------------
  320. // -------------------------------------------------------------------------------
  321. // Build Foam Tex coords -----------------------------------------------------
  322. Foam1Scalar *= .005; // create a more managable number in MAX sliders
  323. Foam2Scalar *= .004; // create a more managable number in MAX sliders
  324. FoamSpeed *= Time * .011; // animate Foam Speed as a multiplier of Time
  325. float2 FoamTexCoords1 = worldPosition.xy * Foam1Scalar;
  326. float2 FoamTexCoords2 = worldPosition.xy * Foam2Scalar;
  327. // Animate Foam Texture Coords --------------------------
  328. FoamTexCoords1.x += FoamSpeed;
  329. FoamTexCoords2.x -= FoamSpeed;
  330. // -------------------------------------------------------------------------------
  331. // -- nDisp Displacment and Mapping -------------------------------------------
  332. // -------------------------------------------------------------------------------
  333. // Build vDisp Tex coords and displace according to Amplitude ----------
  334. OctaveScalar = .0025; // create a more managable number in MAX sliders
  335. OctaveSpeed *= Time * .015; // animate Octave as a multiplier of Time
  336. OctaveDivergenceAngle = 55;
  337. float2 nDispTexCoords = float2(worldPosition.x * OctaveScalar, worldPosition.y * OctaveScalar);
  338. // Build Octave Texture Rotation Matrix And Convert Degrees to Radians --
  339. float cosAngle = 0;
  340. float sinAngle = 0;
  341. float2x2 uvCoordRotate = { 1.0f, 0.0f, 1.0f, 0.0f };
  342. sincos (OctaveDivergenceAngle * .017453, sinAngle, cosAngle);
  343. uvCoordRotate[0][0] = cosAngle;
  344. uvCoordRotate[0][1] = -sinAngle;
  345. uvCoordRotate[1][1] = uvCoordRotate[0][0];
  346. uvCoordRotate[1][0] = -uvCoordRotate[0][1];
  347. // Rotate and Animate vDisp Divergence Texture Coords --------------------
  348. float2 nDispTexCoordsDiverge = mul(nDispTexCoords, uvCoordRotate);
  349. nDispTexCoordsDiverge.x += OctaveSpeed + OctaveSpeed * OctaveDivergenceSpeed;
  350. float2 nDispTexCoordsDivergeInv = mul(nDispTexCoords, transpose(uvCoordRotate));
  351. nDispTexCoordsDivergeInv.x += OctaveSpeed - OctaveSpeed * OctaveDivergenceSpeed;
  352. #if defined(DO_DYNAMIC_DISPLACEMENT)
  353. float3 waveDisplacement = tex2Dlod(SAMPLER(DisplacementTexture), float4(PositionXY.x, 1.0 - PositionXY.y, 0, 0));
  354. #if defined(EA_PLATFORM_XENON) // scale range on xenon
  355. waveDisplacement.xy = waveDisplacement.xy * 2 - 1;
  356. #endif
  357. waveDisplacement = min(waveDisplacement,.13); // Hard-coded limit so the waves will not invert in the x/y axis
  358. waveDisplacement.x *= -1;
  359. // Yes its a hard coded number, this is the relationship between Vertex Displacement and
  360. // Normal Displacement in the pixel shader that looks correct
  361. worldPosition += waveDisplacement * 300;
  362. #else
  363. float3 waveDisplacement = 0;
  364. float waveValue = 0.0;
  365. for(int i=0; i<NWAVES; i++)
  366. {
  367. waveValue = CalculateWave(wave[i], worldPosition.xy, Time);
  368. worldPosition.z += max(waveValue, 0);
  369. }
  370. #endif
  371. // Compute all remaining registers ---------------------------------------
  372. Out.Position = mul(float4(worldPosition, 1), GetViewProjection());
  373. Out.Color = float4(MaterialColorDiffuse.xyz, 1.0); //float4(waveDisplacement.xyz,0); //
  374. Out.FoamTexCoords = float4(FoamTexCoords1, FoamTexCoords2);
  375. Out.nDispTexCoords = float4(nDispTexCoordsDiverge, nDispTexCoordsDivergeInv);
  376. Out.ShadowMapTexCoord = CalculateShadowMapTexCoord(worldPosition);
  377. Out.WorldPosition = worldPosition;
  378. Out.Displacement_Refraction.xy = float2(PositionXY.x, 1.0 - PositionXY.y);
  379. Out.Displacement_Refraction.zw = Out.Position.xy / Out.Position.w * 0.5 * float2(1, -1) + 0.5;
  380. Out.ShroudTexCoord_FoamScaleOffset.xy = CalculateShroudTexCoord(Shroud, worldPosition);
  381. float2 foamScaleOffset = float2(300 / FoamBlend, -FoamHeight / FoamBlend - 1);
  382. #if defined(EA_PLATFORM_WINDOWS)
  383. // On Windows do the actual foam strength calculation in the pixel shader as it will also work on non-vertex texturing hardware
  384. Out.ShroudTexCoord_FoamScaleOffset.zw = foamScaleOffset;
  385. #else
  386. // On console compute use the wave displacement we already have to calculate the foam strength directly
  387. float foamStrength = waveDisplacement.z * foamScaleOffset.x + foamScaleOffset.y;
  388. Out.ShroudTexCoord_FoamScaleOffset.zw = foamStrength;
  389. #endif
  390. return Out;
  391. }
  392. float4 PS_ULTRAHIGH(VSOutputHigh In, uniform bool hasShadow) COLORTARGET
  393. {
  394. //return In.Color;
  395. USE_DIRECTIONAL_LIGHT_INTERACTIVE(DirectionalLight, 0);
  396. float3 worldPosition = In.WorldPosition;
  397. // Compute view direction in world space
  398. float3 worldEyeDir = normalize(GetEyePosition() - worldPosition);
  399. float4 color = In.Color;
  400. float3 FoamSamp = tex2D(SAMPLER(Foam), In.FoamTexCoords.xy);
  401. FoamSamp *= tex2D(SAMPLER(Foam), In.FoamTexCoords.zw);
  402. //Calculate surface normals
  403. float3 staticDisplacement = tex2D(SAMPLER(StaticDisplacementTexture), In.nDispTexCoords.xy) * 2 - 1;
  404. staticDisplacement += tex2D(SAMPLER(StaticDisplacementTexture), In.nDispTexCoords.zw) * 2 - 1;
  405. #if defined(EA_PLATFORM_WINDOWS) // Don't displace the normals on console
  406. float2 PositionXY = In.Displacement_Refraction.xy;
  407. float heightCenter = tex2D(SAMPLER(DisplacementTexture), PositionXY).z;
  408. float heightX = tex2D(SAMPLER(DisplacementTexture), PositionXY + float2(1.0 / DisplacementTextureSize, 0)).z;
  409. float heightY = tex2D(SAMPLER(DisplacementTexture), PositionXY + float2(0, 1.0 / DisplacementTextureSize)).z;
  410. float3 nDisp = float3(heightX - heightCenter, heightY - heightCenter, 0.01) * 50;
  411. nDisp = normalize(nDisp + staticDisplacement * .2);
  412. #else
  413. float3 nDisp = (staticDisplacement); //normalize
  414. #endif
  415. float3 Nn = normalize(nDisp * 50 + float3(0, 0, 1));
  416. // Calculate Fresnel Effect
  417. float fresnelDiffuse = pow( 1-dot( worldEyeDir, Nn), 1.0);
  418. // Calculate reflection texture
  419. float4 hPosition = mul(float4(In.WorldPosition.xyz, 1), GetViewProjection());
  420. float2 reflectionTexCoord = (0.5 * (hPosition.xy + hPosition.w * float2(1.0, 1.0)) ) / hPosition.w;
  421. reflectionTexCoord += Nn * .2;
  422. float3 reflectionColor = tex2D( SAMPLER(WaterReflectionTexture), reflectionTexCoord.xy );
  423. // the cubemap is in light space so we can bake all lighting calculations to the Cube map
  424. float3 reflVect = -reflect(worldEyeDir,Nn);
  425. // Although not technically correct, since we use the Cubemap to fake specular, multiply against the shadow map and add to color
  426. float shadowMap = (hasShadow) ? shadow( SAMPLER(ShadowMap), In.ShadowMapTexCoord + float4(nDisp.xy * .01,0,0) ):1.0;
  427. float3 envcolor = GammaToLinear(texCUBE( SAMPLER(EnvironmentTexture), reflVect).xyz);
  428. #if defined(EA_PLATFORM_WINDOWS)
  429. // On Windows do the actual foam strength calculation in the pixel shader as it will also work on non-vertex texturing hardware
  430. float2 foamScaleOffset = In.ShroudTexCoord_FoamScaleOffset.zw;
  431. float HeightBlendFactor = heightCenter * foamScaleOffset.x + foamScaleOffset.y;
  432. #else
  433. // On console use the foam strength from the VS
  434. float HeightBlendFactor = In.ShroudTexCoord_FoamScaleOffset.z;
  435. #endif
  436. FoamSamp = pow(FoamSamp,2) * clamp(HeightBlendFactor * .2,.025,3) * DirectionalLight[0].Color;
  437. envcolor.xyz = envcolor.xyz * DirectionalLight[0].Color * fresnelDiffuse * 2 * shadowMap;
  438. // Apply shroud. Don't apply it to the refraction texture's samples, as those are already darkened
  439. float shroud = tex2D( SAMPLER(ShroudSampler), In.ShroudTexCoord_FoamScaleOffset.xy).x;
  440. // Calculate refraction texture
  441. float2 refractionTexCoord = In.Displacement_Refraction.zw;
  442. refractionTexCoord += Nn * .15;
  443. float3 refractionColor = tex2D(SAMPLER(WaterRefractionTexture), refractionTexCoord);
  444. float3 baseColor = tex2D(SAMPLER(WaterRefractionTexture), In.Displacement_Refraction.zw);
  445. // ngavalas
  446. // Because we are just blindly sampling the refraction texture based on a displacement offset
  447. // and because objects are drawn before the water since they can be underwater, we get
  448. // bleeding edges of objects in the water. In order to correct this without sampling the pixel
  449. // depth (requires a depth map which isn't available on medium LOD), we see how different the
  450. // color of the displaced pixel is to that of the NON-displaced pixel. If there is a big difference,
  451. // chances are it's the pixel from an object and we don't want to use that color to computer
  452. // the refraction color. In that case we just use the color of the NON-displaced pixel.
  453. const float maxColorDeltaToUseRefraction = .1;
  454. float colorDelta = distance(refractionColor, baseColor);
  455. float3 waterColor = baseColor;
  456. if (colorDelta < maxColorDeltaToUseRefraction)
  457. {
  458. waterColor = refractionColor;
  459. }
  460. color.xyz = waterColor + shroud * ((reflectionColor * .5) + FoamSamp + envcolor);
  461. return color;
  462. }
  463. // ----------------------------------------------------------------------------
  464. // Technique Medium
  465. // ----------------------------------------------------------------------------
  466. struct VSOutputMedium
  467. {
  468. float4 Position : POSITION;
  469. float4 Color : COLOR0;
  470. float4 nDispTexCoords : TEXCOORD0;
  471. float4 WorldEyeDirection_Normal : TEXCOORD1;
  472. float4 Displacement_Refraction : TEXCOORD2;
  473. float2 ShroudTexCoord : TEXCOORD3;
  474. };
  475. // ----------------------------------------------------------------------------
  476. // Vertex and Pixel/Fragment Shader
  477. // ----------------------------------------------------------------------------
  478. VSOutputMedium VS_MEDIUM(float2 PositionXY : POSITION)
  479. {
  480. VSOutputMedium Out;
  481. float3 worldPosition = ( mul( float4( PositionXY, 0, 1 ), World ) ).xyz;
  482. float WaterPlaneHeight = worldPosition.z;
  483. // -------------------------------------------------------------------------------
  484. // -- MAX Friendly Stuff --------------------------------------------------------
  485. // -------------------------------------------------------------------------------
  486. // MAX and In-game handle time differently, this will allow a more WYSIWYG in Max
  487. #if defined(_3DSMAX_)
  488. OctaveSpeed *= .2;
  489. OctaveDivergenceSpeed *= .2;
  490. #endif
  491. // -------------------------------------------------------------------------------
  492. // -- nDisp Displacment and Mapping -------------------------------------------
  493. // -------------------------------------------------------------------------------
  494. // Build vDisp Tex coords and displace according to Amplitude ----------
  495. OctaveScalar = .0025; // create a more managable number in MAX sliders
  496. OctaveSpeed *= Time * .015; // animate Octave as a multiplier of Time
  497. OctaveDivergenceAngle = 55;
  498. float2 nDispTexCoords = float2(worldPosition.x * OctaveScalar, worldPosition.y * OctaveScalar);
  499. // Build Octave Texture Rotation Matrix And Convert Degrees to Radians --
  500. float cosAngle = 0;
  501. float sinAngle = 0;
  502. float2x2 uvCoordRotate = { 1.0f, 0.0f, 1.0f, 0.0f };
  503. sincos (OctaveDivergenceAngle * .017453, sinAngle, cosAngle);
  504. uvCoordRotate[0][0] = cosAngle;
  505. uvCoordRotate[0][1] = -sinAngle;
  506. uvCoordRotate[1][1] = uvCoordRotate[0][0];
  507. uvCoordRotate[1][0] = -uvCoordRotate[0][1];
  508. // Rotate and Animate vDisp Divergence Texture Coords --------------------
  509. float2 nDispTexCoordsDiverge = mul(nDispTexCoords, uvCoordRotate);
  510. nDispTexCoordsDiverge.x += OctaveSpeed + OctaveSpeed * OctaveDivergenceSpeed;
  511. float2 nDispTexCoordsDivergeInv = mul(nDispTexCoords, transpose(uvCoordRotate));
  512. nDispTexCoordsDivergeInv.x += OctaveSpeed - OctaveSpeed * OctaveDivergenceSpeed;
  513. float waveValue = 0.0;
  514. float waveValueNormal = 0.0;
  515. for(int i=0; i<NWAVES; i++)
  516. {
  517. waveValue = CalculateWave(wave[i], worldPosition.xy, Time);
  518. waveValueNormal += CalculateWaveNormal(wave[i], worldPosition.xy, Time);
  519. worldPosition.z += max(waveValue, 0);
  520. }
  521. worldPosition.z -= 2; // There are too many areas where only on medium the water shows up through very shallow terrain areas. To not have to rework the terrain, we lower the water globally a bit.
  522. // Compute all remaining registers ---------------------------------------
  523. Out.Position = mul(float4(worldPosition, 1), GetViewProjection());
  524. Out.Color = float4(MaterialColorDiffuse.xyz, 1.0);
  525. Out.nDispTexCoords = float4(nDispTexCoordsDiverge, nDispTexCoordsDivergeInv);
  526. Out.WorldEyeDirection_Normal.xyz = normalize(GetEyePosition() - worldPosition);
  527. Out.WorldEyeDirection_Normal.w = waveValueNormal;
  528. Out.Displacement_Refraction.xy = float2(PositionXY.x, 1.0 - PositionXY.y);
  529. Out.Displacement_Refraction.zw = Out.Position.xy / Out.Position.w * 0.5 * float2(1, -1) + 0.5;
  530. Out.ShroudTexCoord = CalculateShroudTexCoord(Shroud, worldPosition);
  531. return Out;
  532. }
  533. float4 PS_MEDIUM(VSOutputMedium In) : COLOR
  534. {
  535. USE_DIRECTIONAL_LIGHT_INTERACTIVE(DirectionalLight, 0);
  536. float4 color = In.Color;
  537. // Calculate surface normals
  538. float3 staticDisplacement = tex2D(SAMPLER(StaticDisplacementTexture), In.nDispTexCoords.xy) * 2 - 1;
  539. staticDisplacement += tex2D(SAMPLER(StaticDisplacementTexture), In.nDispTexCoords.zw) * 2 - 1;
  540. float3 nDisp = normalize(staticDisplacement * .2);
  541. float3 Nn = normalize(nDisp * 50 + (In.WorldEyeDirection_Normal.w * .5));
  542. // the cubemap is in light space so we can bake all lighting calculations to the Cube map
  543. float3 reflVect = -reflect(In.WorldEyeDirection_Normal.xyz,Nn);
  544. float3 envcolor = texCUBE( SAMPLER(EnvironmentTexture), reflVect).xyz;
  545. // Apply shroud. Don't apply it to the refraction texture's samples, as those are already darkened
  546. float shroud = tex2D( SAMPLER(ShroudSampler), In.ShroudTexCoord).x;
  547. // Calculate refraction texture
  548. float2 refractionTexCoord = In.Displacement_Refraction.zw;
  549. refractionTexCoord += Nn * .15;
  550. float3 refractionColor = tex2D(SAMPLER(WaterRefractionTexture), refractionTexCoord);
  551. float3 baseColor = tex2D(SAMPLER(WaterRefractionTexture), In.Displacement_Refraction.zw);
  552. // ngavalas
  553. // Because we are just blindly sampling the refraction texture based on a displacement offset
  554. // and because objects are drawn before the water since they can be underwater, we get
  555. // bleeding edges of objects in the water. In order to correct this without sampling the pixel
  556. // depth (requires a depth map which isn't available on medium LOD), we see how different the
  557. // color of the displaced pixel is to that of the NON-displaced pixel. If there is a big difference,
  558. // chances are it's the pixel from an object and we don't want to use that color to computer
  559. // the refraction color. In that case we just use the color of the NON-displaced pixel.
  560. const float maxColorDeltaToUseRefraction = .15;
  561. float3 colorDelta = refractionColor - baseColor;
  562. float3 waterColor = baseColor;
  563. if (dot(colorDelta, colorDelta) < maxColorDeltaToUseRefraction)
  564. {
  565. waterColor = refractionColor;
  566. }
  567. color.xyz = shroud * ((waterColor * float3(.16, .57, .79)) + envcolor * DirectionalLight[0].Color);
  568. return color;
  569. }
  570. // ----------------------------------------------------------------------------
  571. float4 PS_ULTRAHIGH_Xenon(VSOutputHigh In) : COLOR
  572. {
  573. return PS_ULTRAHIGH( In, HasShadow);
  574. }
  575. #if defined(EA_PLATFORM_PS3)
  576. // ----------------------------------------------------------------------------
  577. float4 PS_ULTRAHIGH_PS3(VSOutputHigh In) : COLOR
  578. {
  579. float4 color = In.Color;
  580. float3 FoamSamp = tex2D(SAMPLER(Foam), In.FoamTexCoords.xy);
  581. FoamSamp *= tex2D(SAMPLER(Foam), In.FoamTexCoords.zw);
  582. color.xyz = FoamSamp;
  583. color.w = 0.6;
  584. float shroud = tex2D( SAMPLER(ShroudSampler), In.ShroudTexCoord).x;
  585. color *= shroud;
  586. return color;
  587. }
  588. #endif // #if defined(EA_PLATFORM_PS3)
  589. DEFINE_ARRAY_MULTIPLIER(PS_Default_Multiplier_NumShadows = 1);
  590. #define PS_CreateWater_NumShadows \
  591. compile PS_3_0 PS_ULTRAHIGH(0), \
  592. compile PS_3_0 PS_ULTRAHIGH(1)
  593. DEFINE_ARRAY_MULTIPLIER(PS_Default_Multiplier_NumShadows_Final = 2*PS_Default_Multiplier_NumShadows);
  594. #if SUPPORTS_SHADER_ARRAYS
  595. pixelshader PS_WaterShadowMap_Array[PS_Default_Multiplier_NumShadows_Final] =
  596. {
  597. PS_CreateWater_NumShadows
  598. };
  599. #endif
  600. // ----------------------------------------------------------------------------
  601. // Technique Low
  602. // ----------------------------------------------------------------------------
  603. struct VSOutputLow
  604. {
  605. float4 Position : POSITION;
  606. float4 Color : COLOR0;
  607. float3 ReflectionDirection : TEXCOORD0;
  608. float4 ShroudTexCoord_Foam : TEXCOORD1;
  609. };
  610. // ----------------------------------------------------------------------------
  611. // Vertex and Pixel/Fragment Shader
  612. // ----------------------------------------------------------------------------
  613. VSOutputLow VS_LOW(float2 PositionXY : POSITION)
  614. {
  615. VSOutputLow Out;
  616. float3 worldPosition = ( mul( float4( PositionXY, 0, 1 ), World ) ).xyz;
  617. // Compute all remaining registers ---------------------------------------
  618. Out.Position = mul(float4(worldPosition, 1), GetViewProjection());
  619. Out.Color = float4(.16, .47, .69, 0.6);
  620. float3 worldEyeDirection = normalize(GetEyePosition() - worldPosition);
  621. Out.ReflectionDirection = -reflect(worldEyeDirection, float3(0,0,1));
  622. Out.ShroudTexCoord_Foam.xy = CalculateShroudTexCoord(Shroud, worldPosition);
  623. Out.ShroudTexCoord_Foam.zw = (worldPosition.xy * .01 - (Time * .05)).yx;
  624. return Out;
  625. }
  626. float4 PS_LOW(VSOutputLow In) : COLOR
  627. {
  628. USE_DIRECTIONAL_LIGHT_INTERACTIVE(DirectionalLight, 0);
  629. // the cubemap is in light space so we can bake all lighting calculations to the Cube map
  630. float3 envcolor = texCUBE( SAMPLER(EnvironmentTexture), In.ReflectionDirection).xyz;
  631. float4 color = float4(In.Color.xyz + (envcolor * DirectionalLight[0].Color), In.Color.w);
  632. float3 FoamSamp = tex2D(SAMPLER(Foam), In.ShroudTexCoord_Foam.wz);
  633. color.xyz += FoamSamp * .2;
  634. // Apply shroud
  635. color.xyz *= tex2D( SAMPLER(ShroudSampler), In.ShroudTexCoord_Foam.xy).x;
  636. return color;
  637. }
  638. // ----------------------------------------------------------------------------
  639. // Technique Definitions
  640. // ----------------------------------------------------------------------------
  641. technique Default
  642. {
  643. pass P0
  644. {
  645. #if defined(EA_PLATFORM_PS3)
  646. VertexShader = compile VS_3_0 VS_HIGH();
  647. PixelShader = ARRAY_EXPRESSION_DIRECT_PS(
  648. PS_WaterShadowMap_Array,
  649. HasShadow*PS_Default_Multiplier_NumShadows,
  650. // Non-array alternative
  651. compile PS_3_0 PS_ULTRAHIGH_PS3()
  652. );
  653. AlphaBlendEnable = true;
  654. SrcBlend = SrcAlpha;
  655. DestBlend = InvSrcAlpha;
  656. #else // #if defined(EA_PLATFORM_PS3)
  657. VertexShader = compile VS_3_0 VS_HIGH();
  658. PixelShader = ARRAY_EXPRESSION_DIRECT_PS(
  659. PS_WaterShadowMap_Array,
  660. HasShadow*PS_Default_Multiplier_NumShadows,
  661. // Non-array alternative
  662. compile PS_3_0 PS_ULTRAHIGH_Xenon()
  663. );
  664. AlphaBlendEnable = false;
  665. #endif // #if defined(EA_PLATFORM_PS3)
  666. ZEnable = true;
  667. ZFunc = ZFUNC_INFRONT;
  668. ZWriteEnable = false;
  669. CullMode = cw;
  670. AlphaTestEnable = false;
  671. }
  672. }
  673. #if ENABLE_LOD
  674. technique Default_M
  675. {
  676. pass P0
  677. {
  678. VertexShader = compile VS_2_0 VS_MEDIUM();
  679. PixelShader = compile PS_2_0 PS_MEDIUM();
  680. ZEnable = true;
  681. ZFunc = ZFUNC_INFRONT;
  682. ZWriteEnable = false;
  683. CullMode = cw;
  684. AlphaTestEnable = false;
  685. AlphaBlendEnable = false;
  686. }
  687. }
  688. technique Default_L
  689. {
  690. pass P0
  691. {
  692. VertexShader = compile VS_2_0 VS_LOW();
  693. PixelShader = compile PS_2_0 PS_LOW();
  694. ZEnable = true;
  695. ZFunc = ZFUNC_INFRONT;
  696. ZWriteEnable = false;
  697. CullMode = cw;
  698. AlphaTestEnable = false;
  699. AlphaBlendEnable = true;
  700. SrcBlend = SrcAlpha;
  701. DestBlend = InvSrcAlpha;
  702. }
  703. }
  704. #endif