|
|
//===================== 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" [CONSOLE] // STATIC: "MIRRORABOUTVIEWPORTEDGES" "0..0" [PC] // STATIC: "SHADER_SRGB_READ" "0..1" [ps20b] // STATIC: "LOCALREFRACT" "0..1"
#include "common_fog_ps_fxc.h" // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" [ps20b] [PC] // DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0" [ps20b] [CONSOLE] // DYNAMIC: "D_NVIDIA_STEREO" "0..1" [ps20b] [PC] // DYNAMIC: "D_NVIDIA_STEREO" "0..0" [ps20b] [CONSOLE]
// SKIP: $MASKED && $BLUR
#if defined( SHADER_MODEL_PS_2_0 ) #define WRITE_DEPTH_TO_DESTALPHA 0 #endif
#ifdef _X360 #ifdef SHADER_SRGB_READ #undef SHADER_SRGB_READ #endif #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 samplerCUBE EnvmapSampler : register( s4 ); #endif
#if REFRACTTINTTEXTURE sampler RefractTintSampler : register( s5 ); #endif
#if D_NVIDIA_STEREO sampler StereoParamSampler : register( s6 ); #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 float3 g_c7 : register( c7 ); #define g_vRefractTextureAspectFixup ( g_c7.xy ) #define g_flRefractDepth ( g_c7.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.5f * g_BlurFraction;
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 };
// NVIDIA's function to convert mono refract UV to the correct stereo UV for each eye float2 MonoTostereoClipPosXY( float3 vMonoClipPos ) // .z is actually .w { #if ( !D_NVIDIA_STEREO ) { return vMonoClipPos.xy; } #else { // 0th pixel = 1/16 == 1/16 + 1/8 * 0 float flEyeSep = tex2D( StereoParamSampler, float2( 0.0625f, 0 ) ).x; // 0.19 * 0.1316;
// 1st pixel = 3/16 == 1/16 + 1/8 * 1 float flConvergence = tex2D( StereoParamSampler, float2( 0.1875, 0 ) ).x; // 4; float3 vStereoClipPos = vMonoClipPos.xyz;
// Undo the stereo transform vStereoClipPos.x += flEyeSep * ( vMonoClipPos.z - flConvergence ); return vStereoClipPos.xy; } #endif }
float4_color_return_type main( PS_INPUT i ) : COLOR { // AlexV - Don't delete this line. I will remove it in a few days. //i.vBumpTexCoord.x = ( i.vBumpTexCoord.x - 98.0/255.0 ) / ( 158.0/255.0-98.0/255.0 );
float3 vResult;
float flPixelFogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.xyz, i.worldPos_projPosZ.xyz, i.worldPos_projPosZ.w );
float flBlend = 1.0f; #if ( FADEOUTONSILHOUETTE ) { //flBlend = -i.projNormal.z; flBlend = saturate( dot( -i.vWorldViewVector.xyz, i.vWorldNormal.xyz ) ); flBlend = flBlend * flBlend * flBlend; } #endif
// Sample normal float4 vNormalTexel = tex2D( NormalSampler, i.vBumpTexCoord.xy ); float4 vNormalTs = float4( vNormalTexel.xyz * 2.0f - 1.0f, vNormalTexel.a );
#if ( SECONDARY_NORMAL ) { float3 vNormal2Ts = tex2D( NormalSampler, i.vBumpTexCoord.wz ).xyz * 2.0f - 1.0f; vNormalTs.xyz = normalize( vNormalTs.xyz + vNormal2Ts.xyz ); } #endif
#if ( REFRACTTINTTEXTURE ) float3 vRefractTintColor = 2.0 * g_RefractTint * tex2D( RefractTintSampler, i.vBumpTexCoord.xy ).rgb; #else float3 vRefractTintColor = g_RefractTint; #endif
#if ( COLORMODULATE ) { vRefractTintColor.rgb *= i.ColorModulate.rgb; } #endif
// Compute coordinates for sampling refraction float2 vRefractTexCoordNoWarp = MonoTostereoClipPosXY( i.vRefractXYW.xyz ) / i.vRefractXYW.z; // Divide by w float2 vRefractTexCoord = vNormalTs.xy; // This normal should be in screen space! float flScale = vNormalTs.a * g_RefractScale; #if COLORMODULATE { flScale *= i.ColorModulate.a; } #endif vRefractTexCoord.xy *= flScale;
#if ( MAGNIFY ) { vRefractTexCoord.xy += float2( 0.5, 0.5 ) + float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y ); vRefractTexCoord.xy += ( vRefractTexCoordNoWarp.xy - float2( 0.5, 0.5 ) - float2( g_vMagnifyCenter.x, g_vMagnifyCenter.y ) ) * g_flInverseMagnifyScale; } #else { vRefractTexCoord.xy += vRefractTexCoordNoWarp.xy; } #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 == 0 ) { #if ( MASKED ) { float4 vMaskedResult = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy ); return FinalOutput( vMaskedResult, flPixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE ); } #else { float3 vColorWarp = tex2Dsrgb( RefractSampler, vRefractTexCoord.xy ).rgb; float3 vColorNoWarp = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ).rgb;
vColorWarp.rgb *= vRefractTintColor.rgb; vResult.rgb = lerp( vColorNoWarp.rgb, vColorWarp.rgb, flBlend ); } #endif } #elif ( 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 ); vResult.rgb = tex2D( RefractSampler, upper_2x2_loc ).rgb * 0.4444444; vResult.rgb += tex2D( RefractSampler, right_1x2_loc ).rgb * 0.2222222; vResult.rgb += tex2D( RefractSampler, lower_2x1_loc ).rgb * 0.2222222; vResult.rgb += tex2D( RefractSampler, singleton_loc ).rgb * 0.1111111;
#if ( SHADER_SRGB_READ ) { // Just do this once rather than after every blur step, which is wrong, but much more efficient if ( IsX360() ) { #if defined( CSTRIKE15 ) // [mariod] - RT's are all 2.2 gamma in CSTRIKE15 vResult.rgb = GammaToLinear( vResult.rgb ); #else vResult.rgb = X360GammaToLinear( vResult.rgb ); #endif } else { vResult.rgb = SrgbGammaToLinear( vResult.rgb ); } } #endif
float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ).rgb; vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb * vRefractTintColor.rgb, flBlend ); } #elif ( BLUR > 1 ) // iteratively step through render target { int x, y;
vResult.rgb = float3( 0.0f, 0.0f, 0.0f ); for ( x = -g_BlurCount; x <= g_BlurCount; x++ ) { for ( y = -g_BlurCount; y <= g_BlurCount; y++ ) { vResult.rgb += tex2D( RefractSampler, vRefractTexCoord.xy + float2( g_BlurFraction * x, g_BlurFraction * y ) ).rgb; } }
#if ( SHADER_SRGB_READ ) { // Just do this once rather than after every blur step, which is wrong, but much more efficient if ( IsX360() ) { #if defined( CSTRIKE15 ) // [mariod] - RT's are all 2.2 gamma in CSTRIKE15 vResult.rgb = GammaToLinear( vResult.rgb ); #else vResult.rgb = X360GammaToLinear( vResult.rgb ); #endif } else { vResult.rgb = SrgbGammaToLinear( vResult.rgb ); } } #endif
int nWidth = g_BlurCount * 2 + 1; vResult.rgb *= 1.0f / ( nWidth * nWidth );
// vResult is the blurred one now. . .now lerp. float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vRefractTexCoordNoWarp.xy ); vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb * vRefractTintColor.rgb, flBlend ); } #endif
#if ( LOCALREFRACT ) { float2 vTexCoord = i.vBumpTexCoord.xy;
// The interpolaged tangent space vert to eye vector isn't good enough, so compute a higher quality vector here float3 vVertexToEyeDirWs = g_EyePos_SpecExponent.xyz - i.worldPos_projPosZ.xyz; float3 vVertexToEyeDirTs = Vec3WorldToTangentNormalized( vVertexToEyeDirWs.xyz, i.vWorldNormal.xyz, i.vWorldTangent.xyz, i.vWorldBinormal.xyz );
//float3 vRefractTs = refract( -vVertexToEyeDirTs.xyz, vNormalTs.xyz, 0.66 ); float3 vRefractTs = vVertexToEyeDirTs.xyz; // Just use the vert to eye vector as the refract vector
float flRDotN = -vRefractTs.z; // This is R.GeometricNormal, so just use tangent z
float2 vRefractedUv = vRefractTs.xy / flRDotN; vRefractedUv.xy += vNormalTs.xy; vRefractedUv.xy += ( 1.0f - vNormalTs.z ) * vRefractTs.xy / flRDotN; vRefractedUv.xy *= g_vRefractTextureAspectFixup.xy * g_flRefractDepth;
// Original uv's vRefractedUv.xy += vTexCoord.xy;
float4 vRefract = tex2Dsrgb( RefractSampler, saturate( vRefractedUv.xy ) ); float4 vRefract2 = tex2Dsrgb( RefractSampler, saturate( vTexCoord.xy + vNormalTs.xy*0.1 ) ); vRefract.rgb = lerp( vRefract.rgb, vRefract2.aaa, 0.025 );
float flFresnel = pow( vNormalTs.z, 3.0f ); vResult.rgb = vRefract.rgb * flFresnel * vRefractTintColor.rgb;
float3 vUnblurredColor = tex2Dsrgb( RefractSampler, vTexCoord.xy ).rgb; vResult.rgb = lerp( vUnblurredColor.rgb, vResult.rgb, flBlend ); } #endif
#if ( CUBEMAP ) { float3 vNormalWs = Vec3TangentToWorld( vNormalTs.xyz, i.vWorldNormal.xyz, i.vWorldTangent.xyz, i.vWorldBinormal.xyz );
float3 vReflectRayWs = CalcReflectionVectorUnnormalized( vNormalWs.xyz, i.vTangentVertToEyeVector.xyz ); float3 vSpecularLighting = ENV_MAP_SCALE * texCUBE( EnvmapSampler, vReflectRayWs.xyz ).rgb;
// Spec mask float flSpecularMask = vNormalTs.a; vSpecularLighting.rgb *= flSpecularMask;
// Tint vSpecularLighting.rgb *= g_EnvmapTint.rgb;
// Contrast float3 vSpecularLightingSquared = vSpecularLighting.rgb * vSpecularLighting.rgb; vSpecularLighting.rgb = lerp( vSpecularLighting.rgb, vSpecularLightingSquared.rgb, g_EnvmapContrast );
// Saturation float3 vSpecularLuminance = dot( vSpecularLighting.rgb, float3( 0.299f, 0.587f, 0.114f ) ); vSpecularLighting.rgb = lerp( vSpecularLuminance.rgb, vSpecularLighting.rgb, g_EnvmapSaturation );
// Fresnel float flNdotV = saturate( dot( vNormalTs.xyz, i.vTangentVertToEyeVector.xyz ) ); float g_flReflectance = 0.6f; float flFresnel = g_flReflectance + ( ( 1.0f - g_flReflectance ) * pow( 1.0f - flNdotV, 1.0f ) );
vResult.rgb += vSpecularLighting.rgb * flFresnel; } #endif
#if ( COLORMODULATE ) float flResultAlpha = i.ColorModulate.a * vNormalTs.a; #else float flResultAlpha = vNormalTs.a; #endif
return FinalOutput( float4( vResult, flResultAlpha ), flPixelFogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE, ( WRITE_DEPTH_TO_DESTALPHA != 0 ), i.worldPos_projPosZ.w ); }
|