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.

282 lines
12 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. // STATIC: "STAGE" "0..2"
  3. // STATIC: "TINTED" "0..1"
  4. // STATIC: "SHADER_SRGB_READ" "0..1" [ps20b] [PC]
  5. // STATIC: "SHADER_SRGB_READ" "0..0" [ps20b] [CONSOLE]
  6. // DYNAMIC: "D_NVIDIA_STEREO" "0..1" [ps20b] [PC]
  7. // DYNAMIC: "D_NVIDIA_STEREO" "0..0" [ps20b] [CONSOLE]
  8. // SKIP: ( $STAGE != 2 ) && ( $TINTED == 1 )
  9. #if defined( _X360 )
  10. #undef SHADER_SRGB_READ
  11. #define SHADER_SRGB_READ 1
  12. #endif
  13. #include "common_fog_ps_supportsvertexfog_fxc.h"
  14. // Includes =======================================================================================
  15. #include "common_vertexlitgeneric_dx9.h"
  16. // Texture Samplers ===============================================================================
  17. sampler g_tRefractionSampler : register( s0 );
  18. sampler g_tPortalNoiseSampler : register( s1 );
  19. sampler g_tPortalColorSampler : register( s2 );
  20. #if D_NVIDIA_STEREO
  21. sampler StereoParamSampler : register( s3 );
  22. #endif
  23. // Shaders Constants and Globals ==================================================================
  24. const float4 g_mViewProj0 : register( c0 ); // 1st row of matrix
  25. const float4 g_mViewProj1 : register( c1 ); // 2nd row of matrix
  26. const float4 g_mViewProj2 : register( c2 ); // 3rd row of matrix
  27. const float4 g_mViewProj3 : register( c3 ); // 4th row of matrix
  28. const float3 g_vConst4 : register( c4 );
  29. #define g_flPortalOpenAmount g_vConst4.x
  30. #define g_flPortalActive g_vConst4.y
  31. #define g_flPortalColorScale g_vConst4.z
  32. const float4 g_vCameraPosition : register( c5 );
  33. const float4 g_vFogParams : register( c6 );
  34. #if ( TINTED == 1 )
  35. const float4 g_vGradientDark : register( c7 ); //the dark side of a color gradient when not using a color texture
  36. const float4 g_vGradientLight : register( c8 ); //the bright side of a color gradient when not using a color texture
  37. #endif
  38. const float4 g_vViewportMad : register( c9 );
  39. // Interpolated values ============================================================================
  40. struct PS_INPUT
  41. {
  42. float2 vUv0 : TEXCOORD0;
  43. float3 vWorldTangent : TEXCOORD1;
  44. float3 vWorldBinormal : TEXCOORD2;
  45. float4 vWorldPosition : TEXCOORD3; // Proj pos z in w
  46. float3 vProjPosForRefract : TEXCOORD4;
  47. float4 vNoiseTexCoord : TEXCOORD5;
  48. };
  49. // This is the equilavent of smoothstep built into HLSL but linear
  50. float linearstep( float iMin, float iMax, float iValue )
  51. {
  52. return saturate( ( iValue - iMin ) / ( iMax - iMin ) );
  53. }
  54. // NVIDIA's function to convert mono refract UV to the correct stereo UV for each eye
  55. float2 MonoToStereoClipPosXY( float3 vMonoClipPos ) // .z is actually .w
  56. {
  57. #if ( !D_NVIDIA_STEREO )
  58. {
  59. return vMonoClipPos.xy;
  60. }
  61. #else
  62. {
  63. // 0th pixel = 1/16 == 1/16 + 1/8 * 0
  64. float flEyeSep = tex2D( StereoParamSampler, float2( 0.0625f, 0 ) ).x; // 0.19 * 0.1316;
  65. // 1st pixel = 3/16 == 1/16 + 1/8 * 1
  66. float flConvergence = tex2D( StereoParamSampler, float2( 0.1875, 0 ) ).x; // 4;
  67. float3 vStereoClipPos = vMonoClipPos.xyz;
  68. // Undo the stereo transform
  69. vStereoClipPos.x += flEyeSep * ( vMonoClipPos.z - flConvergence );
  70. return vStereoClipPos.xy;
  71. }
  72. #endif
  73. }
  74. // Main ===========================================================================================
  75. float4_color_return_type main( PS_INPUT i ) : COLOR
  76. {
  77. float kFlPortalOuterBorder = 0.075f; // Must match VS!
  78. float kFlPortalInnerBorder = kFlPortalOuterBorder * 4.0f;
  79. // Add a slight border around the portal opening (Do this in the VS?)
  80. //i.vUv0.xy = i.vUv0.xy * ( 1.0f + kFlPortalOuterBorder ) - ( kFlPortalOuterBorder * 0.5f );
  81. // Portal open time
  82. float flPortalOpenAmount = smoothstep( 0.0f, 1.0f, saturate( g_flPortalOpenAmount ) );
  83. //float flPortalOpenAmount = saturate( g_flPortalOpenAmount );
  84. float flPortalOpenAmountSquared = flPortalOpenAmount * flPortalOpenAmount;
  85. // Stretch values
  86. float2 vStretchVector = ( i.vUv0.xy * 2.0f ) - 1.0f;
  87. float flDistFromCenter = length( vStretchVector );
  88. float2 vStretchVectorNormalized = normalize( vStretchVector );
  89. // Stencil cutout (1.0 in hole)
  90. float flStencilCutout = step( flDistFromCenter, flPortalOpenAmountSquared );
  91. //==================================//
  92. // Stage 0: Warp pixels around hole //
  93. //==================================//
  94. #if ( STAGE == 0 )
  95. {
  96. // Unrefracted tex coords
  97. float2 vRefractTexCoordNoWarp = i.vProjPosForRefract.xy / i.vProjPosForRefract.z;
  98. // Projected screen-space tangent
  99. float3 vProjTangent;
  100. vProjTangent.x = dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj0.xyzw ); // 1st row
  101. vProjTangent.y = -dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj1.xyzw ); // 2nd row
  102. vProjTangent.z = dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj3.xyzw ); // 4th row
  103. vProjTangent.xy += vProjTangent.z;
  104. vProjTangent.xy *= 0.5f;
  105. vProjTangent.xy /= vProjTangent.z;
  106. vProjTangent.xy -= vRefractTexCoordNoWarp.xy;
  107. // Projected screen-space binormal
  108. float3 vProjBinormal;
  109. vProjBinormal.x = dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj0.xyzw ); // 1st row
  110. vProjBinormal.y = -dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj1.xyzw ); // 2nd row
  111. vProjBinormal.z = dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj3.xyzw ); // 4th row
  112. vProjBinormal.xy += vProjBinormal.z;
  113. vProjBinormal.xy *= 0.5f;
  114. vProjBinormal.xy /= vProjBinormal.z;
  115. vProjBinormal.xy -= vRefractTexCoordNoWarp.xy;
  116. // Tangent-space uv offset
  117. float2 vTangentRefract = -vStretchVectorNormalized * flPortalOpenAmountSquared * ( 1.0f - pow( saturate( flDistFromCenter ), 64.0f ) );
  118. vTangentRefract.xy *= smoothstep( ( flPortalOpenAmount * 1.5f ), flPortalOpenAmount, flDistFromCenter );
  119. // Note: This works well perpendicular to the surface, but because the projection is non-linear, it's refracty very edge on
  120. float2 kPortalRadius = { 32.0f, 32.0f }; // Should be 32, 54 but this reduces the artifacts from the comment above
  121. vTangentRefract.xy *= kPortalRadius.xy;
  122. // Generate refracteds screen-space uv
  123. float2 vRefractTexCoord = MonoToStereoClipPosXY( i.vProjPosForRefract.xyz ) / i.vProjPosForRefract.z;
  124. vRefractTexCoord.xy += vTangentRefract.x * vProjTangent.xy;
  125. vRefractTexCoord.xy -= vTangentRefract.y * vProjBinormal.xy;
  126. // Adjust for current viewport
  127. #if defined( _X360 ) || defined( _PS3 )
  128. {
  129. vRefractTexCoord.xy = ( vRefractTexCoord.xy * g_vViewportMad.xy ) + g_vViewportMad.zw;
  130. }
  131. #endif
  132. // Fetch color from texture
  133. float3 cRefract = tex2Dsrgb( g_tRefractionSampler, vRefractTexCoord.xy ).rgb;
  134. // Darken the ring around the portal as it's opening to help it stand out on plain walls
  135. float flHoleEdge = flPortalOpenAmountSquared;
  136. float flDimEdge = saturate( flPortalOpenAmount * 2.0f );
  137. float flDarkeningRing = linearstep( flHoleEdge - 0.01f, flDimEdge, flDistFromCenter );
  138. flDarkeningRing = ( abs( flDarkeningRing * 2.0f - 1.0f ) * 0.15f ) + 0.85f;
  139. //===============//
  140. // Combine terms //
  141. //===============//
  142. float4 result;
  143. result.rgb = cRefract.rgb;
  144. result.rgb *= flDarkeningRing;
  145. // Alpha test away outside the portal oval
  146. result.a = step( flDistFromCenter, 1.0f );
  147. return FinalOutput( result, 0.0f, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE );
  148. }
  149. #endif
  150. //============================================================================//
  151. // Stage 1: Cut a hole in the stencil buffer (only render pixels in the hole) //
  152. //============================================================================//
  153. #if ( STAGE == 1 )
  154. {
  155. float4 result;
  156. result.rgb = 0.0f;
  157. result.a = flStencilCutout;
  158. //result = 0.0f; // Disable the hole for debugging
  159. return result;
  160. }
  161. #endif
  162. //============================================//
  163. // Stage 2: Fire effect around rim of opening //
  164. //============================================//
  165. #if ( STAGE == 2 )
  166. {
  167. // Outer effect mask
  168. float flOuterEffectMask = ( 1.0f - linearstep( flPortalOpenAmountSquared, flPortalOpenAmountSquared + kFlPortalOuterBorder, flDistFromCenter ) ) * ( 1.0f - flStencilCutout );
  169. // Inner effect mask
  170. float flInnerEffectMask = ( linearstep( flPortalOpenAmountSquared - kFlPortalInnerBorder, flPortalOpenAmountSquared, flDistFromCenter ) ) * ( flStencilCutout );
  171. // Fade it in as the portal is opening
  172. //float flPortalActive = smoothstep( 0.0f, 1.0f, saturate( g_flPortalActive ) );
  173. float flPortalActive = saturate( g_flPortalActive ); // This is good enough...smoothstep above is not necessary
  174. //flPortalActive = linearstep( 0.0f, saturate( flDistFromCenter ), saturate( flPortalActive ) ); // Experiment to fade from center out
  175. float flEffectFadeIn = max( saturate( flPortalOpenAmount * 2.5f ), ( 1.0f - flPortalActive ) );
  176. // Combine mask terms
  177. float flEffectMask = ( flInnerEffectMask + flOuterEffectMask ) * flEffectFadeIn;
  178. //flEffectMask = pow( flEffectMask, 0.75f ); // This will thicken the border but also darken the alpha blend in ugly ways. Leaving this here for experiments later.
  179. float4 cNoiseTexel1 = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.xy );
  180. float4 cNoiseTexel2 = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.wz - cNoiseTexel1.rg*0.02 );
  181. cNoiseTexel1.rgba = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.xy - cNoiseTexel2.rg*0.02 );
  182. //float flNoise = ( ( cNoiseTexel1.g * cNoiseTexel2.g ) * 2.0f ); // More broken up flames and crazier
  183. float flNoise = ( ( cNoiseTexel1.g + cNoiseTexel2.g ) * 0.5f ); // More solid flames and calmer
  184. float flPortalActiveWithNoise = smoothstep( 0.0f, flNoise, flPortalActive );
  185. float kFlBorderSoftness = 0.875f; // Larger numbers give more color in the middle when portal is inactive
  186. float flBorderMaskWithNoise = ( 1.0f - smoothstep( flEffectMask - kFlBorderSoftness, flEffectMask + kFlBorderSoftness, flNoise ) );
  187. flNoise = flBorderMaskWithNoise;
  188. flEffectMask *= flBorderMaskWithNoise;
  189. // This will get stuffed in alpha
  190. float flTransparancy = saturate( flEffectMask + ( flStencilCutout * ( 1.0f - flPortalActiveWithNoise ) ) ) * 1.5f; // Magic number at the end will make the flames thicker with larger numbers
  191. // This will make the portals shift in color from bottom to top (Set to 1.0f to disable)
  192. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.9f ) + 0.1f; // More extreme
  193. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.85f ) + 0.15f;
  194. float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.8f ) + 0.2f;
  195. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.75f ) + 0.25f; // More subtle (needs higher color scale below)
  196. //float flBottomToTopBrightnessShift = 1.0f; // Disabled
  197. float3 cFlameColor;
  198. float flGradientSampleLocation = pow( flNoise, 0.5f ) * flBottomToTopBrightnessShift * flTransparancy;
  199. #if ( TINTED == 0 )
  200. {
  201. // Fetch color from 1D texture
  202. cFlameColor.rgb = tex1D( g_tPortalColorSampler, flGradientSampleLocation ).rgb;
  203. }
  204. #else
  205. {
  206. cFlameColor.rgb = lerp( g_vGradientDark.rgb, g_vGradientLight.rgb, flGradientSampleLocation );
  207. }
  208. #endif
  209. cFlameColor.rgb *= g_flPortalColorScale; // Brighten colors to make it look more emissive
  210. // Generate final color result
  211. float4 result;
  212. result.rgb = cFlameColor.rgb;
  213. result.a = flTransparancy;
  214. //result.rgb *= result.a; // This will give better definition to the flames but also darkens the outer rim
  215. //result.rgb = pow( result.rgb, 1.5f );
  216. //result.rgb *= result.rgb; // Make it look hotter
  217. // Debugging
  218. //result.rgba = flBorderMaskWithNoise;
  219. //result.rgba = flEffectMask;
  220. //result.rgba = flTransparancy;
  221. //result.rgba = flPortalActive * flStencilCutout;
  222. // Apply fog and deal with HDR
  223. float fogFactor = 0.0f;
  224. #if !defined( SHADER_MODEL_PS_2_0 )
  225. {
  226. fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_vFogParams, g_vCameraPosition.xyz, i.vWorldPosition.xyz, i.vWorldPosition.w );
  227. }
  228. #endif
  229. // Limit tonemap scalar to 0.0-1.0 so the colors don't oversaturate, but let it drop down to 0 in case we're fading
  230. float flTonemapScalar = saturate( LINEAR_LIGHT_SCALE );
  231. return FinalOutput( result, fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE ) * flTonemapScalar;
  232. }
  233. #endif
  234. }