|
|
//========== 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; }
|