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.

739 lines
28 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. // STATIC: "MASKS1" "0..1"
  3. // STATIC: "MASKS2" "0..1"
  4. // STATIC: "FRESNELRANGESTEXTURE" "0..1"
  5. // STATIC: "PHONGWARPTEXTURE" "0..1" [ps30]
  6. // STATIC: "ENVMAP" "0..1"
  7. // STATIC: "AMBIENTREFLECTION" "0..1"
  8. // STATIC: "USEBOUNCECOLOR" "0..1" [ps30]
  9. // STATIC: "ANISOTROPY" "0..1" [ps30]
  10. // STATIC: "BASEALPHAPHONGMASK" "0..1" [ps30]
  11. // STATIC: "BASEALPHAENVMASK" "0..1"
  12. // STATIC: "BUMPALPHAENVMASK" "0..1"
  13. // STATIC: "SHADOWSATURATION" "0..1" [ps30]
  14. // STATIC: "BASEALPHASELFILLUMMASK" "0..1"
  15. // STATIC: "FAKERIM" "0..1"
  16. // STATIC: "CASCADED_SHADOW_MAPPING" "0..1" [ps30]
  17. // STATIC: "CSM_MODE" "0..3" [ps30]
  18. // STATIC: "DOPREVIEW" "0..1"
  19. // STATIC: "USEPATTERN" "0..4"
  20. // STATIC: "FLASHLIGHT" "0..1"
  21. // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..3"
  22. // DYNAMIC: "NUM_LIGHTS" "0..4" [ps30]
  23. // DYNAMIC: "DYN_CSM_ENABLED" "0..1"
  24. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0"
  25. // DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1"
  26. #include "common_fog_ps_fxc.h"
  27. // SKIP: ( $AMBIENTREFLECTION == 0 ) && ( $USEBOUNCECOLOR == 1 )
  28. // SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $ENVMAP == 0 )
  29. // SKIP: ( $BUMPALPHAENVMASK == 1 ) && ( $ENVMAP == 0 )
  30. // SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $BUMPALPHAENVMASK == 1 )
  31. // SKIP: ( $BASEALPHASELFILLUMMASK == 1) && ( $BASEALPHAENVMASK == 1 )
  32. // SKIP: ( $BASEALPHASELFILLUMMASK == 1) && ( $BASEALPHAPHONGMASK == 1 )
  33. // SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $BASEALPHASELFILLUMMASK )
  34. // SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $DYN_CSM_ENABLED == 1 )
  35. // SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $CSM_MODE != 0 )
  36. // SKIP: ( $DOPREVIEW == 0 ) && ( $USEPATTERN != 0 )
  37. // SKIP: ( $DOPREVIEW == 1 ) && ( $USEBOUNCECOLOR == 1 )
  38. // SKIP: ( $DOPREVIEW == 1 ) && ( $BASEALPHASELFILLUMMASK == 1)
  39. // SKIP: ( $DOPREVIEW == 1 ) && ( $FAKERIM == 1 )
  40. // SKIP: ( $DOPREVIEW == 1 ) && ( $CSM_MODE > 0 )
  41. // SKIP: ( $DOPREVIEW == 1 ) && ( $DYN_CSM_ENALBED == 1 )
  42. // SKIP: ( $DOPREVIEW == 1 ) && ( $NUM_LIGHTS > 1 )
  43. // SKIP: ( $DOPREVIEW == 1 ) && ( $FLASHLIGHT == 1 )
  44. // SKIP: ( $CASCADED_SHADOW_MAPPING > 0) && ( $FLASHLIGHT == 1 )
  45. // SKIP: ( $DYN_CSM_ENALBED == 1 ) && ( $FLASHLIGHT == 1 )
  46. // SKIP: ( $CSM_MODE > 0 ) && ( $FLASHLIGHT == 1 )
  47. // SKIP: ( $FLASHLIGHTDEPTHFILTERMODE > 0 ) && ( $FLASHLIGHT == 0 )
  48. // SKIP: ( $FLASHLIGHT == 1 ) && ( $FAKERIM == 1 )
  49. #define PHONG 1
  50. #define RIMLIGHT 1
  51. #define BUMPMAP 1
  52. #define HALFLAMBERT 0
  53. #include "common_ps_fxc.h"
  54. #include "shader_constant_register_map.h"
  55. #if ( DOPREVIEW == 1 )
  56. #define GENERATEBASETEXTURE 1
  57. #if ( BUMPMAP == 1 )
  58. #define GENERATENORMAL 1
  59. #endif
  60. #if( MASKS1 == 1 )
  61. #define GENERATEMASKS1 1
  62. #endif
  63. #define CHEAPFILTERING 1
  64. #include "custom_character_fxc.h"
  65. #endif
  66. sampler BaseTextureSampler : register( s0 );
  67. sampler NormalMapSampler : register( s1 );
  68. #if ( DOPREVIEW == 1 )
  69. sampler Masks1Sampler : register( s2 );
  70. #else
  71. sampler Masks1Sampler : register( s10 );
  72. #endif
  73. sampler Masks2Sampler : register( s3 );
  74. sampler FresnelRangesSampler : register( s4 );
  75. sampler NormalizeSampler : register( s5 );
  76. sampler EnvmapSampler : register( s6 );
  77. sampler PhongWarpSampler : register( s7 );
  78. #if ( FLASHLIGHT == 1 )
  79. #include "common_flashlight_fxc.h"
  80. sampler FlashlightSampler : register( s8 );
  81. sampler ShadowDepthSampler : register( s11 );
  82. #else
  83. sampler CSMDepthAtlasSampler : register( s8 );
  84. #endif
  85. //#undef CASCADED_SHADOW_MAPPING
  86. //#define CASCADED_SHADOW_MAPPING 1
  87. #if ( CASCADED_SHADOW_MAPPING == 1 )
  88. #define CASCADE_SIZE 3
  89. #define CSM_ENABLED 1
  90. #include "csm_common_fxc.h"
  91. #endif
  92. const float4 g_vBounceTerms : register( c0 );
  93. #define g_cBounce g_vBounceTerms.rgb
  94. #define g_fAmbientBounceBoost g_vBounceTerms.w
  95. const float4 g_vDiffuseModulation : register( c1 );
  96. const float4 g_vDiffuseTerms : register( c101 );
  97. #define g_fEnvmapLightScale g_vDiffuseTerms.x
  98. #define g_fShadowSaturation g_vDiffuseTerms.y
  99. #define g_fMetalness g_vDiffuseTerms.z
  100. #define g_fRimLightAlbedo g_vDiffuseTerms.w
  101. const float4 g_vShadowSaturationBounds : register( c2 );
  102. const float3 g_vEyePos : register( c3 );
  103. const float3 g_cAmbientCube[6] : register( PSREG_AMBIENT_CUBE ); // (c4-c9)
  104. const float4 g_vPhongTerms : register( c10 );
  105. #define g_fPhongBoost g_vPhongTerms.x
  106. #define g_fPhongAlbedoBoost g_vPhongTerms.y
  107. #define g_fPhongExponent g_vPhongTerms.z
  108. #define g_fAnisotropyAmount g_vPhongTerms.w
  109. const float4 g_vPhongTint_ShadowRimBoost : register( c11 );
  110. #define g_cPhongTint g_vPhongTint_ShadowRimBoost.rgb
  111. #define g_fShadowRimBoost g_vPhongTint_ShadowRimBoost.w
  112. const float3 g_vFresnelRanges : register( c12 );
  113. const float4 g_cShadowTint : register( c102 );
  114. const float4 g_vEnvmapTerm : register( c103 );
  115. #define g_vEnvmapLightScaleMin g_vEnvmapTerm.xxx
  116. #define g_vEnvmapLightScaleMax g_vEnvmapTerm.yyy
  117. #define g_fEnvmapContrast g_vEnvmapTerm.z
  118. #define g_fEnvmapSaturation g_vEnvmapTerm.w
  119. const float3 g_cEnvmapTint : register( c104 );
  120. const float4 g_vRimTerms_SelfIllumTerms : register( c105 );
  121. #define g_fRimLightExponent g_vRimTerms_SelfIllumTerms.x
  122. #define g_fRimLightBoost g_vRimTerms_SelfIllumTerms.y
  123. #define g_fSelfIllumBoost g_vRimTerms_SelfIllumTerms.z
  124. #define g_fWarpIndex g_vRimTerms_SelfIllumTerms.w
  125. const float4 g_cRimLightTint_fRimHaloBoost : register( c106 );
  126. #define g_cRimLightTint g_cRimLightTint_fRimHaloBoost.xyz
  127. #define g_fRimHaloBoost g_cRimLightTint_fRimHaloBoost.w
  128. const float4 g_vFakeRimTint_ShadowScale : register( c107 );
  129. #define g_cFakeRimTint g_vFakeRimTint_ShadowScale.rgb
  130. #define g_fShadowScale g_vFakeRimTint_ShadowScale.w
  131. const float4 g_FogParams : register( c19 );
  132. PixelShaderLightInfo g_cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // (c20-c25)
  133. const float4 g_vRimHaloBounds : register( c33 );
  134. //const float4 cFlashlightColor : register( PSREG_FLASHLIGHT_COLOR ); // c28 - 31
  135. const float4 g_FlashlightAttenuationFactors : register( PSREG_FLASHLIGHT_ATTENUATION );
  136. const float4 g_FlashlightPos_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
  137. #define g_FlashlightPos g_FlashlightPos_RimBoost.xyz
  138. const float4x4 g_FlashlightWorldToTexture : register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE );
  139. const float4 g_vShadowTweaks : register( c109 );
  140. #define g_fRetroReflectivityBoost 5.0f
  141. #define g_fRetroReflectivityPower 4.0f
  142. struct PS_INPUT
  143. {
  144. float4 vTexCoord0 : TEXCOORD0;
  145. float4 lightAtten : TEXCOORD1;
  146. float4 tangentSpaceTranspose0_FakeRimx : TEXCOORD2; // when flashlight is on, the .w components
  147. float4 tangentSpaceTranspose1_FakeRimy : TEXCOORD3; // hold the projection position
  148. float4 tangentSpaceTranspose2_FakeRimz : TEXCOORD4; // instead of rim params
  149. float4 vWorldPos_projZ : TEXCOORD5;
  150. float4 cAmbient_fRimBoost : TEXCOORD6;
  151. #if defined( SHADER_MODEL_PS_3_0 )
  152. float4 vWorldTangentS_vBounceCenterx : TEXCOORD7;
  153. float4 vWorldTangentT_vBounceCentery : TEXCOORD8;
  154. float4 vBounceCenterDir_vBounceCenterz : TEXCOORD9;
  155. #endif
  156. };
  157. float3 saturateColor( float3 c1, float fsat )
  158. {
  159. float3 finalColor = c1;
  160. if ( fsat != 0 )
  161. {
  162. // perceptual luminance
  163. float3 lum = float3( 0.299, 0.587, 0.114 );
  164. float3 c2 = pow( c1, 4 );
  165. float luminance1 = dot( c1, lum );
  166. if ( fsat < 0 )
  167. {
  168. finalColor = lerp( c1, luminance1, -fsat );
  169. }
  170. else
  171. {
  172. float luminance2 = dot( c2, lum );
  173. luminance2 = max( luminance2, 0.000001f );
  174. c2 = c2 * luminance1 / luminance2;
  175. finalColor = lerp( c1, c2, fsat );
  176. }
  177. }
  178. return finalColor;
  179. }
  180. float3 tintColor( float3 c1, float3 tint, float amt )
  181. {
  182. // perceptual luminance
  183. float3 lum = float3( 0.299, 0.587, 0.114 );
  184. float3 c2 = tint;
  185. float luminance1 = dot( c1, lum );
  186. float luminance2 = dot( c2, lum );
  187. luminance2 = max( luminance2, 0.000001f );
  188. c2 = c2 * luminance1 / luminance2 ;
  189. return lerp( c1, c2, amt );
  190. }
  191. void CharacterSpecularAndRimTerms( const float3 vWorldNormal, const float3 vLightDir, const float fSpecularExponent, const float3 vEyeDir,
  192. const bool bDoSpecularWarp, in sampler specularWarpSampler,
  193. const float3 color, const bool bDoRimLighting, const float fRimExponent, const float fWarpIndex,
  194. const bool bDoAnisotropy, const float fAnisoAmount, const float VdotT, const float sVdotT, const float vTangent,
  195. const bool bDoRetroReflectivity, const float fRetroReflectivityAmount, const float fRetroReflectivityFresnel,
  196. // Outputs
  197. out float3 specularLighting, out float3 rimLighting, out float rimHalo )
  198. {
  199. float3 vHalfAngle = normalize( vEyeDir.xyz + vLightDir.xyz );
  200. float flNDotH = saturate( dot( vWorldNormal.xyz, vHalfAngle.xyz ) );
  201. float flNDotL = saturate( dot( vWorldNormal, vLightDir ) );
  202. specularLighting = float3( 0.0f, 0.0f, 0.0f );
  203. if ( bDoAnisotropy )
  204. {
  205. float LdotT = dot( vLightDir, vTangent );
  206. float sLdotT = sqrt( 1 - LdotT * LdotT );
  207. float anisotropicSpecular = saturate( VdotT * LdotT + sVdotT * sLdotT );
  208. /*if ( bDoSpecularWarp )
  209. {
  210. anisotropicSpecular = pow( anisotropicSpecular, 16.0f ); // need to raise it to a power to keep anisotropic feel, otherwise the falloff is too abrupt
  211. }*/
  212. flNDotH = lerp( flNDotH, anisotropicSpecular, fAnisoAmount );
  213. }
  214. // Optionally warp as function of scalar specular
  215. if ( bDoSpecularWarp )
  216. {
  217. specularLighting = tex2D( specularWarpSampler, float2( flNDotH, fWarpIndex ) ).rgb;
  218. }
  219. else
  220. {
  221. specularLighting = pow( flNDotH, fSpecularExponent );
  222. }
  223. if ( bDoRetroReflectivity )
  224. {
  225. float flVDotL = saturate( dot( vEyeDir.xyz, vLightDir.xyz ) );
  226. specularLighting = lerp( specularLighting, fRetroReflectivityFresnel * flVDotL * g_fRetroReflectivityBoost, fRetroReflectivityAmount );
  227. }
  228. specularLighting *= pow( flNDotL, 0.5 );
  229. specularLighting *= color; // Modulate with light color
  230. // Optionally do rim lighting
  231. rimLighting = float3( 0.0, 0.0, 0.0 );
  232. rimHalo = 0;
  233. if ( bDoRimLighting )
  234. {
  235. float flNDotV = 1.0f - saturate( dot( vWorldNormal.xyz, vEyeDir.xyz ) );
  236. rimHalo = flNDotH * flNDotL;
  237. rimHalo *= pow( flNDotV, fRimExponent );
  238. rimHalo *= pow( flNDotL, 0.5 );
  239. rimLighting = rimHalo * color;
  240. }
  241. }
  242. void CharacterDoSpecularLighting( const float3 worldPos, const float3 vWorldNormal, const float fSpecularExponent, const float3 vEyeDir,
  243. const float4 lightAtten, const int nNumLights, PixelShaderLightInfo cLightInfo[3],
  244. const bool bDoSpecularWarp, in sampler specularWarpSampler,
  245. const bool bDoRimLighting, const float fRimExponent, const float flDirectShadow, const float fWarpIndex,
  246. const bool bDoAnisotropy, const float fAnisoAmount, const float fAnisotropyAngle,
  247. const float3 vTangent,
  248. const bool bDoRetroReflectivity, const float fRetroReflectivityAmount, const float3 ambient,
  249. // Outputs
  250. out float3 specularLighting, out float3 rimLighting, out float rimHalo )
  251. {
  252. specularLighting = rimLighting = float3( 0.0f, 0.0f, 0.0f );
  253. rimHalo = 0.0f;
  254. float3 localSpecularTerm, localRimTerm = float3( 0.0f, 0.0f, 0.0f );
  255. float localRimHalo = 0.0f;
  256. float flVDotN = 0.0f;
  257. if ( bDoRetroReflectivity )
  258. {
  259. flVDotN = saturate( dot( vWorldNormal.xyz, vEyeDir.xyz ) );
  260. flVDotN = pow( flVDotN, g_fRetroReflectivityPower );
  261. specularLighting += fRetroReflectivityAmount * flVDotN * ambient * g_fRetroReflectivityBoost;
  262. }
  263. float VdotT = 1;
  264. float sVdotT = 1;
  265. if ( bDoAnisotropy )
  266. {
  267. VdotT = dot( vEyeDir, vTangent );
  268. sVdotT = sqrt( 1 - VdotT * VdotT );
  269. }
  270. if( nNumLights > 0 )
  271. {
  272. // First local light will always be forced to a directional light in CS:GO (see CanonicalizeMaterialLightingState() in shaderapidx8.cpp) - it may be completely black.
  273. CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 0 ), fSpecularExponent, vEyeDir,
  274. bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 0 ) * lightAtten[0],
  275. bDoRimLighting, fRimExponent, fWarpIndex,
  276. bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
  277. bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
  278. localSpecularTerm, localRimTerm, localRimHalo );
  279. specularLighting += localSpecularTerm * flDirectShadow; // Accumulate specular and rim terms
  280. rimLighting += localRimTerm * flDirectShadow;
  281. rimHalo += localRimHalo;
  282. }
  283. if( nNumLights > 1 )
  284. {
  285. CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 1 ), fSpecularExponent, vEyeDir,
  286. bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 1 ) * lightAtten[1],
  287. bDoRimLighting, fRimExponent, fWarpIndex,
  288. bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
  289. bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
  290. localSpecularTerm, localRimTerm, localRimHalo );
  291. specularLighting += localSpecularTerm; // Accumulate specular and rim terms
  292. rimLighting += localRimTerm;
  293. rimHalo += localRimHalo;
  294. }
  295. if( nNumLights > 2 )
  296. {
  297. CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 2 ), fSpecularExponent, vEyeDir,
  298. bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 2 ) * lightAtten[2],
  299. bDoRimLighting, fRimExponent, fWarpIndex,
  300. bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
  301. bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
  302. localSpecularTerm, localRimTerm, localRimHalo );
  303. specularLighting += localSpecularTerm; // Accumulate specular and rim terms
  304. rimLighting += localRimTerm;
  305. rimHalo += localRimHalo;
  306. }
  307. if( nNumLights > 3 )
  308. {
  309. CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 3 ), fSpecularExponent, vEyeDir,
  310. bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 3 ) * lightAtten[3],
  311. bDoRimLighting, fRimExponent, fWarpIndex,
  312. bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
  313. bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
  314. localSpecularTerm, localRimTerm, localRimHalo );
  315. specularLighting += localSpecularTerm; // Accumulate specular and rim terms
  316. rimLighting += localRimTerm;
  317. rimHalo += localRimHalo;
  318. }
  319. }
  320. float3 desaturateColor( float3 c1 )
  321. {
  322. // perceptual luminance
  323. float3 lum = float3( 0.299, 0.587, 0.114 );
  324. return dot( c1, lum );
  325. }
  326. // ======================= MAIN ======================= //
  327. float4_color_return_type main( PS_INPUT i ) : COLOR
  328. {
  329. float4 vBaseTextureSample = tex2D( BaseTextureSampler, i.vTexCoord0.xy );
  330. #if ( MASKS1 )
  331. float4 vMasks1Params = tex2D( Masks1Sampler, i.vTexCoord0.xy );
  332. #else
  333. float4 vMasks1Params = float4( 1.0f, 0.0f, 1.0f, 0.0f );
  334. #endif
  335. #if ( BUMPMAP )
  336. float4 vNormalSample = tex2D( NormalMapSampler, i.vTexCoord0.xy );
  337. #else
  338. float4 vNormalSample = float4( 0.0f, 0.0f, 1.0f, 1.0f );
  339. #endif
  340. #if ( DOPREVIEW )
  341. customizeCharacter( i.vTexCoord0.xy, vBaseTextureSample, vNormalSample, vMasks1Params );
  342. #endif
  343. float fAlpha = vBaseTextureSample.a;
  344. float3 cBase = vBaseTextureSample.rgb;
  345. float fSpecMask = 1.0f;
  346. float fEnvMask = 1.0f;
  347. float fSelfIllumMask = 0.0f;
  348. #if ( BASEALPHAPHONGMASK == 1 )
  349. fSpecMask = vBaseTextureSample.a;
  350. fAlpha = 1.0f;
  351. #endif
  352. #if ( BASEALPHAENVMASK == 1 )
  353. fEnvMask = vBaseTextureSample.a;
  354. fAlpha = 1.0f;
  355. #endif
  356. #if ( BASEALPHASELFILLUMMASK == 1 )
  357. fSelfIllumMask = vBaseTextureSample.a;
  358. #endif
  359. float fRimMask = 1.0f;
  360. float fMetalnessMask = 1.0f;
  361. float fPhongAlbedoMask = 0.0f;
  362. float fWarpIndex = g_fWarpIndex;
  363. #if ( MASKS1 )
  364. {
  365. fRimMask = vMasks1Params.r;
  366. fPhongAlbedoMask = vMasks1Params.g;
  367. fMetalnessMask = vMasks1Params.b;
  368. fWarpIndex = vMasks1Params.a;
  369. }
  370. #else
  371. fMetalnessMask = g_fMetalness;
  372. #endif
  373. float3 vTangentNormal = float3( 0.0f, 0.0f, 1.0f );
  374. #if ( BUMPMAP )
  375. {
  376. vTangentNormal = vNormalSample.xyz * 2.0f - 1.0f;
  377. #if ( BASEALPHAPHONGMASK == 0 )
  378. fSpecMask = vNormalSample.a;
  379. #endif
  380. #if ( BUMPALPHAENVMASK )
  381. fEnvMask = vNormalSample.a;
  382. #endif
  383. }
  384. #endif
  385. float3x3 mTangentSpaceTranspose = float3x3( i.tangentSpaceTranspose0_FakeRimx.xyz, i.tangentSpaceTranspose1_FakeRimy.xyz, i.tangentSpaceTranspose2_FakeRimz.xyz );
  386. float3 vWorldNormal = normalize( mul( mTangentSpaceTranspose, vTangentNormal ) );
  387. float3 vEyeDir = normalize( g_vEyePos - i.vWorldPos_projZ.xyz );
  388. #if ( FRESNELRANGESTEXTURE )
  389. float fFresnel = saturate( dot( vEyeDir, vWorldNormal ) );
  390. float3 vFresnelParams = tex2D( FresnelRangesSampler, float2( fFresnel, fWarpIndex ) );
  391. fFresnel = vFresnelParams.y;
  392. float fAmbientReflectionMask = vFresnelParams.z * fRimMask;
  393. #else
  394. float fFresnel = Fresnel( vWorldNormal, vEyeDir, g_vFresnelRanges );
  395. float fAmbientReflectionMask = fFresnel * fRimMask;
  396. #endif
  397. float fCSMShadow = 1.0f;
  398. #if ( CASCADED_SHADOW_MAPPING && DYN_CSM_ENABLED ) && defined( SHADER_MODEL_PS_3_0 )
  399. fCSMShadow = CSMComputeShadowing( i.vWorldPos_projZ.xyz );
  400. #endif
  401. float3 linearLightColor = PixelShaderDoLighting( i.vWorldPos_projZ.xyz, vWorldNormal,
  402. float3( 0.0f, 0.0f, 0.0f), false,
  403. true, i.lightAtten, g_cAmbientCube,
  404. NormalizeSampler, NUM_LIGHTS, g_cLightInfo, ( HALFLAMBERT == 1 ),
  405. false, NULL, fCSMShadow );
  406. float fShadowSaturationMask = 1.0f;
  407. float fAnisotropyAmount = g_fAnisotropyAmount;
  408. float fAnisotropyAngle = 1.57;
  409. float fRetroReflectivityMask = 0.0f;
  410. float fEnvmapLightScale = g_fEnvmapLightScale;
  411. #if ( MASKS2 )
  412. float4 vMasks2Params = tex2D( Masks2Sampler, i.vTexCoord0.xy );
  413. fShadowSaturationMask *= vMasks2Params.x;
  414. fAnisotropyAmount *= ( vMasks2Params.g > 0 );
  415. fAnisotropyAngle = vMasks2Params.g * 3.14159;
  416. fEnvmapLightScale *= vMasks2Params.b;
  417. fRetroReflectivityMask = 1.0f - vMasks2Params.a;
  418. #endif
  419. float3 cSpecularLight = float3( 0.0f, 0.0f, 0.0f );
  420. float3 cRimLight = float3( 0.0f, 0.0f, 0.0f );
  421. float3 cAdditiveRimlight = float3( 0.0f, 0.0f, 0.0f );
  422. float3 vTangent = float3( 0.0f, 0.0f, 0.0f );
  423. float3 vReflectionEyeVec = vEyeDir;
  424. float fRimHalo = 0;
  425. #if ( FLASHLIGHT )
  426. float4 flashlightSpacePosition = TransformFlashlightWorldToTexture( i.vWorldPos_projZ.xyz, g_FlashlightWorldToTexture );
  427. float3 vProjPos = float3( i.tangentSpaceTranspose0_FakeRimx.w, i.tangentSpaceTranspose1_FakeRimy.w, i.tangentSpaceTranspose2_FakeRimz.w );
  428. float3 vProjCoords = flashlightSpacePosition.xyz / flashlightSpacePosition.w;
  429. float2 vScreenPos = vProjPos.xy / vProjPos.z;
  430. bool bShadows = true;
  431. linearLightColor += DoFlashlight( g_FlashlightPos, i.vWorldPos_projZ.xyz, flashlightSpacePosition, vWorldNormal,
  432. g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w, FlashlightSampler, ShadowDepthSampler,
  433. NormalizeSampler, FLASHLIGHTDEPTHFILTERMODE, bShadows,
  434. vProjCoords.xy, false, g_vShadowTweaks, true );
  435. #if ( PHONG )
  436. float3 cSpecularFlashlight = float3( 0.0f, 0.0f, 0.0f );
  437. float3 flashlightColor = tex2D( FlashlightSampler, vProjCoords.xy ).rgb;
  438. flashlightColor *= flashlightSpacePosition.www > float3(0,0,0);
  439. float3 vFlashlightDir = g_FlashlightPos - i.vWorldPos_projZ.xyz;
  440. float distSquared = dot( vFlashlightDir, vFlashlightDir );
  441. float dist = sqrt( distSquared );
  442. float fAtten = saturate( dot( g_FlashlightAttenuationFactors.xyz, float3( 1.0f, 1.0f/dist, 1.0f/distSquared ) ) );
  443. vFlashlightDir = normalize( vFlashlightDir );
  444. float endFalloffFactor = RemapNormalizedValClamped( dist, g_FlashlightAttenuationFactors.w, 0.6f * g_FlashlightAttenuationFactors.w );
  445. flashlightColor *= fAtten * endFalloffFactor * cFlashlightColor;
  446. float VdotT = 0;
  447. float sVdotT = 0;
  448. float NdotL = dot( vFlashlightDir, vWorldNormal );
  449. if ( bShadows )
  450. {
  451. float flShadow = DoFlashlightShadow( ShadowDepthSampler, NormalizeSampler, vProjCoords.xyz, vScreenPos, FLASHLIGHTDEPTHFILTERMODE, g_vShadowTweaks, NdotL );
  452. float flAttenuated = lerp( flShadow, 1.0f, g_vShadowTweaks.y ); // Blend between fully attenuated and not attenuated
  453. flShadow = saturate( lerp( flAttenuated, flShadow, fAtten ) ); // Blend between shadow and above, according to light attenuation
  454. flashlightColor *= flShadow; // Shadow term
  455. }
  456. if ( ANISOTROPY == 1 )
  457. {
  458. VdotT = dot( vEyeDir, vTangent );
  459. sVdotT = sqrt( 1 - VdotT * VdotT );
  460. }
  461. CharacterSpecularAndRimTerms( vWorldNormal, vFlashlightDir, g_fPhongExponent, vEyeDir,
  462. ( PHONGWARPTEXTURE == 1 ), PhongWarpSampler,
  463. flashlightColor, false, g_fRimLightExponent, fWarpIndex,
  464. ( ANISOTROPY == 1 ), fAnisotropyAmount, VdotT, sVdotT, vTangent,
  465. false, 0, 0, // TODO: enable retroreflectivity with flashlight
  466. // Outputs
  467. cSpecularFlashlight, cAdditiveRimlight, fRimHalo );
  468. #endif
  469. #endif
  470. #if ( FAKERIM )
  471. {
  472. float3 localRimTerm, localSpecularTerm = float3( 0.0f, 0.0f, 0.0f );
  473. float localRimHalo = 0;
  474. float3 vFakeRimDir = float3( i.tangentSpaceTranspose0_FakeRimx.w, i.tangentSpaceTranspose1_FakeRimy.w, i.tangentSpaceTranspose2_FakeRimz.w );
  475. float3 cFakeRimColor = i.cAmbient_fRimBoost.rgb * i.cAmbient_fRimBoost.a * g_cFakeRimTint;
  476. CharacterSpecularAndRimTerms( vWorldNormal, vFakeRimDir, 1.0f, vEyeDir,
  477. false, NULL, cFakeRimColor,
  478. true, g_fRimLightExponent, 0.0f,
  479. false, 0.0f, 0.0f, 0.0f, float3( 0.0f, 0.0f, 0.0f ),
  480. false, 0.0f, 0.0f,
  481. localSpecularTerm, localRimTerm, localRimHalo );
  482. cAdditiveRimlight += localRimTerm * fRimMask;
  483. // TODO: add rim saturation here?
  484. }
  485. #endif
  486. #if ( ANISOTROPY )
  487. float3 vnWorldTangentS = normalize( cross( vWorldNormal, i.vWorldTangentT_vBounceCentery.xyz ) );
  488. float3 vnWorldTangentT = normalize( cross( vWorldNormal, vnWorldTangentS ) );
  489. float cr, sr;
  490. sincos( fAnisotropyAngle, cr, sr );
  491. vTangent = normalize( cr * vnWorldTangentT + sr * vnWorldTangentS );
  492. float3 rvec = cross( vTangent, vWorldNormal.xyz );
  493. float3 uvec = cross( vEyeDir, rvec );
  494. float3 evec = normalize( cross( rvec, vTangent ) );
  495. vReflectionEyeVec = lerp( vEyeDir, evec, fAnisotropyAmount );
  496. #endif
  497. #if ( PHONG )
  498. CharacterDoSpecularLighting( i.vWorldPos_projZ.xyz, vWorldNormal, g_fPhongExponent, vEyeDir,
  499. i.lightAtten, NUM_LIGHTS, g_cLightInfo,
  500. ( PHONGWARPTEXTURE == 1 ), PhongWarpSampler,
  501. ( RIMLIGHT == 1 ), g_fRimLightExponent, fCSMShadow, fWarpIndex,
  502. ( ANISOTROPY == 1 ), fAnisotropyAmount, fAnisotropyAngle,
  503. vTangent,
  504. ( ( MASKS2 == 1 ) && ( fRetroReflectivityMask > 0 ) ), fRetroReflectivityMask, i.cAmbient_fRimBoost.xyz,
  505. // Outputs
  506. cSpecularLight, cRimLight, fRimHalo );
  507. #if ( FLASHLIGHT )
  508. cSpecularLight += cSpecularFlashlight;
  509. #endif
  510. #if ( RIMLIGHT )
  511. float fRimModulation = g_fRimLightBoost * fRimMask;
  512. float fRimBoost = i.cAmbient_fRimBoost.w * g_fShadowRimBoost;
  513. fRimBoost += 1.0f;
  514. fRimModulation *= fRimBoost;
  515. cRimLight *= fRimModulation;
  516. #endif
  517. float fPhongBoost = g_fPhongBoost;
  518. cSpecularLight *= fSpecMask;
  519. #if ( MASKS1 )
  520. fPhongBoost = lerp( g_fPhongBoost, g_fPhongAlbedoBoost, fPhongAlbedoMask );
  521. #endif
  522. cSpecularLight *= fPhongBoost;
  523. #endif
  524. #if ( AMBIENTREFLECTION || ENVMAP )
  525. float3 vReflection = CalcReflectionVectorUnnormalized( vWorldNormal, vReflectionEyeVec );
  526. #endif
  527. #if ( ENVMAP )
  528. float3 cEnvmap = ENV_MAP_SCALE * texCUBE( EnvmapSampler, vReflection ).rgb;
  529. cEnvmap = saturateColor( cEnvmap, g_fEnvmapSaturation );
  530. float3 cEnvmapLight = saturate( ( ( linearLightColor + i.cAmbient_fRimBoost.xyz ) - g_vEnvmapLightScaleMin ) * g_vEnvmapLightScaleMax );
  531. cEnvmap = lerp( cEnvmap, cEnvmap * cEnvmapLight, fEnvmapLightScale );
  532. cEnvmap = lerp( cEnvmap, cEnvmap * cEnvmap, g_fEnvmapContrast );
  533. cEnvmap *= fEnvMask * g_cEnvmapTint;
  534. cSpecularLight += cEnvmap;
  535. #endif
  536. #if ( PHONG || ENVMAP )
  537. #if ( MASKS2 )
  538. fFresnel = lerp( fFresnel, 1.0f, fRetroReflectivityMask );
  539. #endif
  540. cSpecularLight *= fFresnel;
  541. #endif
  542. #if ( AMBIENTREFLECTION )
  543. float3 cAmbientReflection = AmbientLight( vReflection, g_cAmbientCube );
  544. float3 cAmbientLightColor = PixelShaderDoLighting( i.vWorldPos_projZ.xyz, float3( 0.0f, 0.0f, 1.0f ),
  545. float3( 0.0f, 0.0f, 0.0f), false,
  546. false, i.lightAtten, g_cAmbientCube,
  547. NormalizeSampler, min( NUM_LIGHTS, 1 ), g_cLightInfo, false,
  548. false, NULL, 1.0f );
  549. cAmbientReflection *= cAmbientLightColor;
  550. #if ( USEBOUNCECOLOR )
  551. float3 vBounceCenter = float3( i.vWorldTangentS_vBounceCenterx.w, i.vWorldTangentT_vBounceCentery.w, i.vBounceCenterDir_vBounceCenterz.w );
  552. float3 linearLightBounceModulate = PixelShaderDoLighting( vBounceCenter, -i.vBounceCenterDir_vBounceCenterz.xyz,
  553. float3( 0.0f, 0.0f, 0.0f), false,
  554. false, i.lightAtten, g_cAmbientCube,
  555. NormalizeSampler, min( NUM_LIGHTS, 1 ), g_cLightInfo, false,
  556. false, NULL, 1.0f );
  557. float fBounceTerm = saturate( dot( vWorldNormal, i.vBounceCenterDir_vBounceCenterz.xyz ) );
  558. float3 cBounce = g_cBounce * i.cAmbient_fRimBoost.xyz * linearLightBounceModulate;
  559. cAmbientReflection = lerp( cAmbientReflection, cBounce, fBounceTerm );
  560. #endif
  561. cAmbientReflection *= g_fAmbientBounceBoost * fAmbientReflectionMask;
  562. cSpecularLight += cAmbientReflection;
  563. #endif
  564. float fRimLightAlbedo = g_fRimLightAlbedo;
  565. #if ( MASKS1 )
  566. cSpecularLight *= lerp( float3( 1.0f, 1.0f, 1.0f ), cBase, fPhongAlbedoMask );
  567. fRimLightAlbedo = g_fRimLightAlbedo * fPhongAlbedoMask;
  568. #endif
  569. cRimLight *= lerp( g_cRimLightTint, cBase * fRimLightAlbedo, saturate( fRimLightAlbedo ) );
  570. float fShadowScale = saturate( g_fShadowScale + i.cAmbient_fRimBoost.w ); // If we darken shadows to increase contrast, don't do it in very dark areas
  571. float lightIntensity = desaturateColor( linearLightColor + cRimLight );
  572. float fShadeLevels = smoothstep( 0.3, 0.0, lightIntensity );
  573. #if ( SHADOWSATURATION )
  574. lightIntensity = desaturateColor( linearLightColor ).g;
  575. // dark-to-mid blend
  576. float fShadeLevelsDark = smoothstep( g_vShadowSaturationBounds.x, g_vShadowSaturationBounds.y, lightIntensity );
  577. // mid-to-light blend
  578. float fShadeLevelsLight = smoothstep( g_vShadowSaturationBounds.w, g_vShadowSaturationBounds.z, lightIntensity );
  579. #if ( RIMLIGHT )
  580. // don't just use linear lighting, make a nice saturated halo on the rimlight too
  581. float rimHalo = smoothstep( g_vRimHaloBounds.x, g_vRimHaloBounds.y, fRimHalo );
  582. rimHalo *= smoothstep( g_vRimHaloBounds.w, g_vRimHaloBounds.z, fRimHalo );
  583. rimHalo *= desaturateColor( cRimLight ).g;
  584. rimHalo *= g_fRimHaloBoost;
  585. lightIntensity += rimHalo;
  586. fShadeLevelsLight = fShadeLevelsLight + rimHalo;
  587. #endif
  588. cBase = lerp( cBase, saturateColor( cBase, g_fShadowSaturation ), fShadeLevelsDark * fShadeLevelsLight * fShadowSaturationMask );
  589. cBase = lerp( cBase, tintColor( cBase, g_cShadowTint.rgb, g_cShadowTint.a ) * fShadowScale, fShadeLevels );
  590. #else
  591. cBase = lerp( cBase, tintColor( cBase, g_cShadowTint.rgb, g_cShadowTint.a ) * fShadowScale, fShadeLevels );
  592. #endif
  593. linearLightColor += i.cAmbient_fRimBoost.xyz;
  594. cBase *= fMetalnessMask;
  595. float3 finalColor = ( cBase * linearLightColor ) + cSpecularLight + cRimLight + cAdditiveRimlight;
  596. #if ( BASEALPHASELFILLUMMASK )
  597. finalColor = lerp( finalColor, vBaseTextureSample.rgb * ( 1.0f + g_fSelfIllumBoost ), fSelfIllumMask );
  598. #endif
  599. float flVertexFogFactor = 0.0f;
  600. #if ( !HARDWAREFOGBLEND && !DOPIXELFOG )
  601. flVertexFogFactor = i.worldPos_vertexFogFactor.w;
  602. #endif
  603. fAlpha *= g_vDiffuseModulation.a;
  604. finalColor *= g_vDiffuseModulation.rgb;
  605. float fogFactor = CalcPixelFogFactorSupportsVertexFog( PIXELFOGTYPE, g_FogParams, g_vEyePos.xyz, i.vWorldPos_projZ.xyz, i.vWorldPos_projZ.w, flVertexFogFactor );
  606. #if ( WRITEWATERFOGTODESTALPHA && ( PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT ) )
  607. fAlpha = fogFactor;
  608. #endif
  609. return FinalOutput( float4( finalColor, fAlpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, false, i.vWorldPos_projZ.w );
  610. }