//========== Copyright (c) Valve Corporation, All rights reserved. ==========// // STATIC: "COMPOSITEMODE" "0..2" // STATIC: "CASCADED_SHADOW_MAPPING" "0..1" [ps30] // STATIC: "CSM_MODE" "0..0" [ = 0 ] [ps20] [ps20b] [PC] // STATIC: "CSM_MODE" "0..3" [ps30] [PC] // STATIC: "USE_PATTERN1" "0..1" // STATIC: "USE_PATTERN2" "0..1" // STATIC: "USE_PATTERN_OFFSET" "0..1" // STATIC: "USE_LOGO1" "0..1" // STATIC: "USE_LOGO2" "0..1" // STATIC: "SWAP_PATTERN_MASKS" "0..1" // DYNAMIC: "NUM_LIGHTS" "0..2" [ps20] // DYNAMIC: "NUM_LIGHTS" "0..4" [ps20b] [ps30] // DYNAMIC: "DYN_CSM_ENABLED" "0..1" // DYNAMIC: "AO_MODE" "0..1" // SKIP: ( ( $COMPOSITEMODE == 1 ) && ( $CASCADED_SHADOW_MAPPING != 0 ) ) // SKIP: ( ( $COMPOSITEMODE == 1 ) && ( $NUM_LIGHTS != 0 ) ) // SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $DYN_CSM_ENABLED == 1 ) // SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $CSM_MODE != 0 ) // SKIP: ( $USE_PATTERN2 == 1 ) && ( $USE_PATTERN1 == 0 ) // SKIP: ( $USE_PATTERN_OFFSET == 1 ) && ( $USE_PATTERN1 == 0 && $USE_PATTERN2 == 0 ) // SKIP: ( $SWAP_PATTERN_MASKS == 1 ) && ( $USE_PATTERN1 == 0 && $USE_PATTERN2 == 0 ) // SKIP: ( $USE_LOGO2 == 1 ) && ( $USE_LOGO1 == 0 ) // SKIP: ( $COMPOSITEMODE == 2 ) && ( $USE_PATTERN1 == 1 ) // SKIP: ( $COMPOSITEMODE == 2 ) && ( $USE_PATTERN2 == 1 ) // SKIP: ( $COMPOSITEMODE == 2 ) && ( $USE_PATTERN_OFFSET == 1 ) // SKIP: ( $COMPOSITEMODE == 2 ) && ( $USE_LOGO1 == 1 ) // SKIP: ( $COMPOSITEMODE == 2 ) && ( $USE_LOGO2 == 1 ) // SKIP: ( $AO_MODE == 1 ) && ( $COMPOSITEMODE == 1 ) // SKIP: ( $AO_MODE == 1 ) && ( $NUM_LIGHTS != 0 ) // SKIP: ( $AO_MODE == 1 ) && ( $DYN_CSM_ENABLED == 1 ) #include "common_ps_fxc.h" #include "shader_constant_register_map.h" #define NEED_COMPOSITE_INPUTS ( COMPOSITEMODE == 0 || COMPOSITEMODE == 1 ) //3D preview or 2D composite #define IS_3D_MODE ( COMPOSITEMODE != 1 ) //Not mode 1, that is anything other than 2D composite mode. Silly name to avoid starting with a numeral #define IS_3D_POSTCOMPOSITE ( COMPOSITEMODE == 2 ) #define USE_HALF_LAMBERT false #define SSAO_EFFECT_MULTIPLIER 0.9f // SAMPLERS sampler BaseSampler : register( s0 ); sampler NormalMapSampler : register( s1 ); #if AO_MODE == 0 sampler SSAOMapSampler : register( s10 ); #endif #if NEED_COMPOSITE_INPUTS sampler AOMapSampler : register( s2 ); sampler MaskMapSampler : register( s3 ); #if USE_PATTERN1 sampler Pattern1Sampler : register( s4 ); #endif #if USE_PATTERN2 sampler Pattern2Sampler : register( s6 ); #endif sampler GrimeSampler : register( s7 ); #if USE_PATTERN_OFFSET sampler OffsetSampler : register( s8 ); #endif #if USE_LOGO1 sampler LogoSampler : register( s9 ); #endif #endif #if IS_3D_MODE sampler NormalizeSampler : register( s5 ); #endif #if ( CASCADED_SHADOW_MAPPING == 1 ) sampler CSMDepthAtlasSampler : register( s15 ); #undef CASCADE_SIZE #define CASCADE_SIZE 3 #define CSM_ENABLED 1 //#define CSM_VERTEXLIT_AND_UNLIT_GENERIC_BUMP //use the same CSM const registers? #include "csm_common_fxc.h" #endif // REGISTERS #if IS_3D_MODE const float3 g_cAmbientCube[6] : register( PSREG_AMBIENT_CUBE ); // 4 through 9 PixelShaderLightInfo cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 20 through 25 //for normalized screen-space coords const float4 g_fvConstRegister17 : register( c17 ); const float4 g_fvConstRegister18 : register( c18 ); #define g_vEyePos g_fvConstRegister18.xyz #define g_flElementDistance g_fvConstRegister18.w #endif #if NEED_COMPOSITE_INPUTS const float4 g_fvConstRegister0 : register( c0 ); const float4 g_fvConstRegister1 : register( c1 ); const float4 g_fvConstRegister2 : register( c2 ); const float4 g_fvConstRegister10 : register( c10 ); const float4 g_fvConstRegister11 : register( c11 ); const float4 g_fvConstRegister12 : register( c12 ); #define g_vPattern1Color1 float3( g_fvConstRegister0.x, g_fvConstRegister0.y, g_fvConstRegister0.z ) #define g_vPattern1Color2 float3( g_fvConstRegister1.x, g_fvConstRegister1.y, g_fvConstRegister1.z ) #define g_vPattern1Color3 float3( g_fvConstRegister2.x, g_fvConstRegister2.y, g_fvConstRegister2.z ) #define g_vPattern1Color4 float3( g_fvConstRegister0.w, g_fvConstRegister1.w, g_fvConstRegister2.w ) #define g_vPattern2Color1 float3( g_fvConstRegister10.x, g_fvConstRegister10.y, g_fvConstRegister10.z ) #define g_vPattern2Color2 float3( g_fvConstRegister11.x, g_fvConstRegister11.y, g_fvConstRegister11.z ) #define g_vPattern2Color3 float3( g_fvConstRegister12.x, g_fvConstRegister12.y, g_fvConstRegister12.z ) #define g_vPattern2Color4 float3( g_fvConstRegister10.w, g_fvConstRegister11.w, g_fvConstRegister12.w ) const float4 g_fvConstRegister13 : register( c13 ); #define g_vPattern1Scale g_fvConstRegister13.x #define g_vPattern2Scale g_fvConstRegister13.y #define g_flCavityPower g_fvConstRegister13.z #define g_flOffsetAmount g_fvConstRegister13.w const float4 g_fvConstRegister14 : register( c14 ); #define g_vLogoOffset g_fvConstRegister14.xy #define g_fLogoScale g_fvConstRegister14.z #define g_fLogoRotation g_fvConstRegister14.w const float4 g_fvConstRegister15 : register( c15 ); #define g_vLogo2Offset g_fvConstRegister15.xy #define g_fLogo2Scale g_fvConstRegister15.z #define g_fLogo2Rotation g_fvConstRegister15.w const float4 g_fvConstRegister16 : register( c16 ); #define g_fLogoMaskCrispnessMin g_fvConstRegister16.x #define g_fLogoMaskCrispnessMax g_fvConstRegister16.y #define g_fLogoWear g_fvConstRegister16.z #endif #define DESAT float3( 0.3f, 0.59f, 0.11f ) float2 rotate( float2 inputUV, float rotateTau ) { return float2( inputUV.x * cos(rotateTau) - inputUV.y * sin(rotateTau), inputUV.x * sin(rotateTau) + inputUV.y * cos(rotateTau) ); } float2 getLogoUV( float2 inputUV, float2 inputOffset, float inputScale, float inputRotation ) { float2 vLogoUV = inputUV; vLogoUV -= float2( 0.5f , 0.5f ); vLogoUV -= inputOffset; vLogoUV *= inputScale; vLogoUV = rotate( vLogoUV, inputRotation ); return (vLogoUV + float2( 0.5f , 0.5f )); } struct PS_INPUT { float4 vBaseUV_PatternUV : TEXCOORD0; float4 vWearUV_GrungeUV : TEXCOORD1; #if IS_3D_MODE float4 lightAtten : TEXCOORD2; float3 worldPos : TEXCOORD3; float3x3 tangentSpaceTranspose : TEXCOORD4; // second row : TEXCOORD5; // third row : TEXCOORD6; float4 vProjPos : TEXCOORD7; #endif }; float3 PhotoshopOverlay( float3 cBase, float3 cBlend ) { float3 cNew; cNew = step( 0.5, cBase ); cNew = lerp( (cBase*cBlend*2), (1.0-(2.0*(1.0-cBase)*(1.0-cBlend))), cNew ); return cNew; } float2 PackFloat2( float f) { float2 packed; f *= 256.0f; packed.x = floor( f ) * (1.0f / 256.0f); packed.y = frac( f ); return packed; } float4_color_return_type main( PS_INPUT i ) : COLOR { #if AO_MODE == 1 float flLocalDistance = smoothstep( g_flElementDistance - 40.0f, g_flElementDistance + 40.0f, length( g_vEyePos.xyz - i.worldPos.xyz ) ); float3 vNormalTexel = 2.0f * (tex2D( NormalMapSampler, i.vBaseUV_PatternUV.xy ).rgb) - 1.0f; float3 vWorldPixelNormal = normalize( mul( (float3x3)i.tangentSpaceTranspose, vNormalTexel ) ); float3 vEyeDir = normalize(g_vEyePos.xyz - i.worldPos.xyz); float3 vLeftDir = cross( vEyeDir, float3(0,0,1) ); float3 vUpDir = cross( vEyeDir, vLeftDir ); return float4( (dot( vLeftDir, vWorldPixelNormal ) + 1.0f) * 0.5f, (dot( vUpDir, vWorldPixelNormal ) + 1.0f) * 0.5f, PackFloat2( flLocalDistance ) ); //return float4( dot( vLeftDir, vWorldPixelNormal ), dot( vUpDir, vWorldPixelNormal ), PackFloat2( flLocalDistance ) ); #else float3 vColorTexel = tex2D( BaseSampler, i.vBaseUV_PatternUV.xy ).rgb; #if NEED_COMPOSITE_INPUTS float3 vMasksTexel = tex2D( MaskMapSampler, i.vBaseUV_PatternUV.xy ).rgb; float3 vAOTexel = tex2D( AOMapSampler, i.vBaseUV_PatternUV.xy ).rgb; float flCavityPostPow = pow(vAOTexel.g, g_flCavityPower); vAOTexel.b = smoothstep( g_fLogoMaskCrispnessMin, g_fLogoMaskCrispnessMax, vAOTexel.b ); float3 vGrime = tex2D( GrimeSampler, i.vBaseUV_PatternUV.xy ).rgb; #if USE_PATTERN1 #if SWAP_PATTERN_MASKS vMasksTexel.rg = vMasksTexel.gr; #endif float2 vPatternUV = i.vBaseUV_PatternUV.xy; #if USE_PATTERN_OFFSET float distAlphaMask = tex2D( OffsetSampler, i.vBaseUV_PatternUV.xy ).a; //offset pattern UVs by distance-field offset mask vPatternUV.x += step( 0.5f, distAlphaMask ) * g_flOffsetAmount; #endif //sample patterns float3 vColorPattern1 = tex2D( Pattern1Sampler, vPatternUV * g_vPattern1Scale ).rgb; #if USE_PATTERN2 float3 vColorPattern2 = tex2D( Pattern2Sampler, vPatternUV * g_vPattern2Scale ).rgb; #endif //bash pattern1 by solid color mask (fixme) vColorPattern1 = lerp( vColorPattern1, float3(0,1,0), vMasksTexel.b ); #if USE_PATTERN2 vColorPattern2 = lerp( vColorPattern2, float3(0,0,1), vMasksTexel.b ); #endif //colorize patterns vColorPattern1 = lerp( lerp( lerp( g_vPattern1Color1, g_vPattern1Color2, vColorPattern1.r ), g_vPattern1Color3, vColorPattern1.g ), g_vPattern1Color4, vColorPattern1.b ); #if USE_PATTERN2 vColorPattern2 = lerp( lerp( lerp( g_vPattern2Color1, g_vPattern2Color2, vColorPattern2.r ), g_vPattern2Color3, vColorPattern2.g ), g_vPattern2Color4, vColorPattern2.b ); #endif //apply colorized patterns using per-pattern masks vColorTexel = lerp( vColorTexel, vColorPattern1, vMasksTexel.r ); #if USE_PATTERN2 vColorTexel = lerp( vColorTexel, vColorPattern2, vMasksTexel.g ); #endif #if USE_PATTERN_OFFSET //darken seams caused by pattern offset float flPatternOffsetSeamMask = saturate( (abs(distAlphaMask - 0.5f) * 8.0f) + 0.5f); vColorTexel *= flPatternOffsetSeamMask; #endif #endif //USE_PATTERN1 #if USE_LOGO1 float fLogoMaskCavity = vAOTexel.b * pow( (1.0f - flCavityPostPow), g_fLogoWear ); //logo1 float4 vLogoColor = tex2D( LogoSampler, getLogoUV( i.vBaseUV_PatternUV.xy, g_vLogoOffset, g_fLogoScale, g_fLogoRotation ) ); //apply logo with alpha vColorTexel.rgb = lerp( vColorTexel.rgb, vLogoColor.rgb, vLogoColor.a * fLogoMaskCavity ); #if USE_LOGO2 //logo2 float4 vLogo2Color = tex2D( LogoSampler, getLogoUV( i.vBaseUV_PatternUV.xy, g_vLogo2Offset, g_fLogo2Scale, g_fLogo2Rotation ) ); //apply logo2 with alpha vColorTexel.rgb = lerp( vColorTexel.rgb, vLogo2Color.rgb, vLogo2Color.a * fLogoMaskCavity ); #endif #endif //USE_LOGO1 //desaturate by cavity and apply grime vColorTexel = lerp( vColorTexel, dot(DESAT, vColorTexel) * vGrime.rgb, flCavityPostPow ); //apply ao vColorTexel *= (2.0f * vAOTexel.r); #endif // NEED_COMPOSITE_INPUTS #if !(IS_3D_MODE) // (2d compositing) // draw pink squares onto the composite to make sure it's working //if ( fmod( i.vBaseUV_PatternUV.x, 0.1f ) < 0.05f && fmod( i.vBaseUV_PatternUV.y, 0.1f ) < 0.05f ) //{ // vColorTexel = float3(1,0,1); //} float4 cOut = float4( vColorTexel.rgb, 1 ); return cOut; #else // (any 3d mode) // apply normal map driven lighting in 3d mode float3 vNormalTexel = 2.0f * (tex2D( NormalMapSampler, i.vBaseUV_PatternUV.xy ).rgb) - 1.0f; float3 vWorldPixelNormal = normalize( mul( (float3x3)i.tangentSpaceTranspose, vNormalTexel ) ); //return float4( vNormalTexel, 1 ); #if ( (CASCADED_SHADOW_MAPPING == 1) && (DYN_CSM_ENABLED == 1) ) float flCSMShadow = CSMComputeShadowing( i.worldPos ); #else float flCSMShadow = 1.0f; #endif float3 linearColor = PixelShaderDoLighting( i.worldPos, vWorldPixelNormal, float3( 0.1f, 0.1f, 0.1f), false, true, i.lightAtten, g_cAmbientCube, NormalizeSampler, NUM_LIGHTS, cLightInfo, USE_HALF_LAMBERT, false, NULL, flCSMShadow ); #if IS_3D_POSTCOMPOSITE //incorporate AO from the offscreen buffer rendered earlier in the frame float2 vScreenPos = (i.vProjPos.xy / i.vProjPos.w) * g_fvConstRegister17.xy + g_fvConstRegister17.zw; vScreenPos += float2( 0.0005f, 0.0005f ); float3 vAO = tex2D( SSAOMapSampler, vScreenPos).rgb; float flCenterDepth = length( g_vEyePos.xyz - i.worldPos.xyz ); float flDepthFadeDistance = smoothstep( 500.0f, 400.f, flCenterDepth ); linearColor = lerp( linearColor, linearColor * vAO, flDepthFadeDistance * SSAO_EFFECT_MULTIPLIER ); #endif // IS_3D_POSTCOMPOSITE vColorTexel *= linearColor; //vColorTexel = linearColor; float4 cOut = float4( vColorTexel.rgb, 1 ); return FinalOutput( cOut, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_LINEAR ); #endif // any 3D mode #endif // not AO_MODE }