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.

372 lines
12 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. // STATIC: "MAGNIFY" "0..1"
  3. // STATIC: "BLUR" "0..1"
  4. // STATIC: "FADEOUTONSILHOUETTE" "0..1"
  5. // STATIC: "CUBEMAP" "0..1"
  6. // STATIC: "REFRACTTINTTEXTURE" "0..1"
  7. // STATIC: "MASKED" "0..1"
  8. // STATIC: "COLORMODULATE" "0..1"
  9. // STATIC: "SECONDARY_NORMAL" "0..1"
  10. // STATIC: "MIRRORABOUTVIEWPORTEDGES" "0..1" [CONSOLE]
  11. // STATIC: "MIRRORABOUTVIEWPORTEDGES" "0..0" [PC]
  12. // STATIC: "SHADER_SRGB_READ" "0..1" [ps20b]
  13. // STATIC: "LOCALREFRACT" "0..1"
  14. #include "common_fog_ps_fxc.h"
  15. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" [ps20b] [PC]
  16. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0" [ps20b] [CONSOLE]
  17. // DYNAMIC: "D_NVIDIA_STEREO" "0..1" [ps20b] [PC]
  18. // DYNAMIC: "D_NVIDIA_STEREO" "0..0" [ps20b] [CONSOLE]
  19. // SKIP: $MASKED && $BLUR
  20. #if defined( SHADER_MODEL_PS_2_0 )
  21. #define WRITE_DEPTH_TO_DESTALPHA 0
  22. #endif
  23. #ifdef _X360
  24. #ifdef SHADER_SRGB_READ
  25. #undef SHADER_SRGB_READ
  26. #endif
  27. #define SHADER_SRGB_READ 1
  28. #endif
  29. #include "common_ps_fxc.h"
  30. #include "shader_constant_register_map.h"
  31. sampler NormalSampler2 : register( s1 );
  32. sampler RefractSampler : register( s2 );
  33. sampler NormalSampler : register( s3 );
  34. #if CUBEMAP
  35. samplerCUBE EnvmapSampler : register( s4 );
  36. #endif
  37. #if REFRACTTINTTEXTURE
  38. sampler RefractTintSampler : register( s5 );
  39. #endif
  40. #if D_NVIDIA_STEREO
  41. sampler StereoParamSampler : register( s6 );
  42. #endif
  43. const float3 g_EnvmapTint : register( c0 );
  44. const float3 g_RefractTint : register( c1 );
  45. const float3 g_EnvmapContrast : register( c2 );
  46. const float3 g_EnvmapSaturation : register( c3 );
  47. const float4 g_NormalizedViewportMinXYMaxWZ : register( c4 );
  48. const float4 g_c5 : register( c5 );
  49. #define g_RefractScale g_c5.x
  50. #define g_flTime g_c5.w
  51. const float4 g_c6 : register( c6 );
  52. #define g_vMagnifyCenter g_c6.xy
  53. #define g_flInverseMagnifyScale g_c6.z
  54. const float3 g_c7 : register( c7 );
  55. #define g_vRefractTextureAspectFixup ( g_c7.xy )
  56. #define g_flRefractDepth ( g_c7.z )
  57. const float4 g_FogParams : register( PSREG_FOG_PARAMS );
  58. const float4 g_EyePos_SpecExponent : register( PSREG_EYEPOS_SPEC_EXPONENT );
  59. static const int g_BlurCount = BLUR;
  60. static const float g_BlurFraction = 1.0f / 512.0f;
  61. static const float g_HalfBlurFraction = 0.5f * g_BlurFraction;
  62. struct PS_INPUT
  63. {
  64. float4 vBumpTexCoord : TEXCOORD0; // NormalMap1 in xy, NormalMap2 in wz
  65. float3 vTangentVertToEyeVector : TEXCOORD1;
  66. float3 vWorldNormal : TEXCOORD2;
  67. float3 vWorldTangent : TEXCOORD3;
  68. float3 vWorldBinormal : TEXCOORD4;
  69. float3 vRefractXYW : TEXCOORD5;
  70. float3 vWorldViewVector : TEXCOORD6;
  71. #if COLORMODULATE
  72. float4 ColorModulate : COLOR0;
  73. #endif
  74. float4 worldPos_projPosZ : TEXCOORD7; // Necessary for pixel fog
  75. };
  76. // NVIDIA's function to convert mono refract UV to the correct stereo UV for each eye
  77. float2 MonoTostereoClipPosXY( float3 vMonoClipPos ) // .z is actually .w
  78. {
  79. #if ( !D_NVIDIA_STEREO )
  80. {
  81. return vMonoClipPos.xy;
  82. }
  83. #else
  84. {
  85. // 0th pixel = 1/16 == 1/16 + 1/8 * 0
  86. float flEyeSep = tex2D( StereoParamSampler, float2( 0.0625f, 0 ) ).x; // 0.19 * 0.1316;
  87. // 1st pixel = 3/16 == 1/16 + 1/8 * 1
  88. float flConvergence = tex2D( StereoParamSampler, float2( 0.1875, 0 ) ).x; // 4;
  89. float3 vStereoClipPos = vMonoClipPos.xyz;
  90. // Undo the stereo transform
  91. vStereoClipPos.x += flEyeSep * ( vMonoClipPos.z - flConvergence );
  92. return vStereoClipPos.xy;
  93. }
  94. #endif
  95. }
  96. float4_color_return_type main( PS_INPUT i ) : COLOR
  97. {
  98. // AlexV - Don't delete this line. I will remove it in a few days.
  99. //i.vBumpTexCoord.x = ( i.vBumpTexCoord.x - 98.0/255.0 ) / ( 158.0/255.0-98.0/255.0 );
  100. float3 vResult;
  101. float flPixelFogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.xyz, i.worldPos_projPosZ.xyz, i.worldPos_projPosZ.w );
  102. float flBlend = 1.0f;
  103. #if ( FADEOUTONSILHOUETTE )
  104. {
  105. //flBlend = -i.projNormal.z;
  106. flBlend = saturate( dot( -i.vWorldViewVector.xyz, i.vWorldNormal.xyz ) );
  107. flBlend = flBlend * flBlend * flBlend;
  108. }
  109. #endif
  110. // Sample normal
  111. float4 vNormalTexel = tex2D( NormalSampler, i.vBumpTexCoord.xy );
  112. float4 vNormalTs = float4( vNormalTexel.xyz * 2.0f - 1.0f, vNormalTexel.a );
  113. #if ( SECONDARY_NORMAL )
  114. {
  115. float3 vNormal2Ts = tex2D( NormalSampler, i.vBumpTexCoord.wz ).xyz * 2.0f - 1.0f;
  116. vNormalTs.xyz = normalize( vNormalTs.xyz + vNormal2Ts.xyz );
  117. }
  118. #endif
  119. #if ( REFRACTTINTTEXTURE )
  120. float3 vRefractTintColor = 2.0 * g_RefractTint * tex2D( RefractTintSampler, i.vBumpTexCoord.xy ).rgb;
  121. #else
  122. float3 vRefractTintColor = g_RefractTint;
  123. #endif
  124. #if ( COLORMODULATE )
  125. {
  126. vRefractTintColor.rgb *= i.ColorModulate.rgb;
  127. }
  128. #endif
  129. // Compute coordinates for sampling refraction
  130. float2 vRefractTexCoordNoWarp = MonoTostereoClipPosXY( i.vRefractXYW.xyz ) / i.vRefractXYW.z; // Divide by w
  131. float2 vRefractTexCoord = vNormalTs.xy; // This normal should be in screen space!
  132. float flScale = vNormalTs.a * g_RefractScale;
  133. #if COLORMODULATE
  134. {
  135. flScale *= i.ColorModulate.a;
  136. }
  137. #endif
  138. vRefractTexCoord.xy *= flScale;
  139. #if ( MAGNIFY )
  140. {
  141. vRefractTexCoord.xy += float2( 0.5, 0.5 ) + float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y );
  142. vRefractTexCoord.xy += ( vRefractTexCoordNoWarp.xy - float2( 0.5, 0.5 ) - float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y ) ) * g_flInverseMagnifyScale;
  143. }
  144. #else
  145. {
  146. vRefractTexCoord.xy += vRefractTexCoordNoWarp.xy;
  147. }
  148. #endif
  149. #if ( MIRRORABOUTVIEWPORTEDGES )
  150. {
  151. //
  152. // need to mirror the texcoords on every border so that one splitscreen viewport doesn't bleed into another one.
  153. //
  154. // mirror on the min viewport in both dimensions
  155. vRefractTexCoord.xy -= g_NormalizedViewportMinXYMaxWZ.xy;
  156. vRefractTexCoord.xy = abs( vRefractTexCoord.xy );
  157. vRefractTexCoord.xy += g_NormalizedViewportMinXYMaxWZ.xy;
  158. // mirror on the max viewport in both dimensions
  159. vRefractTexCoord.xy = g_NormalizedViewportMinXYMaxWZ.wz - vRefractTexCoord.xy;
  160. vRefractTexCoord.xy = abs( vRefractTexCoord.xy );
  161. vRefractTexCoord.xy = g_NormalizedViewportMinXYMaxWZ.wz - vRefractTexCoord.xy;
  162. }
  163. #endif
  164. #if ( BLUR == 0 )
  165. {
  166. #if ( MASKED )
  167. {
  168. float4 vMaskedResult = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy );
  169. return FinalOutput( vMaskedResult, flPixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  170. }
  171. #else
  172. {
  173. float3 vColorWarp = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy ).rgb;
  174. float3 vColorNoWarp = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ).rgb;
  175. vColorWarp.rgb *= vRefractTintColor.rgb;
  176. vResult.rgb = lerp( vColorNoWarp.rgb, vColorWarp.rgb, flBlend );
  177. }
  178. #endif
  179. }
  180. #elif ( BLUR == 1 ) // use polyphase magic to convert 9 lookups into 4
  181. {
  182. // basic principle behind this transformation:
  183. // [ A B C ]
  184. // [ D E F ]
  185. // [ G H I ]
  186. // use bilinear filtering hardware to weight upper 2x2 samples evenly (0.25* [A + B + D + E]).
  187. // scale the upper 2x2 by 4/9 (total area of kernel occupied)
  188. // use bilinear filtering hardware to weight right 1x2 samples evenly (0.5*[C + F])
  189. // scale right 1x2 by 2/9
  190. // use bilinear filtering hardware to weight lower 2x1 samples evenly (0.5*[G + H])
  191. // scale bottom 2x1 by 2/9
  192. // fetch last sample (I) and scale by 1/9.
  193. float2 upper_2x2_loc = vRefractTexCoord.xy - float2( g_HalfBlurFraction, g_HalfBlurFraction );
  194. float2 right_1x2_loc = vRefractTexCoord.xy + float2( g_BlurFraction, -g_HalfBlurFraction );
  195. float2 lower_2x1_loc = vRefractTexCoord.xy + float2( -g_HalfBlurFraction, g_BlurFraction );
  196. float2 singleton_loc = vRefractTexCoord.xy + float2( g_BlurFraction, g_BlurFraction );
  197. vResult.rgb = tex2D( RefractSampler, upper_2x2_loc ).rgb * 0.4444444;
  198. vResult.rgb += tex2D( RefractSampler, right_1x2_loc ).rgb * 0.2222222;
  199. vResult.rgb += tex2D( RefractSampler, lower_2x1_loc ).rgb * 0.2222222;
  200. vResult.rgb += tex2D( RefractSampler, singleton_loc ).rgb * 0.1111111;
  201. #if ( SHADER_SRGB_READ )
  202. {
  203. // Just do this once rather than after every blur step, which is wrong, but much more efficient
  204. if ( IsX360() )
  205. {
  206. #if defined( CSTRIKE15 )
  207. // [mariod] - RT's are all 2.2 gamma in CSTRIKE15
  208. vResult.rgb = GammaToLinear( vResult.rgb );
  209. #else
  210. vResult.rgb = X360GammaToLinear( vResult.rgb );
  211. #endif
  212. }
  213. else
  214. {
  215. vResult.rgb = SrgbGammaToLinear( vResult.rgb );
  216. }
  217. }
  218. #endif
  219. float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ).rgb;
  220. vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb * vRefractTintColor.rgb, flBlend );
  221. }
  222. #elif ( BLUR > 1 ) // iteratively step through render target
  223. {
  224. int x, y;
  225. vResult.rgb = float3( 0.0f, 0.0f, 0.0f );
  226. for ( x = -g_BlurCount; x <= g_BlurCount; x++ )
  227. {
  228. for ( y = -g_BlurCount; y <= g_BlurCount; y++ )
  229. {
  230. vResult.rgb += tex2D( RefractSampler, vRefractTexCoord.xy + float2( g_BlurFraction * x, g_BlurFraction * y ) ).rgb;
  231. }
  232. }
  233. #if ( SHADER_SRGB_READ )
  234. {
  235. // Just do this once rather than after every blur step, which is wrong, but much more efficient
  236. if ( IsX360() )
  237. {
  238. #if defined( CSTRIKE15 )
  239. // [mariod] - RT's are all 2.2 gamma in CSTRIKE15
  240. vResult.rgb = GammaToLinear( vResult.rgb );
  241. #else
  242. vResult.rgb = X360GammaToLinear( vResult.rgb );
  243. #endif
  244. }
  245. else
  246. {
  247. vResult.rgb = SrgbGammaToLinear( vResult.rgb );
  248. }
  249. }
  250. #endif
  251. int nWidth = g_BlurCount * 2 + 1;
  252. vResult.rgb *= 1.0f / ( nWidth * nWidth );
  253. // vResult is the blurred one now. . .now lerp.
  254. float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy );
  255. vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb * vRefractTintColor.rgb, flBlend );
  256. }
  257. #endif
  258. #if ( LOCALREFRACT )
  259. {
  260. float2 vTexCoord = i.vBumpTexCoord.xy;
  261. // The interpolaged tangent space vert to eye vector isn't good enough, so compute a higher quality vector here
  262. float3 vVertexToEyeDirWs = g_EyePos_SpecExponent.xyz - i.worldPos_projPosZ.xyz;
  263. float3 vVertexToEyeDirTs = Vec3WorldToTangentNormalized( vVertexToEyeDirWs.xyz, i.vWorldNormal.xyz, i.vWorldTangent.xyz, i.vWorldBinormal.xyz );
  264. //float3 vRefractTs = refract( -vVertexToEyeDirTs.xyz, vNormalTs.xyz, 0.66 );
  265. float3 vRefractTs = vVertexToEyeDirTs.xyz; // Just use the vert to eye vector as the refract vector
  266. float flRDotN = -vRefractTs.z; // This is R.GeometricNormal, so just use tangent z
  267. float2 vRefractedUv = vRefractTs.xy / flRDotN;
  268. vRefractedUv.xy += vNormalTs.xy;
  269. vRefractedUv.xy += ( 1.0f - vNormalTs.z ) * vRefractTs.xy / flRDotN;
  270. vRefractedUv.xy *= g_vRefractTextureAspectFixup.xy * g_flRefractDepth;
  271. // Original uv's
  272. vRefractedUv.xy += vTexCoord.xy;
  273. float4 vRefract = tex2Dsrgb( RefractSampler, saturate( vRefractedUv.xy ) );
  274. float4 vRefract2 = tex2Dsrgb( RefractSampler, saturate( vTexCoord.xy + vNormalTs.xy*0.1 ) );
  275. vRefract.rgb = lerp( vRefract.rgb, vRefract2.aaa, 0.025 );
  276. float flFresnel = pow( vNormalTs.z, 3.0f );
  277. vResult.rgb = vRefract.rgb * flFresnel * vRefractTintColor.rgb;
  278. float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vTexCoord.xy ).rgb;
  279. vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb, flBlend );
  280. }
  281. #endif
  282. #if ( CUBEMAP )
  283. {
  284. float3 vNormalWs = Vec3TangentToWorld( vNormalTs.xyz, i.vWorldNormal.xyz, i.vWorldTangent.xyz, i.vWorldBinormal.xyz );
  285. float3 vReflectRayWs = CalcReflectionVectorUnnormalized( vNormalWs.xyz, i.vTangentVertToEyeVector.xyz );
  286. float3 vSpecularLighting = ENV_MAP_SCALE * texCUBE( EnvmapSampler, vReflectRayWs.xyz ).rgb;
  287. // Spec mask
  288. float flSpecularMask = vNormalTs.a;
  289. vSpecularLighting.rgb *= flSpecularMask;
  290. // Tint
  291. vSpecularLighting.rgb *= g_EnvmapTint.rgb;
  292. // Contrast
  293. float3 vSpecularLightingSquared = vSpecularLighting.rgb * vSpecularLighting.rgb;
  294. vSpecularLighting.rgb = lerp( vSpecularLighting.rgb, vSpecularLightingSquared.rgb, g_EnvmapContrast );
  295. // Saturation
  296. float3 vSpecularLuminance = dot( vSpecularLighting.rgb, float3( 0.299f, 0.587f, 0.114f ) );
  297. vSpecularLighting.rgb = lerp( vSpecularLuminance.rgb, vSpecularLighting.rgb, g_EnvmapSaturation );
  298. // Fresnel
  299. float flNdotV = saturate( dot( vNormalTs.xyz, i.vTangentVertToEyeVector.xyz ) );
  300. float g_flReflectance = 0.6f;
  301. float flFresnel = g_flReflectance + ( ( 1.0f - g_flReflectance ) * pow( 1.0f - flNdotV, 1.0f ) );
  302. vResult.rgb += vSpecularLighting.rgb * flFresnel;
  303. }
  304. #endif
  305. #if ( COLORMODULATE )
  306. float flResultAlpha = i.ColorModulate.a * vNormalTs.a;
  307. #else
  308. float flResultAlpha = vNormalTs.a;
  309. #endif
  310. return FinalOutput( float4( vResult, flResultAlpha ), flPixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE, ( WRITE_DEPTH_TO_DESTALPHA != 0 ), i.worldPos_projPosZ.w );
  311. }