Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

372 lines
12 KiB

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