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.

247 lines
7.5 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ==========//
  2. // STATIC: "MODE" "0..3"
  3. // STATIC: "PALETTIZE" "0..1"
  4. // SKIP: ( $MODE == 1 )
  5. #include "common_ps_fxc.h"
  6. #include "shader_constant_register_map.h"
  7. #if ( PALETTIZE == 1 )
  8. const int g_nColors : register( c0 );
  9. #else
  10. #define g_nColors 3
  11. #endif
  12. const float g_flColorGamma : register( c1 );
  13. sampler sBaseTexture : register( s0 );
  14. sampler sEmbroideryNormal : register( s1 );
  15. sampler sBackingNormal : register( s2 );
  16. sampler sSphereNormal : register( s3 );
  17. sampler sSampleOffset : register( s4 );
  18. #define g_edgeNormalScale 512.0f
  19. #define g_detailScale 4.0f
  20. #define g_lum float3( 0.299, 0.587, 0.114 )
  21. struct PS_INPUT
  22. {
  23. float2 vTexCoord : TEXCOORD0;
  24. };
  25. float3 posterColor( float3 ic, float colorGamma, int nColors )
  26. {
  27. ic = pow(ic, colorGamma);
  28. ic = ic * nColors;
  29. ic = floor(ic);
  30. ic = ic / nColors;
  31. ic = pow(ic,1.0/colorGamma);
  32. // levels so there's no black or white
  33. ic = ic * 0.93726 + 0.03137;
  34. return ic;
  35. }
  36. float4 maxColor( float4 c1, float4 c2 )
  37. {
  38. if ( dot( c1.rgb, g_lum ) > dot ( c2.rgb, g_lum ) )
  39. {
  40. return c1;
  41. }
  42. return c2;
  43. }
  44. float4_color_return_type main( PS_INPUT i ) : COLOR
  45. {
  46. float2 vOffsets[16] = { float2( -0.00160851f, -0.006003045f ),
  47. float2( 0.00195312f, -0.005074365f ),
  48. float2( 0.006003045f, -0.00160851f ),
  49. float2( -0.001072344f, -0.00400203f ),
  50. float2( 0.0014648475f, -0.00253719f ),
  51. float2( 0.00400203f, -0.001072344f ),
  52. float2( -0.005074365f, -0.00195312f ),
  53. float2( -0.00253719f, -0.0014648475f ),
  54. float2( 0.00253719f, 0.0014648475f ),
  55. float2( 0.005074365f, 0.00195312f ),
  56. float2( -0.00400203f, 0.001072344f ),
  57. float2( -0.0014648475f, 0.00253719f ),
  58. float2( 0.001072344f, 0.00400203f ),
  59. float2( -0.006003045f, 0.00160851f ),
  60. float2( -0.00195312f, 0.005074365f ),
  61. float2( 0.00107234f, 0.00400203f ) };
  62. float4 texCol = tex2D( sBaseTexture, i.vTexCoord );
  63. float3 tc = posterColor( texCol.rgb, g_flColorGamma, g_nColors );
  64. // derive an arbitrary rotation for stitch direction from the posterized color intensity using hue
  65. float rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
  66. float cr, sr;
  67. sincos( rotation, cr, sr );
  68. float2 tiledTexCoord = ( i.vTexCoord * g_detailScale );
  69. float2 embroideryTexCoordRotated;
  70. embroideryTexCoordRotated.x = tiledTexCoord.x * cr - tiledTexCoord.y * sr;
  71. embroideryTexCoordRotated.y = tiledTexCoord.x * sr + tiledTexCoord.y * cr;
  72. // Let's do that again, this time using the original result for perturbing the UVs so the stitches are extended slightly across color
  73. // edge boundaries
  74. float2 vTexCoord = i.vTexCoord;
  75. float2 texOffset = ( 0.015625 * ( tex2D( sSampleOffset, embroideryTexCoordRotated.xy ) * 2.0f - 1.0f ) );
  76. texOffset.x = texOffset.x * cr - texOffset.y * sr;
  77. texOffset.y = texOffset.x * sr + texOffset.y * cr;
  78. vTexCoord += texOffset;
  79. texCol = tex2D( sBaseTexture, vTexCoord );
  80. tc = posterColor( texCol.rgb, g_flColorGamma, g_nColors );
  81. float alpha = step( 0.1f, texCol.a );
  82. // noise reduction at color edge boundaries
  83. float4 minCol = texCol;
  84. int sampleCount = 0;
  85. int k = 0;
  86. for ( k = 0; k < 16; k = k + 2 )
  87. {
  88. float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] );
  89. float3 oc = posterColor( sampleTexCol.rgb, g_flColorGamma, g_nColors );
  90. bool isColorEdge = ( length( tc - oc ) > 0.001 );
  91. sampleCount += isColorEdge;
  92. minCol = maxColor( minCol, sampleTexCol );
  93. }
  94. if ( sampleCount > 3 )
  95. {
  96. tc = posterColor( minCol, g_flColorGamma, g_nColors );
  97. texCol = minCol;
  98. }
  99. // Embroidery stitch normal
  100. float4 embroideryNormSample = tex2D( sEmbroideryNormal, embroideryTexCoordRotated );
  101. float embroiderAlpha = embroideryNormSample.a;
  102. rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
  103. sincos( rotation, cr, sr );
  104. embroideryTexCoordRotated.x = tiledTexCoord.x * cr - tiledTexCoord.y * sr;
  105. embroideryTexCoordRotated.y = tiledTexCoord.x * sr + tiledTexCoord.y * cr;
  106. embroideryNormSample = tex2D( sEmbroideryNormal, embroideryTexCoordRotated );
  107. embroiderAlpha = embroideryNormSample.a;
  108. float stitchingBlend = pow( embroiderAlpha, 0.25f ) * ( sampleCount < 2 ); // mask alpha
  109. //rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
  110. #if ( MODE == 3 ) // anisodir
  111. // return anisotropy direction and an alpha that defines where the aniso highlights do not appear (where we have backing
  112. // not stitching)
  113. return float4( cr * 0.5f + 0.5f, sr * 0.5f + 0.5f, 0.0f, stitchingBlend * pow( embroiderAlpha, 8.0f ) );
  114. #endif
  115. float ao = 1.0f;
  116. float colorEdgeSamples = 1.0f;
  117. float2 colorEdgeNormal = float2( 0.0f, 0.0f );
  118. #if ( MODE == 2 )
  119. float2 alphaEdgeNormal = float2( 0.0f, 0.0f );
  120. float alphaEdgeSamples = 1.0f;
  121. #endif
  122. for ( k = 0; k < 16; k++ )
  123. {
  124. float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] * 1.5f );
  125. float3 oc = posterColor( sampleTexCol.rgb, g_flColorGamma, g_nColors );
  126. bool isColorEdge = ( length( tc - oc ) < 0.3f );
  127. // edges between color islands
  128. colorEdgeSamples += isColorEdge;
  129. colorEdgeNormal -= isColorEdge * vOffsets[k];
  130. #if ( MODE == 2 )
  131. float sampleAlpha = sampleTexCol.a;
  132. bool isAlphaEdge = length( step( 0.1f, sampleAlpha ) - alpha ) < 0.01;
  133. // outer edges of alpha
  134. alphaEdgeSamples += isAlphaEdge;
  135. alphaEdgeNormal -= isAlphaEdge * vOffsets[k];
  136. #endif
  137. }
  138. colorEdgeNormal /= colorEdgeSamples;
  139. colorEdgeNormal *= g_edgeNormalScale;
  140. #if ( MODE == 2 )
  141. alphaEdgeNormal /= alphaEdgeSamples;
  142. alphaEdgeNormal *= g_edgeNormalScale;
  143. #endif
  144. #if ( MODE == 2 ) // bump
  145. embroideryNormSample.xyz = embroideryNormSample.xyz * 2.0f - 1.0f;
  146. float3 texNorm = embroideryNormSample.xyz;
  147. // because we rotated the texcoord, we must also rotate the normal
  148. texNorm.x = embroideryNormSample.x * cr - embroideryNormSample.y * sr;
  149. texNorm.y = embroideryNormSample.x * sr + embroideryNormSample.y * cr;
  150. #endif
  151. #if ( MODE == 0 ) // diffuse
  152. // generate ambient occlusion from stitching and posterized color island edges
  153. ao *= 1.0f - abs( colorEdgeNormal.x ) - abs( colorEdgeNormal.y );
  154. ao = pow( embroiderAlpha, 1.0f - ao );
  155. ao = ao * ao * ao;
  156. ao *= embroiderAlpha;
  157. // diffuse color
  158. #if ( PALETTIZE == 0 )
  159. {
  160. tc = texCol.rgb;
  161. }
  162. #endif
  163. float3 baseColor = texCol.rgb;
  164. // color burn the ao
  165. baseColor = lerp( baseColor * baseColor, baseColor, ao );
  166. //baseColor.rgb = lerp( float3( 0.0f, 0.0f, 0.0f ), baseColor.rgb, alpha );
  167. float dropShadow = alpha;
  168. for ( k = 0; k < 16; k++ )
  169. {
  170. float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] * 3.0f );
  171. dropShadow += step( 0.1f, sampleTexCol.a );
  172. }
  173. dropShadow = dropShadow / 16.0f;
  174. alpha = lerp( dropShadow, pow( embroiderAlpha, 0.75f ) + 0.1f, alpha );
  175. return float4( baseColor, alpha ); // diffuse
  176. #endif
  177. #if ( MODE == 2 )
  178. // Spherical normal gives the patch a bit of puffiness so that the anisotropic highlights in the final use-case
  179. // have some shape and orientation
  180. float4 sphericalNormSample = tex2D( sSphereNormal, i.vTexCoord );
  181. float3 sphericalNorm = sphericalNormSample.xyz * 2.0f - 1.0f;
  182. texNorm.xy += sphericalNorm.xy * 0.5f; // use full range in texture for precision, tone it down here.
  183. // Add influence of posterized color normals and alpha edges
  184. texNorm.xy += lerp( alphaEdgeNormal.xy, colorEdgeNormal.xy, stitchingBlend );
  185. texNorm.xy += alphaEdgeNormal.xy;
  186. texNorm = normalize( texNorm );
  187. texNorm = texNorm * 0.5f + 0.5f;
  188. // output normal
  189. return float4( texNorm, ao );
  190. #endif
  191. return 0;
  192. }