//========== Copyright (c) Valve Corporation, All rights reserved. ==========// // STATIC: "MAGNIFY" "0..1" // STATIC: "BLUR" "0..1" // STATIC: "FADEOUTONSILHOUETTE" "0..1" // STATIC: "CUBEMAP" "0..1" // STATIC: "REFRACTTINTTEXTURE" "0..1" // STATIC: "MASKED" "0..1" // STATIC: "COLORMODULATE" "0..1" // STATIC: "SECONDARY_NORMAL" "0..1" // STATIC: "MIRRORABOUTVIEWPORTEDGES" "0..1" [XBOX] // STATIC: "MIRRORABOUTVIEWPORTEDGES" "0..0" [PC] #include "common_fog_ps_fxc.h" // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" [ps20b] [PC] // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0" [ps20b] [XBOX] // SKIP: $MASKED && $BLUR #if defined( SHADER_MODEL_PS_2_0 ) # define WRITE_DEPTH_TO_DESTALPHA 0 #endif #ifdef _X360 #define SHADER_SRGB_READ 1 #endif #include "common_ps_fxc.h" #include "shader_constant_register_map.h" sampler NormalSampler2 : register( s1 ); sampler RefractSampler : register( s2 ); sampler NormalSampler : register( s3 ); #if CUBEMAP sampler EnvmapSampler : register( s4 ); #endif #if REFRACTTINTTEXTURE sampler RefractTintSampler : register( s5 ); #endif const float3 g_EnvmapTint : register( c0 ); const float3 g_RefractTint : register( c1 ); const float3 g_EnvmapContrast : register( c2 ); const float3 g_EnvmapSaturation : register( c3 ); const float4 g_NormalizedViewportMinXYMaxWZ : register( c4 ); const float4 g_c5 : register( c5 ); #define g_RefractScale g_c5.x #define g_flTime g_c5.w const float4 g_c6 : register( c6 ); #define g_vMagnifyCenter g_c6.xy #define g_flInverseMagnifyScale g_c6.z const float4 g_FogParams : register( PSREG_FOG_PARAMS ); const float4 g_EyePos_SpecExponent : register( PSREG_EYEPOS_SPEC_EXPONENT ); static const int g_BlurCount = BLUR; static const float g_BlurFraction = 1.0f / 512.0f; static const float g_HalfBlurFraction = 0.5 * g_BlurFraction; static const float4 g_BlurFractionVec = float4( g_BlurFraction, g_HalfBlurFraction, -g_BlurFraction,-g_HalfBlurFraction ); struct PS_INPUT { float4 vBumpTexCoord : TEXCOORD0; // NormalMap1 in xy, NormalMap2 in wz float3 vTangentVertToEyeVector : TEXCOORD1; float3 vWorldNormal : TEXCOORD2; float3 vWorldTangent : TEXCOORD3; float3 vWorldBinormal : TEXCOORD4; float3 vRefractXYW : TEXCOORD5; float3 vWorldViewVector : TEXCOORD6; #if COLORMODULATE float4 ColorModulate : COLOR0; #endif float4 worldPos_projPosZ : TEXCOORD7; // Necessary for pixel fog }; float4 main( PS_INPUT i ) : COLOR { float3 result; float pixelFogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.xyz, i.worldPos_projPosZ.xyz, i.worldPos_projPosZ.w ); #if FADEOUTONSILHOUETTE || CUBEMAP float3 vWorldNormal = i.vWorldNormal; #endif #if FADEOUTONSILHOUETTE //float blend = -i.projNormal.z; float blend = saturate( dot( -i.vWorldViewVector.xyz, vWorldNormal.xyz ) ); blend = blend * blend * blend; #else float blend = 1.0f; #endif // Sample normal float4 normalTexel = tex2D( NormalSampler, i.vBumpTexCoord.xy ); float4 vNormal = float4( normalTexel.xyz * 2.0f - 1.0f, normalTexel.a ); #if SECONDARY_NORMAL float3 vNormal2 = tex2D( NormalSampler, i.vBumpTexCoord.wz ).xyz * 2.0f - 1.0f; vNormal.xyz = normalize( vNormal.xyz + vNormal2.xyz ); #endif #if REFRACTTINTTEXTURE float3 refractTintColor = 2.0 * g_RefractTint * tex2D( RefractTintSampler, i.vBumpTexCoord.xy ); #else float3 refractTintColor = g_RefractTint; #endif #if COLORMODULATE refractTintColor *= i.ColorModulate.rgb; #endif // Perform division by W only once float ooW = 1.0f / i.vRefractXYW.z; // Compute coordinates for sampling refraction float2 vRefractTexCoordNoWarp = i.vRefractXYW.xy * ooW; float2 vRefractTexCoord = vNormal.xy; float scale = vNormal.a * g_RefractScale; #if COLORMODULATE scale *= i.ColorModulate.a; #endif vRefractTexCoord *= scale; #if ( MAGNIFY ) { vRefractTexCoord += float2( 0.5, 0.5 ) + float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y ); vRefractTexCoord += ( vRefractTexCoordNoWarp - float2( 0.5, 0.5 ) - float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y ) ) * g_flInverseMagnifyScale; } #else { vRefractTexCoord += vRefractTexCoordNoWarp; } #endif #if ( MIRRORABOUTVIEWPORTEDGES ) { // // need to mirror the texcoords on every border so that one splitscreen viewport doesn't bleed into another one. // // mirror on the min viewport in both dimensions vRefractTexCoord.xy -= g_NormalizedViewportMinXYMaxWZ.xy; vRefractTexCoord.xy = abs( vRefractTexCoord.xy ); vRefractTexCoord.xy += g_NormalizedViewportMinXYMaxWZ.xy; // mirror on the max viewport in both dimensions vRefractTexCoord.xy = g_NormalizedViewportMinXYMaxWZ.wz - vRefractTexCoord.xy; vRefractTexCoord.xy = abs( vRefractTexCoord.xy ); vRefractTexCoord.xy = g_NormalizedViewportMinXYMaxWZ.wz - vRefractTexCoord.xy; } #endif #if (BLUR==1) // use polyphase magic to convert 9 lookups into 4 // basic principle behind this transformation: // [ A B C ] // [ D E F ] // [ G H I ] // use bilinear filtering hardware to weight upper 2x2 samples evenly (0.25* [A + B + D + E]). // scale the upper 2x2 by 4/9 (total area of kernel occupied) // use bilinear filtering hardware to weight right 1x2 samples evenly (0.5*[C + F]) // scale right 1x2 by 2/9 // use bilinear filtering hardware to weight lower 2x1 samples evenly (0.5*[G + H]) // scale bottom 2x1 by 2/9 // fetch last sample (I) and scale by 1/9. float2 upper_2x2_loc = vRefractTexCoord.xy - float2(g_HalfBlurFraction, g_HalfBlurFraction); float2 right_1x2_loc = vRefractTexCoord.xy + float2(g_BlurFraction, -g_HalfBlurFraction); float2 lower_2x1_loc = vRefractTexCoord.xy + float2(-g_HalfBlurFraction, g_BlurFraction); float2 singleton_loc = vRefractTexCoord.xy + float2(g_BlurFraction, g_BlurFraction); result = tex2D(RefractSampler, upper_2x2_loc) * 0.4444444; result += tex2D(RefractSampler, right_1x2_loc) * 0.2222222; result += tex2D(RefractSampler, lower_2x1_loc) * 0.2222222; result += tex2D(RefractSampler, singleton_loc) * 0.1111111; if ( IsX360() ) { result.rgb = X360GammaToLinear( result.rgb ); } float3 unblurredColor = tex2Dsrgb(RefractSampler, vRefractTexCoordNoWarp.xy); result = lerp(unblurredColor, result * refractTintColor, blend); #elif (BLUR>0) // iteratively step through render target int x, y; result = float3( 0.0f, 0.0f, 0.0f ); for( x = -g_BlurCount; x <= g_BlurCount; x++ ) { for( y = -g_BlurCount; y <= g_BlurCount; y++ ) { result += tex2D( RefractSampler, vRefractTexCoord.xy + float2( g_BlurFraction * x, g_BlurFraction * y ) ); } } if ( IsX360() ) { result.rgb = X360GammaToLinear( result.rgb ); } int width = g_BlurCount * 2 + 1; result *= 1.0f / ( width * width ); // result is the blurred one now. . .now lerp. float3 unblurredColor = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ); result = lerp( unblurredColor, result * refractTintColor, blend ); #else #if MASKED float4 fMaskedResult = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy ); return FinalOutput( fMaskedResult, pixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE ); #else float3 colorWarp = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy ); float3 colorNoWarp = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ); colorWarp *= refractTintColor; result = lerp( colorNoWarp, colorWarp, blend ); #endif #endif #if CUBEMAP float specularFactor = vNormal.a; float3 worldSpaceNormal = Vec3TangentToWorld( vNormal.xyz, vWorldNormal, i.vWorldTangent, i.vWorldBinormal ); float3 reflectVect = CalcReflectionVectorUnnormalized( worldSpaceNormal, i.vTangentVertToEyeVector ); float3 specularLighting = texCUBE( EnvmapSampler, reflectVect ); specularLighting *= specularFactor; specularLighting *= g_EnvmapTint; float3 specularLightingSquared = specularLighting * specularLighting; specularLighting = lerp( specularLighting, specularLightingSquared, g_EnvmapContrast ); float3 greyScale = dot( specularLighting, float3( 0.299f, 0.587f, 0.114f ) ); specularLighting = lerp( greyScale, specularLighting, g_EnvmapSaturation ); result += specularLighting; #endif #if COLORMODULATE float resultAlpha = i.ColorModulate.a * vNormal.a; #else float resultAlpha = vNormal.a; #endif return FinalOutput( float4( result, resultAlpha ), pixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE, (WRITE_DEPTH_TO_DESTALPHA != 0), i.worldPos_projPosZ.w ); }