Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

716 lines
25 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. // STATIC: "BASETEXTURE" "0..1"
  3. // STATIC: "MULTITEXTURE" "0..1"
  4. // STATIC: "REFLECT" "0..1"
  5. // STATIC: "REFRACT" "0..1"
  6. // STATIC: "ABOVEWATER" "0..1"
  7. // STATIC: "FLOWMAP" "0..1" [ps20b]
  8. // STATIC: "FLOWMAP" "0..0" [ps20] [ = 0; ]
  9. // STATIC: "FLOW_DEBUG" "0..2"
  10. // STATIC: "FLASHLIGHT" "0..1" [ps20b]
  11. // STATIC: "FLASHLIGHT" "0..0" [ps20] [ = 0; ]
  12. // STATIC: "LIGHTMAPWATERFOG" "0..1" [ps20b]
  13. // STATIC: "LIGHTMAPWATERFOG" "0..0" [ps20] [ = 0; ]
  14. // STATIC: "FORCEFRESNEL" "0..1"
  15. // STATIC: "SIMPLEOVERLAY" "0..1"
  16. // DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" [ps20b]
  17. // DYNAMIC: "FLASHLIGHTSHADOWS" "0..0" [ps20] [ = 0; ]
  18. // DYNAMIC: "BUILDWORLDIMPOSTER" "0..1" [ = r_buildingmapforworld.GetBool() ? 1 : 0 ]
  19. // Multitexture and basetexture are mutually exclusive.
  20. // SKIP: $MULTITEXTURE && $BASETEXTURE
  21. // SKIP: $SIMPLEOVERLAY && $BASETEXTURE
  22. // SKIP: $SIMPLEOVERLAY && !$FLOWMAP
  23. // flowmap doesn't play with multitexture
  24. // SKIP: $FLOWMAP && $MULTITEXTURE
  25. // Have to have the flashlight on to get flashlightshadows.
  26. // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 )
  27. // basetexture doesn't work with flashlight or lightmapwaterfog. multitexture doesn't either. We don't use basetexture or multitexture in newer code and instead use flowmap and flashlight.
  28. // SKIP: ( $FLASHLIGHT || $LIGHTMAPWATERFOG ) && ( ( $BASETEXTURE && !$FLOWMAP ) || $MULTITEXTURE )
  29. #if defined( _PS3 ) || defined ( _X360 )
  30. #define DEPTH_EDGE_FEATHERING 1
  31. #endif
  32. #ifdef _X360
  33. #define SHADER_SRGB_READ 1
  34. #endif
  35. #include "common_ps_fxc.h"
  36. #include "common_fog_ps_fxc.h"
  37. #include "shader_constant_register_map.h"
  38. #include "common_flashlight_fxc.h"
  39. #if REFRACT
  40. sampler RefractSampler : register( s0 );
  41. #endif
  42. #if REFLECT
  43. sampler ReflectSampler : register( s1 );
  44. #else
  45. sampler EnvSampler : register( s1 );
  46. #endif
  47. sampler NormalSampler : register( s2 );
  48. sampler LightmapSampler : register( s3 );
  49. #if BASETEXTURE
  50. sampler BaseTextureSampler : register( s10 );
  51. #endif
  52. #if SIMPLEOVERLAY
  53. sampler SimpleOverlaySampler : register( s11 );
  54. #endif
  55. #if FLOWMAP
  56. sampler FlowmapSampler : register( s4 );
  57. sampler FlowNoiseSampler : register( s5 );
  58. #endif
  59. #if FLASHLIGHT
  60. sampler FlashlightSampler : register( s6 );
  61. sampler ShadowDepthSampler : register( s7 );
  62. sampler RandRotSampler : register( s8 );
  63. #if defined(_PS3)
  64. // Needed for optimal shadow filter code generation on PS3.
  65. #pragma texformat ShadowDepthSampler DEPTH_COMPONENT24
  66. #endif
  67. #endif
  68. #if DEPTH_EDGE_FEATHERING
  69. sampler DepthSampler : register( s9 );
  70. #endif
  71. const float4 g_vRefractTint : register( c1 );
  72. const float4 g_vReflectTint : register( c4 );
  73. #define g_flWaterBlendFactor (g_vReflectTint.a)
  74. const float4 g_ReflectRefractScale : register( c5 ); // xy - reflect scale, zw - refract scale
  75. const float4 g_WaterFogColor : register( c6 );
  76. const float4 g_WaterFogParams : register( c7 );
  77. #define g_WaterFogStart g_WaterFogParams.x
  78. #define g_WaterFogEndMinusStart g_WaterFogParams.y
  79. #define g_Reflect_OverBright g_WaterFogParams.z
  80. const float g_flTime : register( c8 );
  81. #if FLOWMAP
  82. const float2 g_vFlowScrollRate : register( c9 );
  83. #endif
  84. // The flashlight on the water surface is basically the diffuse flashlight * waterfogcolor * g_flFlashlightTint.
  85. // g_flFlashlightTint is tweakable in cases where the water fog color is really dark and the flashlight doesn't show up, etc.
  86. const float3 g_flFlashlightTint : register( c10 );
  87. const float4 g_PixelFogParams : register( PSREG_FOG_PARAMS ); // c12
  88. const float3 g_EyePos : register( PSREG_EYEPOS_SPEC_EXPONENT ); // c11
  89. const float4 g_vFlowParams1 : register( c13 );
  90. #define g_flWorldUvScale ( g_vFlowParams1.x ) // 1.0f / 10.0f
  91. #define g_flNormalUvScale ( g_vFlowParams1.y ) // 1.0f / 1.15f
  92. #define g_flBumpStrength ( g_vFlowParams1.z ) // 3.0f
  93. #define g_flDisplaceStrength ( g_vFlowParams1.w ) // 0.025f // Amount to displace the color fetch based on the normals
  94. const float3 g_vFlowParams2 : register( c14 );
  95. #define g_flFlowTimeIntervalInSeconds ( g_vFlowParams2.x ) // 0.4f // Number of seconds to lerp from texture 1 to texture 2
  96. #define g_flFlowUvScrollDistance ( g_vFlowParams2.y ) // 0.25f // Distance in uv space to fetch
  97. #define g_flNoiseScale ( g_vFlowParams2.z )
  98. const float4 g_vColorFlowParams1 : register( c26 );
  99. #define g_flColorFlowUvScale ( g_vColorFlowParams1.x ) // 1.0f / 1.15f
  100. #define g_flColorFlowTimeIntervalInSeconds ( g_vColorFlowParams1.y ) // 0.4f // Number of seconds to lerp from texture 1 to texture 2
  101. #define g_flColorFlowUvScrollDistance ( g_vColorFlowParams1.z ) // 0.25f // Distance in uv space to fetch
  102. #define g_flColorFlowLerpExp ( g_vColorFlowParams1.w )
  103. const float4 g_FlashlightAttenuationFactors : register( c15 );
  104. const float3 g_FlashlightPos : register( c16 );
  105. const float4x4 g_FlashlightWorldToTexture : register( c17 ); // through c20
  106. const float4 g_vShadowTweaks : register( c21 );
  107. // These constants are used to rotate the world space water normals around the up axis to align the
  108. // normal with the camera and then give us a 2D offset vector to use for reflection and refraction uv's
  109. const float3 g_vWorldToViewWater0 : register( c22 );
  110. const float3 g_vWorldToViewWater1 : register( c23 );
  111. float4 g_vInvViewportTransform : register( c24 );
  112. const float g_flForcedFresnelValue : register( c25 );
  113. #if DEPTH_EDGE_FEATHERING
  114. const float4 g_ProjToWorldZW[2] : register( c33 );
  115. const float4 g_DepthEdgeFeatheringParams : register( c35 );
  116. #endif
  117. struct PS_INPUT
  118. {
  119. float2 vBumpTexCoord : TEXCOORD0;
  120. float3 vPositionToCameraRayWs : TEXCOORD1;
  121. float4 vReflectXY_vRefractYX : TEXCOORD2;
  122. float4 vProjPos : TEXCOORD3;
  123. float3 worldPos : TEXCOORD4;
  124. #if FLASHLIGHT
  125. float4 flashlightSpacePos : TEXCOORD5;
  126. #endif
  127. #if MULTITEXTURE
  128. float4 vExtraBumpTexCoord : TEXCOORD5;
  129. #endif
  130. #if ( BASETEXTURE && !FLOWMAP )
  131. float4 lightmapTexCoord1And2 : TEXCOORD5_centroid;
  132. float2 lightmapTexCoord3 : TEXCOORD6_centroid;
  133. #endif
  134. #if LIGHTMAPWATERFOG
  135. float2 lightmapTexCoord : TEXCOORD7_centroid;
  136. #endif
  137. #if defined( _X360 )
  138. float2 vScreenPos : VPOS;
  139. #endif
  140. };
  141. float2 UnpackNormal2D( float2 vNormal )
  142. {
  143. return ( ( vNormal.xy * 2.0 ) - 1.0 );
  144. }
  145. float3 UnpackNormal3D( float3 vNormal )
  146. {
  147. return ( ( vNormal.xyz * 2.0 ) - 1.0 );
  148. }
  149. float3 ComputeNormalFromXY( float2 vXY )
  150. {
  151. float3 vNormalTs;
  152. vNormalTs.xy = vXY.xy;
  153. vNormalTs.z = sqrt( saturate( 1.0 - dot( vNormalTs.xy, vNormalTs.xy ) ) );
  154. return vNormalTs.xyz;
  155. }
  156. float3 ComputeNormalFromRGTexture( float2 vRGPixel )
  157. {
  158. float3 vNormalTs;
  159. vNormalTs.xy = UnpackNormal2D( vRGPixel.rg );
  160. vNormalTs.z = sqrt( saturate( 1.0 - dot( vNormalTs.xy, vNormalTs.xy ) ) );
  161. return vNormalTs.xyz;
  162. }
  163. // Turning off 32bit lightmaps on Portal 2 to save shader perf. --Thorsten
  164. //#define USE_32BIT_LIGHTMAPS_ON_360 //uncomment to use 32bit lightmaps, be sure to keep this in sync with the same #define in materialsystem/cmatlightmaps.cpp
  165. float3 LightMapSample( sampler LightmapSampler, float2 vTexCoord )
  166. {
  167. #if ( !defined( _X360 ) || !defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  168. {
  169. float3 sample = tex2D( LightmapSampler, vTexCoord ).rgb;
  170. return sample;
  171. }
  172. #else
  173. {
  174. #if 0 //1 for cheap sampling, 0 for accurate scaling from the individual samples
  175. {
  176. float4 sample = tex2D( LightmapSampler, vTexCoord );
  177. return sample.rgb * sample.a;
  178. }
  179. #else
  180. {
  181. float4 Weights;
  182. float4 samples_0; //no arrays allowed in inline assembly
  183. float4 samples_1;
  184. float4 samples_2;
  185. float4 samples_3;
  186. asm {
  187. tfetch2D samples_0, vTexCoord.xy, LightmapSampler, OffsetX = -0.5, OffsetY = -0.5, MinFilter=point, MagFilter=point, MipFilter=keep, UseComputedLOD=false
  188. tfetch2D samples_1, vTexCoord.xy, LightmapSampler, OffsetX = 0.5, OffsetY = -0.5, MinFilter=point, MagFilter=point, MipFilter=keep, UseComputedLOD=false
  189. tfetch2D samples_2, vTexCoord.xy, LightmapSampler, OffsetX = -0.5, OffsetY = 0.5, MinFilter=point, MagFilter=point, MipFilter=keep, UseComputedLOD=false
  190. tfetch2D samples_3, vTexCoord.xy, LightmapSampler, OffsetX = 0.5, OffsetY = 0.5, MinFilter=point, MagFilter=point, MipFilter=keep, UseComputedLOD=false
  191. getWeights2D Weights, vTexCoord.xy, LightmapSampler
  192. };
  193. Weights = float4( (1-Weights.x)*(1-Weights.y), Weights.x*(1-Weights.y), (1-Weights.x)*Weights.y, Weights.x*Weights.y );
  194. float3 result;
  195. result.rgb = samples_0.rgb * (samples_0.a * Weights.x);
  196. result.rgb += samples_1.rgb * (samples_1.a * Weights.y);
  197. result.rgb += samples_2.rgb * (samples_2.a * Weights.z);
  198. result.rgb += samples_3.rgb * (samples_3.a * Weights.w);
  199. return result;
  200. }
  201. #endif
  202. }
  203. #endif
  204. }
  205. float3 PosToColor( float3 vScenePositionWs )
  206. {
  207. int ix = vScenePositionWs.x / 15.0f;
  208. int iy = vScenePositionWs.y / 15.0f;
  209. float3 cColor;
  210. if ( frac( iy / 2.0f ) )
  211. {
  212. if ( frac( ix / 2.0f ) )
  213. {
  214. cColor = float3( 1.0f, 0.0f, 0.0f );
  215. }
  216. else
  217. {
  218. cColor = float3( 0.0f, 1.0f, 0.0f );
  219. }
  220. }
  221. else
  222. {
  223. if ( frac( ix / 2.0f ) )
  224. {
  225. cColor = float3( 0.0f, 1.0f, 0.0f );
  226. }
  227. else
  228. {
  229. cColor = float3( 1.0f, 0.0f, 0.0f );
  230. }
  231. }
  232. return cColor;
  233. }
  234. float4_color_return_type main( PS_INPUT i ) : COLOR
  235. {
  236. float4 vResult;
  237. float flFogFactor;
  238. /* For debugging - Flash all water surfaces blue
  239. vResult.rgba = float4( 0.25, 0.25, 1.0, 0 ) * ( ( floor( g_flTime * 2.0f ) % 2 ) * 0.9f + 0.1f );
  240. flFogFactor = 0;
  241. return FinalOutput( float4( vResult.rgb, 1.0f ), flFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  242. //*/
  243. // Compute coordinates for sampling Reflection
  244. float3 vPositionToCameraDirWs = normalize( i.vPositionToCameraRayWs.xyz );
  245. float4 vNormalWs;
  246. float4 vFlowColor = float4( 0.0f, 0.0f, 0.0f, 0.0f );
  247. #if ( FLOWMAP )
  248. {
  249. float flWorldUvScale = g_flWorldUvScale;
  250. float flNormalUvScale = g_flNormalUvScale;
  251. float flFlowTimeIntervalInSeconds = g_flFlowTimeIntervalInSeconds;
  252. float flFlowUvScrollDistance = g_flFlowUvScrollDistance;
  253. float flBumpStrength = g_flBumpStrength;
  254. float flNoiseScale = g_flNoiseScale;
  255. // Input uv
  256. float2 vWorldUv = i.vBumpTexCoord.xy * flWorldUvScale;
  257. float2 vUv1 = float2( i.worldPos.x, -i.worldPos.y ) * flNormalUvScale;
  258. float2 vUv2 = vUv1.xy;
  259. // Noise texture is used to offset the time interval different spatially so we don't see pulsing
  260. float flNoise = tex2D( FlowNoiseSampler, float2( i.worldPos.x, -i.worldPos.y ) * flNoiseScale ).g;
  261. // Flow texel has a 2D flow vector in the rg channels of the texture
  262. float4 vFlowTexel = tex2D( FlowmapSampler, vWorldUv.xy );
  263. #if ( FLOW_DEBUG == 1 ) // Flow vectors
  264. {
  265. vResult.rgba = float4( pow( vFlowTexel.rgb, 2.2f ), 0 );
  266. flFogFactor = 0;
  267. return FinalOutput( float4( vResult.rgb, 1.0f ), flFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  268. }
  269. #elif ( FLOW_DEBUG == 2 ) // Noise
  270. {
  271. vResult.rgba = pow( flNoise, 2.2 );
  272. flFogFactor = 0;
  273. return FinalOutput( float4( vResult.rgb, 1.0f ), flFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  274. }
  275. #endif
  276. // Unpack world flow vector from texture
  277. float2 vFlowVectorTs = ( vFlowTexel.rg * 2.0f ) - 1.0f;
  278. float flTimeInIntervals = ( g_flTime / ( flFlowTimeIntervalInSeconds * 2.0f ) ) + flNoise;
  279. float flScrollTime1 = frac( flTimeInIntervals );
  280. float flScrollTime2 = frac( flTimeInIntervals + 0.5f ); // Half an interval off from texture 1
  281. // Every interval has a unique offset so we don't see the same bump texels repeating continuously
  282. float flOffset1 = floor( flTimeInIntervals ) * 0.311f;
  283. float flOffset2 = floor( flTimeInIntervals + 0.5f ) * 0.311f + 0.5f; // The +0.5 is to match the phase offset
  284. // Final flow uv is originalUv + interval offset + ( flowvector * scroll
  285. float2 vFlowUv1 = vUv1.xy + flOffset1 + ( flScrollTime1 * ( flFlowUvScrollDistance * vFlowVectorTs.xy ) );
  286. float2 vFlowUv2 = vUv2.xy + flOffset2 + ( flScrollTime2 * ( flFlowUvScrollDistance * vFlowVectorTs.xy ) );
  287. // Lerp values to blend between the two layers of bump
  288. float flWeight1 = abs( ( 2.0f * frac( flTimeInIntervals + 0.5f ) ) - 1.0f );
  289. float flWeight2 = abs( ( 2.0f * frac( flTimeInIntervals ) ) - 1.0f );
  290. float4 vNormalTexel1 = tex2D( NormalSampler, vFlowUv1.xy );
  291. float4 vNormalTexel2 = tex2D( NormalSampler, vFlowUv2.xy );
  292. float3 vNormal1 = ( vNormalTexel1.rgb );
  293. float3 vNormal2 = ( vNormalTexel2.rgb );
  294. // Combine both layers
  295. vNormalWs.xy = UnpackNormal2D( lerp( vNormal1.xy, vNormal2.xy, flWeight2 ) );
  296. // Change bump strength based on the length of the flow vector
  297. //vNormalWs.xy *= ( length( vFlowVectorTs.xy ) + 0.05f ) * flBumpStrength;
  298. vNormalWs.xy *= ( ( vFlowVectorTs.x * vFlowVectorTs.x + vFlowVectorTs.y * vFlowVectorTs.y ) + 0.1f ) * flBumpStrength;
  299. // Generate normal from 2D scaled normal
  300. vNormalWs.xyz = ComputeNormalFromXY( vNormalWs.xy );
  301. //return pow( float4( vNormalWs.xy*0.5+0.5, 0, 0), 2.2);
  302. //vResult.rgba = float4( SrgbGammaToLinear( vNormalWs.xyz * 0.5 + 0.5 ), 0 );
  303. //flFogFactor = 0;
  304. //return FinalOutput( float4( vResult.rgb, 1.0f ), flFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  305. vNormalWs.a = 1.0f;
  306. //-------------------------------------------------------------//
  307. // Specifying a base texture with flow gives us a sludge layer //
  308. //-------------------------------------------------------------//
  309. #if ( BASETEXTURE )
  310. {
  311. float flParallaxIntensity = lerp( vNormalTexel1.a, vNormalTexel2.a, flWeight2 );
  312. flParallaxIntensity *= g_flDisplaceStrength;
  313. float2 vParallaxDirWs = vPositionToCameraDirWs.xy - vNormalWs.xy;
  314. float2 vColorUv = ( float2( i.worldPos.x, -i.worldPos.y ) )* g_flColorFlowUvScale + vParallaxDirWs * flParallaxIntensity;
  315. float flTimeInIntervals = ( g_flTime / ( g_flColorFlowTimeIntervalInSeconds * 2.0f ) ) + flNoise;
  316. float flScrollTime1 = frac( flTimeInIntervals ) - 0.5;
  317. float flScrollTime2 = frac( flTimeInIntervals + 0.5f ) - 0.5; // Half an interval off from texture 1
  318. float flOffset1 = floor( flTimeInIntervals ) * 0.311f;
  319. float flOffset2 = floor( flTimeInIntervals + 0.5f ) * 0.311f + 0.5f; // The +0.5 is to match the phase offset
  320. float2 vColorFlowUv1 = vColorUv.xy + flOffset1 + ( flScrollTime1 * ( g_flColorFlowUvScrollDistance * vFlowVectorTs.xy ) );
  321. float2 vColorFlowUv2 = vColorUv.xy + flOffset2 + ( flScrollTime2 * ( g_flColorFlowUvScrollDistance * vFlowVectorTs.xy ) );
  322. float flWeight1 = pow( abs( ( 2.0f * frac( flTimeInIntervals + 0.5f ) ) - 1.0f ), g_flColorFlowLerpExp );
  323. float flWeight2 = pow( abs( ( 2.0f * frac( flTimeInIntervals ) ) - 1.0f ), g_flColorFlowLerpExp );
  324. float4 vColorTexel1 = tex2Dsrgb( BaseTextureSampler, vColorFlowUv1.xy );
  325. float4 vColorTexel2 = tex2Dsrgb( BaseTextureSampler, vColorFlowUv2.xy );
  326. vFlowColor.rgba = vColorTexel1.rgba * flWeight1;
  327. vFlowColor.rgba += vColorTexel2.rgba * flWeight2;
  328. vFlowColor.rgba *= vFlowTexel.a; // Mask color flow by alpha of flowmap
  329. }
  330. #endif
  331. }
  332. #elif ( MULTITEXTURE )
  333. {
  334. vNormalWs.xyz = tex2D( NormalSampler, i.vBumpTexCoord ).xyz;
  335. float3 vNormalWs1 = tex2D( NormalSampler, i.vExtraBumpTexCoord.xy ).xyz;
  336. float3 vNormalWs2 = tex2D( NormalSampler, i.vExtraBumpTexCoord.zw ).xyz;
  337. vNormalWs.xyz = 0.33 * ( vNormalWs.xyz + vNormalWs1.xyz + vNormalWs2.xyz );
  338. vNormalWs.xyz = 2.0 * vNormalWs.xyz - 1.0;
  339. vNormalWs.a = 1.0f;
  340. }
  341. #else
  342. {
  343. vNormalWs.xyzw = DecompressNormal( NormalSampler, i.vBumpTexCoord, NORM_DECODE_NONE );
  344. }
  345. #endif
  346. // Perform division by W only once
  347. float flOoW = 1.0f / i.vProjPos.w;
  348. float2 unwarpedRefractTexCoord = i.vReflectXY_vRefractYX.wz * flOoW;
  349. // Deal with the viewport transform. We don't do splitscreen on PC, so don't bother doing this with PS20.
  350. unwarpedRefractTexCoord = g_vInvViewportTransform.zw + unwarpedRefractTexCoord * g_vInvViewportTransform.xy;
  351. #if ( ABOVEWATER && REFRACT )
  352. float4 unwarpedSample = tex2Dsrgb( RefractSampler, unwarpedRefractTexCoord );
  353. float waterFogDepthValue = unwarpedSample.a;
  354. #else
  355. // We don't actually have valid depth values in alpha when we are underwater looking out, so
  356. // just set to farthest value.
  357. float waterFogDepthValue = 1.0f;
  358. #endif
  359. float4 vReflectRefractScale = g_ReflectRefractScale;
  360. #if !BASETEXTURE
  361. vReflectRefractScale *= waterFogDepthValue;
  362. #endif
  363. // vectorize the dependent UV calculations (reflect = .xy, refract = .wz)
  364. float4 vN;
  365. vN.x = dot( g_vWorldToViewWater0.xyz, vNormalWs.xyz );
  366. vN.y = dot( g_vWorldToViewWater1.xyz, vNormalWs.xyz );
  367. vN.wz = vN.xy;
  368. float4 vDependentTexCoords = vN.xyzw * vNormalWs.a * vReflectRefractScale;
  369. vDependentTexCoords += i.vReflectXY_vRefractYX * flOoW;
  370. float2 vReflectTexCoord = vDependentTexCoords.xy;
  371. float2 vRefractTexCoord = vDependentTexCoords.wz;
  372. float4 vReflectColor;
  373. #if ( REFLECT )
  374. {
  375. vReflectColor.rgba = tex2Dsrgb( ReflectSampler, vReflectTexCoord );
  376. }
  377. #else
  378. {
  379. float3 vReflectWs = CalcReflectionVectorUnnormalized( vNormalWs.xyz, vPositionToCameraDirWs.xyz );
  380. vReflectColor.rgba = ENV_MAP_SCALE * texCUBE( EnvSampler, vReflectWs.xyz );
  381. }
  382. #endif
  383. vReflectColor *= g_vReflectTint;
  384. float4 vRefractColor;
  385. #if REFRACT
  386. #if defined( _X360 )
  387. {
  388. // deal with the viewport transform for splitscreen
  389. vRefractColor = tex2Dsrgb( RefractSampler, g_vInvViewportTransform.zw + vRefractTexCoord * g_vInvViewportTransform.xy );
  390. }
  391. #else
  392. {
  393. vRefractColor = tex2Dsrgb( RefractSampler, vRefractTexCoord );
  394. }
  395. #endif
  396. float warpedAlpha = vRefractColor.a;
  397. // get the depth value from the refracted sample to be used for fog.
  398. #if ABOVEWATER
  399. // Don't mess with this in the underwater case since we don't really have
  400. // depth values there.
  401. waterFogDepthValue = vRefractColor.a;
  402. #endif
  403. #endif
  404. // Fresnel term
  405. float fFresnel;
  406. #if FORCEFRESNEL
  407. {
  408. fFresnel = g_flForcedFresnelValue;
  409. }
  410. #else
  411. {
  412. float flNdotV = saturate( dot( vPositionToCameraDirWs.xyz, vNormalWs.xyz ) );
  413. float g_flReflectance = 0.2f;
  414. fFresnel = g_flReflectance + ( ( 1.0f - g_flReflectance ) * pow( 1.0f - flNdotV, 5.0f ) );
  415. }
  416. #endif
  417. // Light maps
  418. float3 vLightmapColor = float3( 1.0f, 1.0f, 1.0f );
  419. float4 vLightmappedWaterFogColor = g_WaterFogColor;
  420. #if LIGHTMAPWATERFOG
  421. {
  422. float3 lightmapSample = LightMapSample( LightmapSampler, i.lightmapTexCoord.xy );
  423. vLightmapColor.rgb = lightmapSample * LIGHT_MAP_SCALE * LINEAR_LIGHT_SCALE;
  424. vLightmappedWaterFogColor.xyz *= vLightmapColor.rgb;
  425. }
  426. #endif
  427. // blend between refraction and fog color.
  428. #if ABOVEWATER
  429. #if REFRACT
  430. // Avoid seeing things in front of the water warped in the water refraction by not warping when that case happens.
  431. // Causes a bit of artifacting around foreground objects, but looks better than warping the foreground objects in the water surface.
  432. if ( warpedAlpha < 0.05f )
  433. {
  434. vRefractColor.xyz = unwarpedSample.xyz;
  435. waterFogDepthValue = unwarpedSample.w;
  436. }
  437. #endif
  438. #if REFRACT
  439. float edgeFadeFactor = saturate( 3.5 * waterFogDepthValue );
  440. vRefractColor = lerp( vRefractColor, vRefractColor * g_vRefractTint, edgeFadeFactor );
  441. #endif
  442. #if ( !defined( SHADER_MODEL_PS_2_0 ) )
  443. {
  444. vReflectColor *= saturate( 2.0 * waterFogDepthValue );
  445. }
  446. #endif
  447. #if REFRACT
  448. vRefractColor = lerp( vRefractColor, vLightmappedWaterFogColor, waterFogDepthValue );
  449. #endif
  450. #endif
  451. // Flashlight
  452. float3 vDiffuseLight = vLightmapColor.rgb;
  453. #if ( FLASHLIGHT )
  454. {
  455. float3 vFlashlightDiffuseLighting = DoFlashlight( g_FlashlightPos, i.worldPos.xyz, i.flashlightSpacePos.xyzw, vNormalWs.xyz,
  456. g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w, FlashlightSampler, ShadowDepthSampler,
  457. RandRotSampler, 0, FLASHLIGHTSHADOWS, i.vProjPos.xy / i.vProjPos.w, false, g_vShadowTweaks );
  458. #if ( ABOVEWATER && REFRACT )
  459. {
  460. vFlashlightDiffuseLighting *= edgeFadeFactor;
  461. }
  462. #endif
  463. vDiffuseLight.xyz += g_flFlashlightTint * vFlashlightDiffuseLighting.xyz * LINEAR_LIGHT_SCALE;
  464. }
  465. #endif
  466. #if !BASETEXTURE
  467. {
  468. // fFresnel == 1.0f means full reflection
  469. #if ( REFRACT )
  470. {
  471. fFresnel *= saturate( ( waterFogDepthValue - 0.05f ) * 20.0f );
  472. }
  473. #endif
  474. }
  475. #endif
  476. #if ( BASETEXTURE && !FLOWMAP )
  477. float4 baseSample = tex2D( BaseTextureSampler, i.vBumpTexCoord.xy );
  478. float2 bumpCoord1;
  479. float2 bumpCoord2;
  480. float2 bumpCoord3;
  481. ComputeBumpedLightmapCoordinates( i.lightmapTexCoord1And2, i.lightmapTexCoord3.xy,
  482. bumpCoord1, bumpCoord2, bumpCoord3 );
  483. float4 lightmapSample1 = tex2D( LightmapSampler, bumpCoord1 );
  484. float3 lightmapColor1 = lightmapSample1.rgb;
  485. float3 lightmapColor2 = tex2D( LightmapSampler, bumpCoord2 ).rgb;
  486. float3 lightmapColor3 = tex2D( LightmapSampler, bumpCoord3 ).rgb;
  487. float3 dp;
  488. dp.x = saturate( dot( vNormalWs.xyz, bumpBasis[0] ) );
  489. dp.y = saturate( dot( vNormalWs.xyz, bumpBasis[1] ) );
  490. dp.z = saturate( dot( vNormalWs.xyz, bumpBasis[2] ) );
  491. dp *= dp;
  492. float3 diffuseLighting = dp.x * lightmapColor1 +
  493. dp.y * lightmapColor2 +
  494. dp.z * lightmapColor3;
  495. float sum = dot( dp, float3( 1.0f, 1.0f, 1.0f ) );
  496. diffuseLighting *= LIGHT_MAP_SCALE / sum;
  497. float3 diffuseComponent = baseSample.rgb * diffuseLighting;
  498. #endif
  499. // The underwater color will be reused for the flashlight
  500. float3 vUnderWater = g_WaterFogColor.rgb; // Default to fog color, but may be overridden below
  501. #if ( REFLECT && REFRACT )
  502. {
  503. #if ( BASETEXTURE && FLOWMAP )
  504. {
  505. float3 vLight = vDiffuseLight.rgb;
  506. // The alpha of flow color represents translucency from 0.0-0.5. The range 0.5-1.0 allows pixels to float above the water
  507. float3 vSludge = vFlowColor.rgb * vLight.rgb;
  508. vUnderWater.rgb = lerp( vRefractColor.rgb, vSludge.rgb, saturate( vFlowColor.a * 2.0f ) );
  509. float flSludgeAboveWater = smoothstep( 0.5f, 0.7f, vFlowColor.a );
  510. vResult.rgb = lerp( vUnderWater.rgb, vReflectColor.rgb, saturate( fFresnel * ( 1.0f - flSludgeAboveWater ) ) );
  511. //vUnderWater.rgb *= 1.0f - fFresnel; // I don't think this is necessary since the flashlight applies a cosine term
  512. }
  513. #else
  514. {
  515. vResult = vRefractColor + ( fFresnel * vReflectColor );
  516. }
  517. #endif
  518. }
  519. #elif ( REFRACT )
  520. {
  521. vResult = vRefractColor + ( fFresnel * vReflectColor );
  522. }
  523. #else
  524. {
  525. #if ( BASETEXTURE && FLOWMAP )
  526. {
  527. float3 vLight = vDiffuseLight.rgb;
  528. // The alpha of flow color represents translucency from 0.0-0.5. The range 0.5-1.0 allows pixels to float above the water
  529. float3 vSludge = vFlowColor.rgb * vLight.rgb;
  530. vUnderWater.rgb = lerp( vLightmappedWaterFogColor.rgb, vSludge.rgb, saturate( vFlowColor.a * 2.0f ) );
  531. float flSludgeAboveWater = smoothstep( 0.5f, 0.7f, vFlowColor.a );
  532. vResult.rgb = lerp( vUnderWater.rgb, vReflectColor.rgb, saturate( fFresnel * ( 1.0f - flSludgeAboveWater ) ) );
  533. #if ( BUILDWORLDIMPOSTER )
  534. {
  535. vResult.rgb = vUnderWater.rgb;
  536. }
  537. #endif
  538. //vUnderWater.rgb *= 1.0f - fFresnel; // I don't think this is necessary since the flashlight applies a cosine term
  539. }
  540. #elif ( BASETEXTURE )
  541. {
  542. vResult = float4( diffuseComponent, 1.0f ) + vReflectColor * fFresnel * baseSample.a;
  543. }
  544. #else
  545. {
  546. vResult = lerp( vLightmappedWaterFogColor, vReflectColor, fFresnel );
  547. }
  548. #endif
  549. }
  550. #endif
  551. #if ( SIMPLEOVERLAY )
  552. float4 simpleOverlayComponent = tex2D( SimpleOverlaySampler, i.vBumpTexCoord );
  553. vResult.rgb = lerp( vResult.rgb, simpleOverlayComponent.rgb * vLightmapColor, simpleOverlayComponent.a * saturate( ( waterFogDepthValue - 0.01f ) * 5.0f ) );
  554. #endif
  555. #if ( PIXELFOGTYPE == PIXEL_FOG_TYPE_RANGE )
  556. {
  557. flFogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_PixelFogParams, g_EyePos, i.worldPos, i.vProjPos.z );
  558. }
  559. #else
  560. {
  561. flFogFactor = 0;
  562. }
  563. #endif
  564. float flWaterBlendAlpha = 1.0f;
  565. #if ( DEPTH_EDGE_FEATHERING )
  566. {
  567. float2 vDepthSampleCoords = i.vReflectXY_vRefractYX.wz * flOoW;
  568. float2 vViewportRelativeDepthSampleCoords = g_vInvViewportTransform.zw + vDepthSampleCoords * g_vInvViewportTransform.xy;
  569. // Sample the scene's depth at the current fragment.
  570. float flSceneProjZ = SampleHardwareDepth( DepthSampler, vViewportRelativeDepthSampleCoords );
  571. // Compute current fragment's projection/clip space coords.
  572. float2 vClipUv = ( ( 2.0f * vDepthSampleCoords.xy ) - float2( 1.0f, 1.0f ) ) * float2( 1.0f, -1.0f );
  573. float4 vProjPos = float4( vClipUv.x, vClipUv.y, flSceneProjZ, 1.0f );
  574. // Recover worldspace Z and W.
  575. float vSceneWorldZ = dot( vProjPos, g_ProjToWorldZW[0] );
  576. float vSceneWorldW = dot( vProjPos, g_ProjToWorldZW[1] );
  577. // Project to W=1.
  578. vSceneWorldZ /= vSceneWorldW;
  579. // We now have the worldspace Z's of the current fragment and the surface below it.
  580. // Subtract the current water surface's height from the computed worldspace Z (height) to compute edge feathing factor.
  581. flWaterBlendAlpha = i.worldPos.z - vSceneWorldZ;
  582. flWaterBlendAlpha = saturate( saturate( g_DepthEdgeFeatheringParams.x * flWaterBlendAlpha ) + g_DepthEdgeFeatheringParams.y );
  583. }
  584. #endif
  585. float4_color_return_type vOutput = FinalOutput( float4( vResult.rgb, g_flWaterBlendFactor * flWaterBlendAlpha ), flFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  586. #if ( defined( _X360 ) )
  587. {
  588. vOutput.rgb += ScreenSpaceOrderedDither( i.vScreenPos );
  589. vOutput.rgb = LinearToGamma( vOutput.rgb ); // Simulate the sRGB write here since FinalOutupt() above skips this call with TONEMAP_SCALE_NONE
  590. }
  591. #endif
  592. return vOutput;
  593. }