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