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.
 
 
 
 
 
 

248 lines
7.5 KiB

//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
// STATIC: "MODE" "0..3"
// STATIC: "PALETTIZE" "0..1"
// SKIP: ( $MODE == 1 )
#include "common_ps_fxc.h"
#include "shader_constant_register_map.h"
#if ( PALETTIZE == 1 )
const int g_nColors : register( c0 );
#else
#define g_nColors 3
#endif
const float g_flColorGamma : register( c1 );
sampler sBaseTexture : register( s0 );
sampler sEmbroideryNormal : register( s1 );
sampler sBackingNormal : register( s2 );
sampler sSphereNormal : register( s3 );
sampler sSampleOffset : register( s4 );
#define g_edgeNormalScale 512.0f
#define g_detailScale 4.0f
#define g_lum float3( 0.299, 0.587, 0.114 )
struct PS_INPUT
{
float2 vTexCoord : TEXCOORD0;
};
float3 posterColor( float3 ic, float colorGamma, int nColors )
{
ic = pow(ic, colorGamma);
ic = ic * nColors;
ic = floor(ic);
ic = ic / nColors;
ic = pow(ic,1.0/colorGamma);
// levels so there's no black or white
ic = ic * 0.93726 + 0.03137;
return ic;
}
float4 maxColor( float4 c1, float4 c2 )
{
if ( dot( c1.rgb, g_lum ) > dot ( c2.rgb, g_lum ) )
{
return c1;
}
return c2;
}
float4_color_return_type main( PS_INPUT i ) : COLOR
{
float2 vOffsets[16] = { float2( -0.00160851f, -0.006003045f ),
float2( 0.00195312f, -0.005074365f ),
float2( 0.006003045f, -0.00160851f ),
float2( -0.001072344f, -0.00400203f ),
float2( 0.0014648475f, -0.00253719f ),
float2( 0.00400203f, -0.001072344f ),
float2( -0.005074365f, -0.00195312f ),
float2( -0.00253719f, -0.0014648475f ),
float2( 0.00253719f, 0.0014648475f ),
float2( 0.005074365f, 0.00195312f ),
float2( -0.00400203f, 0.001072344f ),
float2( -0.0014648475f, 0.00253719f ),
float2( 0.001072344f, 0.00400203f ),
float2( -0.006003045f, 0.00160851f ),
float2( -0.00195312f, 0.005074365f ),
float2( 0.00107234f, 0.00400203f ) };
float4 texCol = tex2D( sBaseTexture, i.vTexCoord );
float3 tc = posterColor( texCol.rgb, g_flColorGamma, g_nColors );
// derive an arbitrary rotation for stitch direction from the posterized color intensity using hue
float rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
float cr, sr;
sincos( rotation, cr, sr );
float2 tiledTexCoord = ( i.vTexCoord * g_detailScale );
float2 embroideryTexCoordRotated;
embroideryTexCoordRotated.x = tiledTexCoord.x * cr - tiledTexCoord.y * sr;
embroideryTexCoordRotated.y = tiledTexCoord.x * sr + tiledTexCoord.y * cr;
// Let's do that again, this time using the original result for perturbing the UVs so the stitches are extended slightly across color
// edge boundaries
float2 vTexCoord = i.vTexCoord;
float2 texOffset = ( 0.015625 * ( tex2D( sSampleOffset, embroideryTexCoordRotated.xy ) * 2.0f - 1.0f ) );
texOffset.x = texOffset.x * cr - texOffset.y * sr;
texOffset.y = texOffset.x * sr + texOffset.y * cr;
vTexCoord += texOffset;
texCol = tex2D( sBaseTexture, vTexCoord );
tc = posterColor( texCol.rgb, g_flColorGamma, g_nColors );
float alpha = step( 0.1f, texCol.a );
// noise reduction at color edge boundaries
float4 minCol = texCol;
int sampleCount = 0;
int k = 0;
for ( k = 0; k < 16; k = k + 2 )
{
float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] );
float3 oc = posterColor( sampleTexCol.rgb, g_flColorGamma, g_nColors );
bool isColorEdge = ( length( tc - oc ) > 0.001 );
sampleCount += isColorEdge;
minCol = maxColor( minCol, sampleTexCol );
}
if ( sampleCount > 3 )
{
tc = posterColor( minCol, g_flColorGamma, g_nColors );
texCol = minCol;
}
// Embroidery stitch normal
float4 embroideryNormSample = tex2D( sEmbroideryNormal, embroideryTexCoordRotated );
float embroiderAlpha = embroideryNormSample.a;
rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
sincos( rotation, cr, sr );
embroideryTexCoordRotated.x = tiledTexCoord.x * cr - tiledTexCoord.y * sr;
embroideryTexCoordRotated.y = tiledTexCoord.x * sr + tiledTexCoord.y * cr;
embroideryNormSample = tex2D( sEmbroideryNormal, embroideryTexCoordRotated );
embroiderAlpha = embroideryNormSample.a;
float stitchingBlend = pow( embroiderAlpha, 0.25f ) * ( sampleCount < 2 ); // mask alpha
//rotation = -atan2( 1.732f * ( tc.g - tc.b ), 2 * ( tc.r - tc.g - tc.b ) );
#if ( MODE == 3 ) // anisodir
// return anisotropy direction and an alpha that defines where the aniso highlights do not appear (where we have backing
// not stitching)
return float4( cr * 0.5f + 0.5f, sr * 0.5f + 0.5f, 0.0f, stitchingBlend * pow( embroiderAlpha, 8.0f ) );
#endif
float ao = 1.0f;
float colorEdgeSamples = 1.0f;
float2 colorEdgeNormal = float2( 0.0f, 0.0f );
#if ( MODE == 2 )
float2 alphaEdgeNormal = float2( 0.0f, 0.0f );
float alphaEdgeSamples = 1.0f;
#endif
for ( k = 0; k < 16; k++ )
{
float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] * 1.5f );
float3 oc = posterColor( sampleTexCol.rgb, g_flColorGamma, g_nColors );
bool isColorEdge = ( length( tc - oc ) < 0.3f );
// edges between color islands
colorEdgeSamples += isColorEdge;
colorEdgeNormal -= isColorEdge * vOffsets[k];
#if ( MODE == 2 )
float sampleAlpha = sampleTexCol.a;
bool isAlphaEdge = length( step( 0.1f, sampleAlpha ) - alpha ) < 0.01;
// outer edges of alpha
alphaEdgeSamples += isAlphaEdge;
alphaEdgeNormal -= isAlphaEdge * vOffsets[k];
#endif
}
colorEdgeNormal /= colorEdgeSamples;
colorEdgeNormal *= g_edgeNormalScale;
#if ( MODE == 2 )
alphaEdgeNormal /= alphaEdgeSamples;
alphaEdgeNormal *= g_edgeNormalScale;
#endif
#if ( MODE == 2 ) // bump
embroideryNormSample.xyz = embroideryNormSample.xyz * 2.0f - 1.0f;
float3 texNorm = embroideryNormSample.xyz;
// because we rotated the texcoord, we must also rotate the normal
texNorm.x = embroideryNormSample.x * cr - embroideryNormSample.y * sr;
texNorm.y = embroideryNormSample.x * sr + embroideryNormSample.y * cr;
#endif
#if ( MODE == 0 ) // diffuse
// generate ambient occlusion from stitching and posterized color island edges
ao *= 1.0f - abs( colorEdgeNormal.x ) - abs( colorEdgeNormal.y );
ao = pow( embroiderAlpha, 1.0f - ao );
ao = ao * ao * ao;
ao *= embroiderAlpha;
// diffuse color
#if ( PALETTIZE == 0 )
{
tc = texCol.rgb;
}
#endif
float3 baseColor = texCol.rgb;
// color burn the ao
baseColor = lerp( baseColor * baseColor, baseColor, ao );
//baseColor.rgb = lerp( float3( 0.0f, 0.0f, 0.0f ), baseColor.rgb, alpha );
float dropShadow = alpha;
for ( k = 0; k < 16; k++ )
{
float4 sampleTexCol = tex2D( sBaseTexture, vTexCoord + vOffsets[k] * 3.0f );
dropShadow += step( 0.1f, sampleTexCol.a );
}
dropShadow = dropShadow / 16.0f;
alpha = lerp( dropShadow, pow( embroiderAlpha, 0.75f ) + 0.1f, alpha );
return float4( baseColor, alpha ); // diffuse
#endif
#if ( MODE == 2 )
// Spherical normal gives the patch a bit of puffiness so that the anisotropic highlights in the final use-case
// have some shape and orientation
float4 sphericalNormSample = tex2D( sSphereNormal, i.vTexCoord );
float3 sphericalNorm = sphericalNormSample.xyz * 2.0f - 1.0f;
texNorm.xy += sphericalNorm.xy * 0.5f; // use full range in texture for precision, tone it down here.
// Add influence of posterized color normals and alpha edges
texNorm.xy += lerp( alphaEdgeNormal.xy, colorEdgeNormal.xy, stitchingBlend );
texNorm.xy += alphaEdgeNormal.xy;
texNorm = normalize( texNorm );
texNorm = texNorm * 0.5f + 0.5f;
// output normal
return float4( texNorm, ao );
#endif
return 0;
}