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.

194 lines
8.9 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. // STATIC: "LIGHTWARPTEXTURE" "0..1"
  3. #include "common_fog_ps_fxc.h"
  4. // DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1"
  5. // DYNAMIC: "NUM_LIGHTS" "0..2" [ps20]
  6. // DYNAMIC: "NUM_LIGHTS" "0..4" [ps20b]
  7. // DYNAMIC: "NUM_LIGHTS" "0..4" [ps30]
  8. #include "shader_constant_register_map.h"
  9. sampler BaseSampler : register( s0 ); // Base map
  10. sampler DiffuseWarpSampler : register( s1 ); // 1D texture for diffuse lighting modification
  11. sampler RefractSampler : register( s2 ); // Refraction map copied from back buffer
  12. sampler NormalSampler : register( s3 ); // Normal map
  13. sampler SpecExponentSampler : register( s4 ); // Flashlight cookie
  14. samplerCUBE NormalizeSampler : register( s5 ); // Normalization cube map
  15. const float3x3 g_ViewProj : register( c0 ); // 1st row of Projection matrix
  16. // c1 // 2nd row
  17. // c2 // 4th row
  18. const float2 g_CloakControl : register( c3 ); // { refract amount, cloak, ?, ? }
  19. const float3 cAmbientCube[6] : register( PSREG_AMBIENT_CUBE );
  20. const float4 g_EyePos_SpecExponent : register( PSREG_EYEPOS_SPEC_EXPONENT );
  21. const float4 g_FogParams : register( PSREG_FOG_PARAMS );
  22. const float4 g_FlashlightAttenuationFactors_RimMask : register( PSREG_FLASHLIGHT_ATTENUATION ); // On non-flashlight pass, x has rim mask control
  23. const float4 g_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
  24. const float4 g_FresnelSpecParams : register( PSREG_FRESNEL_SPEC_PARAMS ); // xyz are fresnel, w is specular boost
  25. const float4 g_SpecularRimParams : register( PSREG_SPEC_RIM_PARAMS ); // xyz are specular tint color, w is rim power
  26. PixelShaderLightInfo cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 2 registers each - 6 registers total
  27. #define g_fRimBoost g_RimBoost.w
  28. #define g_FresnelRanges g_FresnelSpecParams.xyz
  29. #define g_SpecularBoost g_FresnelSpecParams.w
  30. #define g_SpecularTint g_SpecularRimParams.xyz
  31. #define g_RimExponent g_SpecularRimParams.w
  32. #define g_FlashlightAttenuationFactors g_FlashlightAttenuationFactors_RimMask
  33. #define g_RimMaskControl g_FlashlightAttenuationFactors_RimMask.x
  34. // 8 2D Poisson offsets (designed to use .xy and .wz swizzles (not .zw)
  35. static const float4 gPoissonOffset[4] = { float4 (-0.0876f, 0.9703f, 0.5651f, 0.4802f ),
  36. float4 ( 0.1851f, 0.1580f, -0.0617f, -0.2616f ),
  37. float4 (-0.5477f, -0.6603f, 0.0711f, -0.5325f ),
  38. float4 (-0.0751f, -0.8954f, 0.4054f, 0.6384f ) };
  39. struct PS_INPUT
  40. {
  41. float2 vBaseTexCoord : TEXCOORD0;
  42. float3x3 tangentSpaceTranspose : TEXCOORD1;
  43. // second row : TEXCOORD2;
  44. // third row : TEXCOORD3;
  45. float3 worldPos : TEXCOORD4;
  46. float3 projPos : TEXCOORD5;
  47. float4 lightAtten : TEXCOORD6;
  48. };
  49. float4_color_return_type main( PS_INPUT i ) : COLOR
  50. {
  51. float3 vSpecular = float3( 0.0f, 0.0f, 0.0f );
  52. bool bDoDiffuseWarp = LIGHTWARPTEXTURE ? true : false;
  53. int nNumLights = NUM_LIGHTS;
  54. // Base color
  55. float4 albedo = tex2D( BaseSampler, i.vBaseTexCoord );
  56. // Load normal and expand range
  57. float4 vNormalSample = tex2D( NormalSampler, i.vBaseTexCoord );
  58. float3 tangentSpaceNormal = 2.0f * vNormalSample.xyz - 1.0f;
  59. // We need a world space normal if we're doing any lighting
  60. float3 vWorldNormal = normalize( mul( i.tangentSpaceTranspose, tangentSpaceNormal ) );
  61. float3 vWorldEyeDir = normalize( g_EyePos_SpecExponent.xyz - i.worldPos );
  62. // Vanilla 1-(N.V) fresnel term used later in transition lerp
  63. float fresnel = 1-saturate( dot( vWorldNormal, vWorldEyeDir ) );
  64. // Summation of diffuse illumination from all local lights
  65. float3 diffuseLighting = PixelShaderDoLighting( i.worldPos, vWorldNormal,
  66. float3( 0.0f, 0.0f, 0.0f ), false,
  67. true, i.lightAtten, cAmbientCube, NormalizeSampler,
  68. nNumLights, cLightInfo, true,
  69. bDoDiffuseWarp, DiffuseWarpSampler );
  70. // Transform world space normal into clip space and project
  71. float2 vProjNormal;
  72. vProjNormal.x = dot( vWorldNormal, g_ViewProj[0] ); // 1st row
  73. vProjNormal.y = dot( vWorldNormal, g_ViewProj[1] ); // 2nd row
  74. // Compute coordinates for sampling refraction
  75. float2 vRefractTexCoordNoWarp = i.projPos.xy / i.projPos.z;
  76. float2 vRefractTexCoord = vProjNormal.xy;
  77. float scale = lerp( g_CloakControl.x, 0.0f, g_CloakControl.y );
  78. vRefractTexCoord *= scale;
  79. vRefractTexCoord += vRefractTexCoordNoWarp;
  80. #ifdef SHADER_MODEL_PS_2_0
  81. float3 vRefract = tex2D( RefractSampler, vRefractTexCoordNoWarp );
  82. #endif
  83. // Extra refraction rays, specular, rim etc are only done on ps_2_b
  84. #if defined( SHADER_MODEL_PS_2_B ) || defined( SHADER_MODEL_PS_3_0 )
  85. // Blur by scalable Poisson filter
  86. float fBlurAmount = lerp( 0.05f, 0.0f, g_CloakControl.y );
  87. float3 vRefract = tex2D( RefractSampler, vRefractTexCoord ).rgb;
  88. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[0].xy * fBlurAmount ).rgb;
  89. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[0].wz * fBlurAmount ).rgb;
  90. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[1].xy * fBlurAmount ).rgb;
  91. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[1].wz * fBlurAmount ).rgb;
  92. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[2].xy * fBlurAmount ).rgb;
  93. vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[2].wz * fBlurAmount ).rgb;
  94. // We're right at the hairy edge of constant register usage and hence have to drop these taps...
  95. // vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[3].xy * fBlurAmount );
  96. // vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[3].wz * fBlurAmount );
  97. vRefract /= 7.0f;
  98. float3 rimLighting = float3( 0.0f, 0.0f, 0.0f );
  99. float3 specularLighting = float3( 0.0f, 0.0f, 0.0f );
  100. float fSpecExp = g_EyePos_SpecExponent.w;
  101. float fSpecMask = vNormalSample.a;
  102. float4 vSpecExpMap = tex2D( SpecExponentSampler, i.vBaseTexCoord );
  103. float fSpecExpMap = vSpecExpMap.r;
  104. float fRimMask = 1.0f;//lerp( 1.0f, vSpecExpMap.a, g_RimMaskControl ); // Select rim mask
  105. float3 vSpecularTint;
  106. // If the exponent passed in as a constant is zero, use the value from the map as the exponent
  107. if ( fSpecExp == 0 )
  108. fSpecExp = 1.0f - fSpecExpMap + 150.0f * fSpecExpMap;
  109. // If constant tint is negative, tint with albedo, based upon scalar tint map
  110. if ( g_SpecularTint.r == -1 )
  111. vSpecularTint = lerp( float3(1.0f, 1.0f, 1.0f), albedo.rgb, vSpecExpMap.g );
  112. else
  113. vSpecularTint = g_SpecularTint.rgb;
  114. // Fresnel to match regular specular lighting
  115. float fFresnelRanges = Fresnel( vWorldNormal, vWorldEyeDir, g_FresnelRanges );
  116. // Summation of specular from all local lights besides the flashlight
  117. PixelShaderDoSpecularLighting( i.worldPos, vWorldNormal, fSpecExp, vWorldEyeDir,
  118. i.lightAtten, nNumLights, cLightInfo, false, BaseSampler, // this sampler isn't actually used; it just needs a value passed in
  119. 1.0f, true, g_RimExponent, 1.0f,
  120. // Outputs
  121. specularLighting, rimLighting );
  122. // Modulate with spec mask, boost, tint and fresnel ranges
  123. specularLighting *= fSpecMask * g_SpecularBoost * fFresnelRanges * vSpecularTint;
  124. float fRimFresnel = Fresnel4( vWorldNormal, vWorldEyeDir );
  125. // Add in rim light modulated with tint, mask and traditional Fresnel (not using Fresnel ranges)
  126. rimLighting *= vSpecularTint * fRimMask * fRimFresnel;
  127. // Fold rim lighting into specular term by using the max so that we don't really add light twice...
  128. specularLighting = max (specularLighting, rimLighting);
  129. // Add in view-ray lookup from ambient cube
  130. specularLighting += fRimFresnel * fRimMask * vSpecularTint /* g_fRimBoost */ * PixelShaderAmbientLight( vWorldEyeDir, cAmbientCube) * saturate(dot(vWorldNormal, float3(0, 0 , 1)) );
  131. float tintLerpFactor = saturate(lerp( 1, fresnel-1.1, saturate(g_CloakControl.y)));
  132. tintLerpFactor = smoothstep( 0.4f, 0.425f, tintLerpFactor );
  133. float3 vTintedRefract = lerp( vRefract, albedo.rgb * vRefract, 0.7f );
  134. vRefract = lerp( vRefract, vTintedRefract, tintLerpFactor );
  135. vSpecular = specularLighting * smoothstep( 0.98, 0.8, saturate(g_CloakControl.y ));
  136. #endif
  137. // Blend refraction component with diffusely lit model
  138. float diffuseLerpFactor = saturate(lerp( 1, fresnel - 1.35, saturate(g_CloakControl.y)));
  139. diffuseLerpFactor = smoothstep( 0.4f, 0.425f, diffuseLerpFactor );
  140. float3 fDiffuse = lerp( vRefract, albedo.rgb * diffuseLighting, diffuseLerpFactor );
  141. float3 result = fDiffuse + vSpecular;
  142. float alpha = 1.0f;
  143. // Emulate LinearColorToHDROutput() when uncloaked
  144. result = lerp( result.xyz * LINEAR_LIGHT_SCALE, result, saturate(g_CloakControl.y) );
  145. float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.xyz, i.worldPos.xyz, i.projPos.z );
  146. #if WRITEWATERFOGTODESTALPHA && (PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT)
  147. alpha = fogFactor;
  148. #endif
  149. return FinalOutput( float4( result, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
  150. }