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.

129 lines
4.3 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. #include "common_ps_fxc.h"
  3. // DYNAMIC: "AO_MODE" "0..2"
  4. sampler FrontNDBuffer : register( s0 );
  5. sampler RandomReflectionSampler : register( s1 );
  6. #define NUM_SSAO_SAMPLES 9
  7. struct PS_INPUT
  8. {
  9. float2 vScreenPos : VPOS;
  10. float2 tc : TEXCOORD0;
  11. float3 vEyeRay : TEXCOORD1;
  12. };
  13. const float4 cNoiseOffset : register( c1 );
  14. const float2 g_vInvScreenExtents : register( c2 );
  15. const float3 g_vEyePt : register( c3 ); // vEyePos in world space
  16. const float3 g_vEyeDir : register( c4 ); // vForward / zFar
  17. const matrix g_mViewProj : register( c5 ); // 5, 6, 7, 8
  18. const float4 g_vRandSampleScale : register( c9 ); // xy is rand sample scale, zw is half-texel offset shift + 0.5
  19. const float4 g_vSampleRadiusNBias : register( c10 ); // x is world rad, y is depth to world space scale, z is far plane, w is bias
  20. const float4 g_vSphereSamples[NUM_SSAO_SAMPLES] : register( c11 );
  21. float ToonEdges( float2 tcCenter )
  22. {
  23. float4 vND[9];
  24. // 3x3 neighborhood offsets
  25. float2 v3x3Offsets[9] = { float2( -0.00078125f, -0.001388f ), float2( 0, -0.001388f ), float2( 0.00078125f, -0.001388f ),
  26. float2( -0.00078125f, 0 ), float2( 0, 0 ), float2( 0.00078125f, 0 ),
  27. float2( -0.00078125f, 0.001388f ), float2( 0, 0.001388f ), float2( 0.00078125f, 0.001388f ) };
  28. // Look up 3x3 neighborhood
  29. [unroll]
  30. for( int i=0; i<9; i++ )
  31. {
  32. vND[i] = tex2D( FrontNDBuffer, tcCenter + v3x3Offsets[i].xy );
  33. vND[i].xyz = normalize( vND[i].xyz );
  34. vND[i].w = vND[i].w;
  35. }
  36. // Take some local dot products
  37. float4 vNormalDots;
  38. vNormalDots.x = dot( vND[4].xyz, vND[1].xyz );
  39. vNormalDots.y = dot( vND[4].xyz, vND[3].xyz );
  40. vNormalDots.z = dot( vND[4].xyz, vND[5].xyz );
  41. vNormalDots.w = dot( vND[4].xyz, vND[7].xyz );
  42. // Threshold the four dots and combine
  43. float normalEdges = smoothstep( 0.7, 0.9, dot( vNormalDots > 0.8f, float4( 0.25, 0.25, 0.25, 0.25 ) ) );
  44. float flSobelX = 1.0f - ( abs( -vND[0].w - vND[3].w * 2.0f - vND[6].w + vND[2].w + vND[5].w * 2.0f + vND[8].w ) > 0.004 );
  45. float flSobelY = 1.0f - ( abs( -vND[0].w - vND[1].w * 2.0f - vND[2].w + vND[6].w + vND[7].w * 2.0f + vND[8].w ) > 0.004 );
  46. return normalEdges * flSobelX * flSobelY;
  47. }
  48. float3 RecoverWorldPos( float flDepth, float3 vEyeRay )
  49. {
  50. return g_vEyePt + vEyeRay * flDepth;
  51. }
  52. float4 main( PS_INPUT Input ) : COLOR0
  53. {
  54. float2 vShiftedScreenPos = Input.vScreenPos.xy + float2( 0.5, 0.5 );
  55. float2 vScreenCoord = ( vShiftedScreenPos ) * ( g_vInvScreenExtents.xy );
  56. float2 vRandSampleCoord = ( Input.vScreenPos.xy ) * ( g_vRandSampleScale.xy );
  57. // Sample from ND buffer
  58. float4 vFrontND = tex2D( FrontNDBuffer, vScreenCoord );
  59. float3 vNormal = vFrontND.xyz;
  60. float flDepth = vFrontND.a;
  61. float3 vReflectPlane = tex2D( RandomReflectionSampler, vRandSampleCoord + cNoiseOffset.xy) * 2 - 1;
  62. float3 vEyePos = RecoverWorldPos( flDepth, Input.vEyeRay );
  63. vEyePos += vNormal * flDepth * g_vSampleRadiusNBias.w;
  64. // Loop over samples
  65. float flTotalOcc = 0.0f;
  66. [unroll]
  67. for ( int s=0; s<NUM_SSAO_SAMPLES; ++s )
  68. {
  69. float3 vPosDelta = reflect( g_vSphereSamples[s], vReflectPlane );
  70. if ( dot( vPosDelta, vNormal ) < 0 )
  71. vPosDelta = reflect( vPosDelta, vNormal );
  72. float3 vSamplePos = vEyePos + g_vSampleRadiusNBias.x * vPosDelta * 0.25;
  73. // World space
  74. float flTestDepth = dot( vSamplePos - g_vEyePt, g_vEyeDir );
  75. float4 vProjSamplePos = mul( g_mViewProj, float4( vSamplePos, 1 ) );
  76. float2 vSampleCoord = vProjSamplePos.xy / vProjSamplePos.w;
  77. vSampleCoord = vSampleCoord * float2( 0.5, -0.5 ) + g_vRandSampleScale.zw;
  78. float flSampleDepth = tex2D( FrontNDBuffer, vSampleCoord ).a;
  79. float flDepthDelta = ( flTestDepth - flSampleDepth ) * g_vSampleRadiusNBias.y;
  80. float flOccMask = saturate( flDepthDelta * 10000000 );
  81. float flOcc = saturate( ( 1.0f / ( flDepthDelta + 0.618f ) ) - 0.618f );
  82. flTotalOcc += flOcc * flOccMask;
  83. }
  84. float flVis = 1 - flTotalOcc / NUM_SSAO_SAMPLES;
  85. flVis = flVis * flVis;
  86. #if ( AO_MODE == 1 ) // Toon edges only
  87. {
  88. return ToonEdges( Input.vScreenPos.xy * g_vInvScreenExtents.xy );
  89. }
  90. #elif ( AO_MODE == 2 ) // Toon edges and ambientocclusion
  91. {
  92. return float4( flVis.xxx, 1 ) * ToonEdges( Input.vScreenPos.xy * g_vInvScreenExtents.xy );
  93. }
  94. #else // ( AO_MODE == 0 ) Ambient occlusion only
  95. {
  96. return float4( flVis.xxx, 1 );
  97. }
  98. #endif
  99. }