Team Fortress 2 Source Code as on 22/4/2020
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.

381 lines
16 KiB

  1. //======= Copyright � 1996-2007, Valve Corporation, All rights reserved. ======
  2. // STATIC: "CONVERT_TO_SRGB" "0..0"
  3. // STATIC: "CUBEMAP" "0..1"
  4. // STATIC: "SELFILLUM" "0..1"
  5. // STATIC: "SELFILLUMFRESNEL" "0..1"
  6. // STATIC: "FLASHLIGHT" "0..1"
  7. // STATIC: "LIGHTWARPTEXTURE" "0..1"
  8. // STATIC: "PHONGWARPTEXTURE" "0..1"
  9. // STATIC: "WRINKLEMAP" "0..1"
  10. // STATIC: "DETAIL_BLEND_MODE" "0..6"
  11. // STATIC: "DETAILTEXTURE" "0..1"
  12. // STATIC: "RIMLIGHT" "0..1"
  13. // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps20b] [PC]
  14. // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps30] [PC]
  15. // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..0" [ps20b] [XBOX]
  16. // STATIC: "FASTPATH_NOBUMP" "0..1"
  17. // STATIC: "BLENDTINTBYBASEALPHA" "0..1"
  18. // DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1"
  19. // DYNAMIC: "PIXELFOGTYPE" "0..1"
  20. // DYNAMIC: "NUM_LIGHTS" "0..4"
  21. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" [ps20b] [PC]
  22. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0" [ps20b] [XBOX]
  23. // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" [ps30]
  24. // DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" [ps20b]
  25. // DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" [ps30]
  26. // DYNAMIC: "PHONG_USE_EXPONENT_FACTOR" "0..0" [ps20]
  27. // DYNAMIC: "PHONG_USE_EXPONENT_FACTOR" "0..1" [ps20b] [ps30] [PC]
  28. // SKIP: ($PIXELFOGTYPE == 0) && ($WRITEWATERFOGTODESTALPHA != 0)
  29. // blend mode doesn't matter if we only have one texture
  30. // SKIP: (! $DETAILTEXTURE) && ( $DETAIL_BLEND_MODE != 0 )
  31. // We don't care about flashlight depth unless the flashlight is on
  32. // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 )
  33. // Flashlight shadow filter mode is irrelevant if there is no flashlight
  34. // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps20b]
  35. // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps30]
  36. // Only need self illum fresnel when self illum enabled
  37. // SKIP: ( $SELFILLUM == 0 ) && ( $SELFILLUMFRESNEL == 1 )
  38. // SKIP: ( $FLASHLIGHT == 1 ) && ( $SELFILLUMFRESNEL == 1 )
  39. // SKIP: ( $FLASHLIGHT == 1 ) && ( $SELFILLUM == 1 )
  40. // BlendTintByBaseAlpha and self illum and are opposing meanings for alpha channel
  41. // SKIP: ( $BLENDTINTBYBASEALPHA ) && ( $SELFILLUM )
  42. // fastpath means:
  43. // no bumpmap
  44. // basealphaenvmapmask (not inverted)
  45. // no spec expmap
  46. // no spectint
  47. // no specwarp
  48. // no rimlight
  49. // no selfillum
  50. // no detail
  51. // no BlendTintByBaseAlpha
  52. // SKIP: $FASTPATH_NOBUMP && ( $RIMLIGHT || $DETAILTEXTURE || $PHONGWARPTEXTURE || $SELFILLUM || $BLENDTINTBYBASEALPHA )
  53. #include "common_flashlight_fxc.h"
  54. #include "shader_constant_register_map.h"
  55. const float4 g_SelfIllumTint_and_DetailBlendFactor : register( PSREG_SELFILLUMTINT );
  56. #if ( SELFILLUMFRESNEL == 1 )
  57. const float4 g_SelfIllumScaleBiasExpBrightness : register( PSREG_SELFILLUM_SCALE_BIAS_EXP );
  58. #endif
  59. const float4 g_DiffuseModulation : register( PSREG_DIFFUSE_MODULATION );
  60. const float4 g_EnvmapTint_ShadowTweaks : register( PSREG_ENVMAP_TINT__SHADOW_TWEAKS ); // w controls spec mask
  61. const float3 cAmbientCube[6] : register( PSREG_AMBIENT_CUBE );
  62. const float4 g_EnvMapFresnel : register( PSREG_ENVMAP_FRESNEL__SELFILLUMMASK ); // x is envmap fresnel ... w is selfillummask control
  63. const float4 g_EyePos_SpecExponent : register( PSREG_EYEPOS_SPEC_EXPONENT );
  64. const float4 g_FogParams : register( PSREG_FOG_PARAMS );
  65. const float4 g_FlashlightAttenuationFactors_RimMask : register( PSREG_FLASHLIGHT_ATTENUATION ); // On non-flashlight pass, x has rim mask control
  66. const float4 g_FlashlightPos_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
  67. #if FLASHLIGHT
  68. const float4x4 g_FlashlightWorldToTexture : register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE );
  69. #endif
  70. const float4 g_FresnelSpecParams : register( PSREG_FRESNEL_SPEC_PARAMS ); // xyz are fresnel, w is specular boost
  71. const float4 g_SpecularRimParams : register( PSREG_SPEC_RIM_PARAMS ); // xyz are specular tint color, w is rim power
  72. PixelShaderLightInfo cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 2 registers each - 6 registers total (4th light spread across w's)
  73. // TODO: give this a better name. For now, I don't want to touch shader_constant_register_map.h since I don't want to trigger a recompile of everything...
  74. const float4 g_ShaderControls : register( PSREG_CONSTANT_27 ); // x is basemap alpgha phong mask, y is 1 - blendtintbybasealpha, z is tint overlay amount, w controls "INVERTPHONGMASK"
  75. #define g_FlashlightPos g_FlashlightPos_RimBoost.xyz
  76. #define g_fRimBoost g_FlashlightPos_RimBoost.w
  77. #define g_FresnelRanges g_FresnelSpecParams.xyz
  78. #define g_SpecularBoost g_FresnelSpecParams.w
  79. #define g_SpecularTint g_SpecularRimParams.xyz
  80. #define g_RimExponent g_SpecularRimParams.w
  81. #define g_FlashlightAttenuationFactors g_FlashlightAttenuationFactors_RimMask
  82. #define g_RimMaskControl g_FlashlightAttenuationFactors_RimMask.x
  83. #define g_SelfIllumMaskControl g_EnvMapFresnel.w
  84. #define g_fBaseMapAlphaPhongMask g_ShaderControls.x
  85. #define g_fTintReplacementControl g_ShaderControls.z
  86. #define g_fInvertPhongMask g_ShaderControls.w
  87. sampler BaseTextureSampler : register( s0 ); // Base map, selfillum in alpha
  88. sampler SpecularWarpSampler : register( s1 ); // Specular warp sampler (for iridescence etc)
  89. sampler DiffuseWarpSampler : register( s2 ); // Lighting warp sampler (1D texture for diffuse lighting modification)
  90. sampler NormalMapSampler : register( s3 ); // Normal map, specular mask in alpha
  91. sampler ShadowDepthSampler : register( s4 ); // Flashlight shadow depth map sampler
  92. sampler NormalizeRandRotSampler : register( s5 ); // Normalization / RandomRotation samplers
  93. sampler FlashlightSampler : register( s6 ); // Flashlight cookie
  94. sampler SpecExponentSampler : register( s7 ); // Specular exponent map
  95. sampler EnvmapSampler : register( s8 ); // Cubic environment map
  96. #if WRINKLEMAP
  97. sampler WrinkleSampler : register( s9 ); // Compression base
  98. sampler StretchSampler : register( s10 ); // Expansion base
  99. sampler NormalWrinkleSampler : register( s11 ); // Compression base
  100. sampler NormalStretchSampler : register( s12 ); // Expansion base
  101. #endif
  102. #if DETAILTEXTURE
  103. sampler DetailSampler : register( s13 ); // detail texture
  104. #endif
  105. sampler SelfIllumMaskSampler : register( s14 ); // selfillummask
  106. struct PS_INPUT
  107. {
  108. float4 baseTexCoordDetailTexCoord : TEXCOORD0; // xy=base zw=detail
  109. float3 lightAtten : TEXCOORD1; // Scalar light attenuation factors for FOUR lights
  110. float3 worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ : TEXCOORD2;
  111. float3x3 tangentSpaceTranspose : TEXCOORD3;
  112. // second row : TEXCOORD4;
  113. // third row : TEXCOORD5;
  114. float4 worldPos_atten3 : TEXCOORD6;
  115. float4 projPos_fWrinkleWeight : TEXCOORD7;
  116. };
  117. float4 main( PS_INPUT i ) : COLOR
  118. {
  119. bool bWrinkleMap = WRINKLEMAP ? true : false;
  120. bool bDoDiffuseWarp = LIGHTWARPTEXTURE ? true : false;
  121. bool bDoSpecularWarp = PHONGWARPTEXTURE ? true : false;
  122. bool bDoAmbientOcclusion = false;
  123. bool bFlashlight = (FLASHLIGHT!=0) ? true : false;
  124. bool bSelfIllum = SELFILLUM ? true : false;
  125. bool bDoRimLighting = RIMLIGHT ? true : false;
  126. bool bCubemap = CUBEMAP ? true : false;
  127. bool bBlendTintByBaseAlpha = BLENDTINTBYBASEALPHA ? true : false;
  128. int nNumLights = NUM_LIGHTS;
  129. // Unpacking for convenience
  130. float fWrinkleWeight = i.projPos_fWrinkleWeight.w;
  131. float3 vProjPos = i.projPos_fWrinkleWeight.xyz;
  132. float3 vWorldPos = i.worldPos_atten3.xyz;
  133. float atten3 = i.worldPos_atten3.w;
  134. float4 vLightAtten = float4( i.lightAtten, atten3 );
  135. #if WRINKLEMAP
  136. float flWrinkleAmount = saturate( -fWrinkleWeight ); // One of these two is zero
  137. float flStretchAmount = saturate( fWrinkleWeight ); // while the other is in the 0..1 range
  138. float flTextureAmount = 1.0f - flWrinkleAmount - flStretchAmount; // These should sum to one
  139. #endif
  140. float4 baseColor = tex2D( BaseTextureSampler, i.baseTexCoordDetailTexCoord.xy );
  141. #if WRINKLEMAP
  142. float4 wrinkleColor = tex2D( WrinkleSampler, i.baseTexCoordDetailTexCoord.xy );
  143. float4 stretchColor = tex2D( StretchSampler, i.baseTexCoordDetailTexCoord.xy );
  144. // Apply wrinkle blend to only RGB. Alpha comes from the base texture
  145. baseColor.rgb = flTextureAmount * baseColor + flWrinkleAmount * wrinkleColor + flStretchAmount * stretchColor;
  146. #endif
  147. #if DETAILTEXTURE
  148. float4 detailColor = tex2D( DetailSampler, i.baseTexCoordDetailTexCoord.zw );
  149. baseColor = TextureCombine( baseColor, detailColor, DETAIL_BLEND_MODE, g_SelfIllumTint_and_DetailBlendFactor.w );
  150. #endif
  151. float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.z, vWorldPos.z, vProjPos.z );
  152. float3 vEyeDir = normalize(i.worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ.xyz);
  153. float3 vRimAmbientCubeColor = PixelShaderAmbientLight(vEyeDir, cAmbientCube);
  154. float3 worldSpaceNormal, tangentSpaceNormal;
  155. float fSpecMask = 1.0f;
  156. float4 normalTexel = tex2D( NormalMapSampler, i.baseTexCoordDetailTexCoord.xy );
  157. #if WRINKLEMAP
  158. float4 wrinkleNormal = tex2D( NormalWrinkleSampler, i.baseTexCoordDetailTexCoord.xy );
  159. float4 stretchNormal = tex2D( NormalStretchSampler, i.baseTexCoordDetailTexCoord.xy );
  160. normalTexel = flTextureAmount * normalTexel + flWrinkleAmount * wrinkleNormal + flStretchAmount * stretchNormal;
  161. #endif
  162. #if (FASTPATH_NOBUMP == 0 )
  163. tangentSpaceNormal = lerp( 2.0f * normalTexel.xyz - 1.0f, float3(0, 0, 1), g_fBaseMapAlphaPhongMask );
  164. fSpecMask = lerp( normalTexel.a, baseColor.a, g_fBaseMapAlphaPhongMask );
  165. #else
  166. tangentSpaceNormal = float3(0, 0, 1);
  167. fSpecMask = baseColor.a;
  168. #endif
  169. // We need a normal if we're doing any lighting
  170. worldSpaceNormal = normalize( mul( i.tangentSpaceTranspose, tangentSpaceNormal ) );
  171. float fFresnelRanges = Fresnel( worldSpaceNormal, vEyeDir, g_FresnelRanges );
  172. float fRimFresnel = Fresnel4( worldSpaceNormal, vEyeDir );
  173. // Break down reflect so that we can share dot(worldSpaceNormal,vEyeDir) with fresnel terms
  174. float3 vReflect = 2 * worldSpaceNormal * dot(worldSpaceNormal, vEyeDir) - vEyeDir;
  175. float3 diffuseLighting = float3( 1.0f, 1.0f, 1.0f );
  176. float3 envMapColor = float3( 0.0f, 0.0f, 0.0f );
  177. if( !bFlashlight )
  178. {
  179. // Summation of diffuse illumination from all local lights
  180. diffuseLighting = PixelShaderDoLighting( vWorldPos, worldSpaceNormal,
  181. float3( 0.0f, 0.0f, 0.0f ), false, true, vLightAtten,
  182. cAmbientCube, NormalizeRandRotSampler, nNumLights, cLightInfo, true,
  183. // These parameters aren't passed by generic shaders:
  184. false, 1.0f,
  185. bDoDiffuseWarp, DiffuseWarpSampler );
  186. if( bCubemap )
  187. {
  188. // Mask is either normal map alpha or base map alpha
  189. #if ( SELFILLUMFRESNEL == 1 ) // This is to match the 2.0 version of vertexlitgeneric
  190. float fEnvMapMask = lerp( baseColor.a, g_fInvertPhongMask, g_EnvmapTint_ShadowTweaks.w );
  191. #else
  192. float fEnvMapMask = lerp( baseColor.a, fSpecMask, g_EnvmapTint_ShadowTweaks.w );
  193. #endif
  194. envMapColor = (ENV_MAP_SCALE *
  195. lerp(1, fFresnelRanges, g_EnvMapFresnel.x) *
  196. lerp(fEnvMapMask, 1-fEnvMapMask, g_fInvertPhongMask)) *
  197. texCUBE( EnvmapSampler, vReflect ) *
  198. g_EnvmapTint_ShadowTweaks.xyz;
  199. }
  200. }
  201. float3 specularLighting = float3( 0.0f, 0.0f, 0.0f );
  202. float3 rimLighting = float3( 0.0f, 0.0f, 0.0f );
  203. float3 vSpecularTint = 1;
  204. float fRimMask = 0;
  205. float fSpecExp = 1;
  206. #if ( FASTPATH_NOBUMP == 0 )
  207. float4 vSpecExpMap = tex2D( SpecExponentSampler, i.baseTexCoordDetailTexCoord.xy );
  208. if ( !bFlashlight )
  209. {
  210. fRimMask = lerp( 1.0f, vSpecExpMap.a, g_RimMaskControl ); // Select rim mask
  211. }
  212. // If the exponent passed in as a constant is zero, use the value from the map as the exponent
  213. #if defined( _X360 )
  214. [flatten]
  215. #endif
  216. #if ( PHONG_USE_EXPONENT_FACTOR )
  217. fSpecExp = ( 1.0f + g_EyePos_SpecExponent.w * vSpecExpMap.r );
  218. #else
  219. fSpecExp = (g_EyePos_SpecExponent.w >= 0.0) ? g_EyePos_SpecExponent.w : (1.0f + 149.0f * vSpecExpMap.r);
  220. #endif
  221. // If constant tint is negative, tint with albedo, based upon scalar tint map
  222. #if defined( _X360 )
  223. [flatten]
  224. #endif
  225. vSpecularTint = lerp( float3(1.0f, 1.0f, 1.0f), baseColor.rgb, vSpecExpMap.g );
  226. vSpecularTint = (g_SpecularTint.r >= 0.0) ? g_SpecularTint.rgb : vSpecularTint;
  227. #else
  228. fSpecExp = max(g_EyePos_SpecExponent.w, 0);
  229. #endif
  230. float3 albedo = baseColor.rgb;
  231. if ( !bFlashlight )
  232. {
  233. // Summation of specular from all local lights besides the flashlight
  234. PixelShaderDoSpecularLighting( vWorldPos, worldSpaceNormal,
  235. fSpecExp, vEyeDir, vLightAtten,
  236. nNumLights, cLightInfo, false, 1.0f, bDoSpecularWarp,
  237. SpecularWarpSampler, fFresnelRanges, bDoRimLighting, g_RimExponent,
  238. // Outputs
  239. specularLighting, rimLighting );
  240. }
  241. else
  242. {
  243. #if FLASHLIGHT
  244. float4 flashlightSpacePosition = mul( float4( vWorldPos, 1.0f ), g_FlashlightWorldToTexture );
  245. DoSpecularFlashlight( g_FlashlightPos, vWorldPos, flashlightSpacePosition, worldSpaceNormal,
  246. g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w,
  247. FlashlightSampler, ShadowDepthSampler, NormalizeRandRotSampler, FLASHLIGHTDEPTHFILTERMODE, FLASHLIGHTSHADOWS, true, vProjPos.xy / vProjPos.z,
  248. fSpecExp, vEyeDir, bDoSpecularWarp, SpecularWarpSampler, fFresnelRanges, g_EnvmapTint_ShadowTweaks,
  249. // These two values are output
  250. diffuseLighting, specularLighting );
  251. #endif
  252. }
  253. // If we didn't already apply Fresnel to specular warp, modulate the specular
  254. if ( !bDoSpecularWarp )
  255. fSpecMask *= fFresnelRanges;
  256. // Modulate with spec mask, boost and tint
  257. specularLighting *= fSpecMask * g_SpecularBoost;
  258. if (bBlendTintByBaseAlpha)
  259. {
  260. float3 tintedColor = albedo * g_DiffuseModulation.rgb;
  261. tintedColor = lerp(tintedColor, g_DiffuseModulation.rgb, g_fTintReplacementControl);
  262. albedo = lerp(albedo, tintedColor, baseColor.a);
  263. }
  264. else
  265. {
  266. albedo = albedo * g_DiffuseModulation.rgb;
  267. }
  268. float3 diffuseComponent = albedo * diffuseLighting;
  269. if ( bSelfIllum && !bFlashlight )
  270. {
  271. #if ( SELFILLUMFRESNEL == 1 ) // To free up the constant register...see top of file
  272. // This will apply a Fresnel term based on the vertex normal (not the per-pixel normal!) to help fake and internal glow look
  273. float3 vVertexNormal = normalize( float3( i.tangentSpaceTranspose[0].z, i.tangentSpaceTranspose[1].z, i.tangentSpaceTranspose[2].z ) );
  274. float flSelfIllumFresnel = ( pow( saturate( dot( vVertexNormal.xyz, vEyeDir.xyz ) ), g_SelfIllumScaleBiasExpBrightness.z ) * g_SelfIllumScaleBiasExpBrightness.x ) + g_SelfIllumScaleBiasExpBrightness.y;
  275. diffuseComponent = lerp( diffuseComponent, g_SelfIllumTint_and_DetailBlendFactor.rgb * albedo * g_SelfIllumScaleBiasExpBrightness.w, baseColor.a * saturate( flSelfIllumFresnel ) );
  276. #else
  277. float3 vSelfIllumMask = tex2D( SelfIllumMaskSampler, i.baseTexCoordDetailTexCoord.xy );
  278. vSelfIllumMask = lerp( baseColor.aaa, vSelfIllumMask, g_SelfIllumMaskControl );
  279. diffuseComponent = lerp( diffuseComponent, g_SelfIllumTint_and_DetailBlendFactor.rgb * albedo, vSelfIllumMask );
  280. #endif
  281. diffuseComponent = max( 0.0f, diffuseComponent );
  282. }
  283. #if DETAILTEXTURE
  284. diffuseComponent = TextureCombinePostLighting( diffuseComponent, detailColor,
  285. DETAIL_BLEND_MODE, g_SelfIllumTint_and_DetailBlendFactor.w );
  286. #endif
  287. if ( bDoRimLighting && !bFlashlight )
  288. {
  289. float fRimMultiply = fRimMask * fRimFresnel; // both unit range: [0, 1]
  290. // Add in rim light modulated with tint, mask and traditional Fresnel (not using Fresnel ranges)
  291. rimLighting *= fRimMultiply;
  292. // Fold rim lighting into specular term by using the max so that we don't really add light twice...
  293. specularLighting = max( specularLighting, rimLighting );
  294. // Add in view-ray lookup from ambient cube
  295. specularLighting += (vRimAmbientCubeColor * g_fRimBoost) * saturate(fRimMultiply * worldSpaceNormal.z);
  296. }
  297. float3 result = specularLighting*vSpecularTint + envMapColor + diffuseComponent;
  298. #if WRITEWATERFOGTODESTALPHA && ( PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT )
  299. float alpha = fogFactor;
  300. #else
  301. float alpha = g_DiffuseModulation.a;
  302. if ( !bSelfIllum && !bBlendTintByBaseAlpha )
  303. {
  304. alpha = lerp( baseColor.a * alpha, alpha, g_fBaseMapAlphaPhongMask );
  305. }
  306. #endif
  307. bool bWriteDepthToAlpha = ( WRITE_DEPTH_TO_DESTALPHA != 0 ) && ( WRITEWATERFOGTODESTALPHA == 0 );
  308. //FIXME: need to take dowaterfog into consideration
  309. return FinalOutput( float4( result, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, bWriteDepthToAlpha, vProjPos.z );
  310. }