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.

224 lines
10 KiB

  1. //========= Copyright � 1996-2007, Valve Corporation, All rights reserved. ============//
  2. // STATIC: "CONVERT_TO_SRGB" "0..1" [ps20b][= g_pHardwareConfig->NeedsShaderSRGBConversion()] [PC]
  3. // STATIC: "CONVERT_TO_SRGB" "0..0" [= 0] [XBOX]
  4. // STATIC: "STAGE" "0..2"
  5. // STATIC: "SHADER_SRGB_READ" "0..1" [ps20b]
  6. // DYNAMIC: "PIXELFOGTYPE" "0..1" [ps20b]
  7. #if defined(SHADER_MODEL_PS_2_0)
  8. #define PIXELFOGTYPE PIXEL_FOG_TYPE_NONE
  9. #endif
  10. // Includes =======================================================================================
  11. #include "common_vertexlitgeneric_dx9.h"
  12. // Texture Samplers ===============================================================================
  13. sampler g_tRefractionSampler : register( s0 );
  14. sampler g_tPortalNoiseSampler : register( s1 );
  15. sampler g_tPortalColorSampler : register( s2 );
  16. // Shaders Constants and Globals ==================================================================
  17. const float4 g_mViewProj0 : register( c0 ); // 1st row of matrix
  18. const float4 g_mViewProj1 : register( c1 ); // 2nd row of matrix
  19. const float4 g_mViewProj2 : register( c2 ); // 3rd row of matrix
  20. const float4 g_mViewProj3 : register( c3 ); // 4th row of matrix
  21. const float3 g_vConst4 : register( c4 );
  22. #define g_flPortalOpenAmount g_vConst4.x
  23. #define g_flPortalActive g_vConst4.y
  24. #define g_flPortalColorScale g_vConst4.z
  25. const float4 g_vCameraPosition : register( c5 );
  26. const float4 g_vFogParams : register( c6 );
  27. // Interpolated values ============================================================================
  28. struct PS_INPUT
  29. {
  30. float2 vUv0 : TEXCOORD0;
  31. float3 vWorldTangent : TEXCOORD1;
  32. float3 vWorldBinormal : TEXCOORD2;
  33. float4 vWorldPosition : TEXCOORD3; // Proj pos z in w
  34. float3 vProjPosForRefract : TEXCOORD4;
  35. float4 vNoiseTexCoord : TEXCOORD5;
  36. };
  37. // This is the equilavent of smoothstep built into HLSL but linear
  38. float linearstep( float iMin, float iMax, float iValue )
  39. {
  40. return saturate( ( iValue - iMin ) / ( iMax - iMin ) );
  41. }
  42. // Main ===========================================================================================
  43. float4 main( PS_INPUT i ) : COLOR
  44. {
  45. float kFlPortalOuterBorder = 0.075f; // Must match VS!
  46. float kFlPortalInnerBorder = kFlPortalOuterBorder * 4.0f;
  47. // Add a slight border around the portal opening (Do this in the VS?)
  48. //i.vUv0.xy = i.vUv0.xy * ( 1.0f + kFlPortalOuterBorder ) - ( kFlPortalOuterBorder * 0.5f );
  49. // Portal open time
  50. float flPortalOpenAmount = smoothstep( 0.0f, 1.0f, saturate( g_flPortalOpenAmount ) );
  51. //float flPortalOpenAmount = saturate( g_flPortalOpenAmount );
  52. float flPortalOpenAmountSquared = flPortalOpenAmount * flPortalOpenAmount;
  53. // Stretch values
  54. float2 vStretchVector = ( i.vUv0.xy * 2.0f ) - 1.0f;
  55. float flDistFromCenter = length( vStretchVector );
  56. float2 vStretchVectorNormalized = normalize( vStretchVector );
  57. // Stencil cutout (1.0 in hole)
  58. float flStencilCutout = step( flDistFromCenter, flPortalOpenAmountSquared );
  59. //==================================//
  60. // Stage 0: Warp pixels around hole //
  61. //==================================//
  62. #if ( STAGE == 0 )
  63. {
  64. // Unrefracted tex coords
  65. float2 vRefractTexCoordNoWarp = i.vProjPosForRefract.xy / i.vProjPosForRefract.z;
  66. // Projected screen-space tangent
  67. float3 vProjTangent;
  68. vProjTangent.x = dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj0.xyzw ); // 1st row
  69. vProjTangent.y = -dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj1.xyzw ); // 2nd row
  70. vProjTangent.z = dot( float4( i.vWorldTangent.xyz, 1.0f ), g_mViewProj3.xyzw ); // 4th row
  71. vProjTangent.xy += vProjTangent.z;
  72. vProjTangent.xy *= 0.5f;
  73. vProjTangent.xy /= vProjTangent.z;
  74. vProjTangent.xy -= vRefractTexCoordNoWarp.xy;
  75. // Projected screen-space binormal
  76. float3 vProjBinormal;
  77. vProjBinormal.x = dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj0.xyzw ); // 1st row
  78. vProjBinormal.y = -dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj1.xyzw ); // 2nd row
  79. vProjBinormal.z = dot( float4( i.vWorldBinormal.xyz, 1.0f ), g_mViewProj3.xyzw ); // 4th row
  80. vProjBinormal.xy += vProjBinormal.z;
  81. vProjBinormal.xy *= 0.5f;
  82. vProjBinormal.xy /= vProjBinormal.z;
  83. vProjBinormal.xy -= vRefractTexCoordNoWarp.xy;
  84. // Tangent-space uv offset
  85. float2 vTangentRefract = -vStretchVectorNormalized * flPortalOpenAmountSquared * ( 1.0f - pow( saturate( flDistFromCenter ), 64.0f ) );
  86. vTangentRefract.xy *= smoothstep( ( flPortalOpenAmount * 1.5f ), flPortalOpenAmount, flDistFromCenter );
  87. // Note: This works well perpendicular to the surface, but because the projection is non-linear, it's refracty very edge on
  88. float2 kPortalRadius = { 32.0f, 32.0f }; // Should be 32, 54 but this reduces the artifacts from the comment above
  89. vTangentRefract.xy *= kPortalRadius.xy;
  90. // Generate refracteds screen-space uv
  91. float2 vRefractTexCoord = vRefractTexCoordNoWarp.xy;
  92. vRefractTexCoord.xy += vTangentRefract.x * vProjTangent.xy;
  93. vRefractTexCoord.xy -= vTangentRefract.y * vProjBinormal.xy;
  94. // Fetch color from texture
  95. float3 cRefract = tex2D( g_tRefractionSampler, vRefractTexCoord.xy );
  96. // In some cases, we have to convert this render target from sRGB to Linear ourselves here
  97. #if ( SHADER_SRGB_READ == 1 )
  98. {
  99. cRefract = GammaToLinear( cRefract );
  100. }
  101. #endif
  102. // Darken the ring around the portal as it's opening to help it stand out on plain walls
  103. float flHoleEdge = flPortalOpenAmountSquared;
  104. float flDimEdge = saturate( flPortalOpenAmount * 2.0f );
  105. float flDarkeningRing = linearstep( flHoleEdge - 0.01f, flDimEdge, flDistFromCenter );
  106. flDarkeningRing = ( abs( flDarkeningRing * 2.0f - 1.0f ) * 0.15f ) + 0.85f;
  107. //===============//
  108. // Combine terms //
  109. //===============//
  110. float4 result;
  111. result.rgb = cRefract.rgb;
  112. result.rgb *= flDarkeningRing;
  113. // Alpha test away outside the portal oval
  114. result.a = step( flDistFromCenter, 1.0f );
  115. return FinalOutput( result, 0.0f, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE );
  116. }
  117. #endif
  118. //============================================================================//
  119. // Stage 1: Cut a hole in the stencil buffer (only render pixels in the hole) //
  120. //============================================================================//
  121. #if ( STAGE == 1 )
  122. {
  123. float4 result;
  124. result.rgb = 0.0f;
  125. result.a = flStencilCutout;
  126. //result = 0.0f; // Disable the hole for debugging
  127. return result;
  128. }
  129. #endif
  130. //============================================//
  131. // Stage 2: Fire effect around rim of opening //
  132. //============================================//
  133. #if ( STAGE == 2 )
  134. {
  135. // Outer effect mask
  136. float flOuterEffectMask = ( 1.0f - linearstep( flPortalOpenAmountSquared, flPortalOpenAmountSquared + kFlPortalOuterBorder, flDistFromCenter ) ) * ( 1.0f - flStencilCutout );
  137. // Inner effect mask
  138. float flInnerEffectMask = ( linearstep( flPortalOpenAmountSquared - kFlPortalInnerBorder, flPortalOpenAmountSquared, flDistFromCenter ) ) * ( flStencilCutout );
  139. // Fade it in as the portal is opening
  140. //float flPortalActive = smoothstep( 0.0f, 1.0f, saturate( g_flPortalActive ) );
  141. float flPortalActive = saturate( g_flPortalActive ); // This is good enough...smoothstep above is not necessary
  142. //flPortalActive = linearstep( 0.0f, saturate( flDistFromCenter ), saturate( flPortalActive ) ); // Experiment to fade from center out
  143. float flEffectFadeIn = max( saturate( flPortalOpenAmount * 2.5f ), ( 1.0f - flPortalActive ) );
  144. // Combine mask terms
  145. float flEffectMask = ( flInnerEffectMask + flOuterEffectMask ) * flEffectFadeIn;
  146. //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.
  147. float4 cNoiseTexel1 = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.xy );
  148. float4 cNoiseTexel2 = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.wz - cNoiseTexel1.rg*0.02 );
  149. cNoiseTexel1.rgba = tex2D( g_tPortalNoiseSampler, i.vNoiseTexCoord.xy - cNoiseTexel2.rg*0.02 );
  150. //float flNoise = ( ( cNoiseTexel1.g * cNoiseTexel2.g ) * 2.0f ); // More broken up flames and crazier
  151. float flNoise = ( ( cNoiseTexel1.g + cNoiseTexel2.g ) * 0.5f ); // More solid flames and calmer
  152. float flPortalActiveWithNoise = smoothstep( 0.0f, flNoise, flPortalActive );
  153. float kFlBorderSoftness = 0.875f; // Larger numbers give more color in the middle when portal is inactive
  154. float flBorderMaskWithNoise = ( 1.0f - smoothstep( flEffectMask - kFlBorderSoftness, flEffectMask + kFlBorderSoftness, flNoise ) );
  155. flNoise = flBorderMaskWithNoise;
  156. flEffectMask *= flBorderMaskWithNoise;
  157. // This will get stuffed in alpha
  158. float flTransparancy = saturate( flEffectMask + ( flStencilCutout * ( 1.0f - flPortalActiveWithNoise ) ) ) * 1.5f; // Magic number at the end will make the flames thicker with larger numbers
  159. // This will make the portals shift in color from bottom to top (Set to 1.0f to disable)
  160. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.9f ) + 0.1f; // More extreme
  161. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.85f ) + 0.15f;
  162. float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.8f ) + 0.2f;
  163. //float flBottomToTopBrightnessShift = ( pow( abs(i.vUv0.y), 1.5f ) * 0.75f ) + 0.25f; // More subtle (needs higher color scale below)
  164. //float flBottomToTopBrightnessShift = 1.0f; // Disabled
  165. // Fetch color from 1D texture
  166. float4 cFlameColor = tex1D( g_tPortalColorSampler, pow( flNoise, 0.5f ) * flBottomToTopBrightnessShift * flTransparancy );
  167. cFlameColor.rgb *= g_flPortalColorScale; // Brighten colors to make it look more emissive
  168. // Generate final color result
  169. float4 result;
  170. result.rgb = cFlameColor.rgb;
  171. result.a = flTransparancy;
  172. //result.rgb *= result.a; // This will give better definition to the flames but also darkens the outer rim
  173. //result.rgb = pow( result.rgb, 1.5f );
  174. //result.rgb *= result.rgb; // Make it look hotter
  175. // Debugging
  176. //result.rgba = flBorderMaskWithNoise;
  177. //result.rgba = flEffectMask;
  178. //result.rgba = flTransparancy;
  179. //result.rgba = flPortalActive * flStencilCutout;
  180. // Apply fog and deal with HDR
  181. float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_vFogParams, g_vCameraPosition.z, i.vWorldPosition.z, i.vWorldPosition.w );
  182. return FinalOutput( result, fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR );
  183. }
  184. #endif
  185. }