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.
 
 
 
 
 
 

740 lines
28 KiB

//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
// STATIC: "MASKS1" "0..1"
// STATIC: "MASKS2" "0..1"
// STATIC: "FRESNELRANGESTEXTURE" "0..1"
// STATIC: "PHONGWARPTEXTURE" "0..1" [ps30]
// STATIC: "ENVMAP" "0..1"
// STATIC: "AMBIENTREFLECTION" "0..1"
// STATIC: "USEBOUNCECOLOR" "0..1" [ps30]
// STATIC: "ANISOTROPY" "0..1" [ps30]
// STATIC: "BASEALPHAPHONGMASK" "0..1" [ps30]
// STATIC: "BASEALPHAENVMASK" "0..1"
// STATIC: "BUMPALPHAENVMASK" "0..1"
// STATIC: "SHADOWSATURATION" "0..1" [ps30]
// STATIC: "BASEALPHASELFILLUMMASK" "0..1"
// STATIC: "FAKERIM" "0..1"
// STATIC: "CASCADED_SHADOW_MAPPING" "0..1" [ps30]
// STATIC: "CSM_MODE" "0..3" [ps30]
// STATIC: "DOPREVIEW" "0..1"
// STATIC: "USEPATTERN" "0..4"
// STATIC: "FLASHLIGHT" "0..1"
// STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..3"
// DYNAMIC: "NUM_LIGHTS" "0..4" [ps30]
// DYNAMIC: "DYN_CSM_ENABLED" "0..1"
// DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..0"
// DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1"
#include "common_fog_ps_fxc.h"
// SKIP: ( $AMBIENTREFLECTION == 0 ) && ( $USEBOUNCECOLOR == 1 )
// SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $ENVMAP == 0 )
// SKIP: ( $BUMPALPHAENVMASK == 1 ) && ( $ENVMAP == 0 )
// SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $BUMPALPHAENVMASK == 1 )
// SKIP: ( $BASEALPHASELFILLUMMASK == 1) && ( $BASEALPHAENVMASK == 1 )
// SKIP: ( $BASEALPHASELFILLUMMASK == 1) && ( $BASEALPHAPHONGMASK == 1 )
// SKIP: ( $BASEALPHAENVMASK == 1 ) && ( $BASEALPHASELFILLUMMASK )
// SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $DYN_CSM_ENABLED == 1 )
// SKIP: ( $CASCADED_SHADOW_MAPPING == 0 ) && ( $CSM_MODE != 0 )
// SKIP: ( $DOPREVIEW == 0 ) && ( $USEPATTERN != 0 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $USEBOUNCECOLOR == 1 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $BASEALPHASELFILLUMMASK == 1)
// SKIP: ( $DOPREVIEW == 1 ) && ( $FAKERIM == 1 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $CSM_MODE > 0 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $DYN_CSM_ENALBED == 1 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $NUM_LIGHTS > 1 )
// SKIP: ( $DOPREVIEW == 1 ) && ( $FLASHLIGHT == 1 )
// SKIP: ( $CASCADED_SHADOW_MAPPING > 0) && ( $FLASHLIGHT == 1 )
// SKIP: ( $DYN_CSM_ENALBED == 1 ) && ( $FLASHLIGHT == 1 )
// SKIP: ( $CSM_MODE > 0 ) && ( $FLASHLIGHT == 1 )
// SKIP: ( $FLASHLIGHTDEPTHFILTERMODE > 0 ) && ( $FLASHLIGHT == 0 )
// SKIP: ( $FLASHLIGHT == 1 ) && ( $FAKERIM == 1 )
#define PHONG 1
#define RIMLIGHT 1
#define BUMPMAP 1
#define HALFLAMBERT 0
#include "common_ps_fxc.h"
#include "shader_constant_register_map.h"
#if ( DOPREVIEW == 1 )
#define GENERATEBASETEXTURE 1
#if ( BUMPMAP == 1 )
#define GENERATENORMAL 1
#endif
#if( MASKS1 == 1 )
#define GENERATEMASKS1 1
#endif
#define CHEAPFILTERING 1
#include "custom_character_fxc.h"
#endif
sampler BaseTextureSampler : register( s0 );
sampler NormalMapSampler : register( s1 );
#if ( DOPREVIEW == 1 )
sampler Masks1Sampler : register( s2 );
#else
sampler Masks1Sampler : register( s10 );
#endif
sampler Masks2Sampler : register( s3 );
sampler FresnelRangesSampler : register( s4 );
sampler NormalizeSampler : register( s5 );
sampler EnvmapSampler : register( s6 );
sampler PhongWarpSampler : register( s7 );
#if ( FLASHLIGHT == 1 )
#include "common_flashlight_fxc.h"
sampler FlashlightSampler : register( s8 );
sampler ShadowDepthSampler : register( s11 );
#else
sampler CSMDepthAtlasSampler : register( s8 );
#endif
//#undef CASCADED_SHADOW_MAPPING
//#define CASCADED_SHADOW_MAPPING 1
#if ( CASCADED_SHADOW_MAPPING == 1 )
#define CASCADE_SIZE 3
#define CSM_ENABLED 1
#include "csm_common_fxc.h"
#endif
const float4 g_vBounceTerms : register( c0 );
#define g_cBounce g_vBounceTerms.rgb
#define g_fAmbientBounceBoost g_vBounceTerms.w
const float4 g_vDiffuseModulation : register( c1 );
const float4 g_vDiffuseTerms : register( c101 );
#define g_fEnvmapLightScale g_vDiffuseTerms.x
#define g_fShadowSaturation g_vDiffuseTerms.y
#define g_fMetalness g_vDiffuseTerms.z
#define g_fRimLightAlbedo g_vDiffuseTerms.w
const float4 g_vShadowSaturationBounds : register( c2 );
const float3 g_vEyePos : register( c3 );
const float3 g_cAmbientCube[6] : register( PSREG_AMBIENT_CUBE ); // (c4-c9)
const float4 g_vPhongTerms : register( c10 );
#define g_fPhongBoost g_vPhongTerms.x
#define g_fPhongAlbedoBoost g_vPhongTerms.y
#define g_fPhongExponent g_vPhongTerms.z
#define g_fAnisotropyAmount g_vPhongTerms.w
const float4 g_vPhongTint_ShadowRimBoost : register( c11 );
#define g_cPhongTint g_vPhongTint_ShadowRimBoost.rgb
#define g_fShadowRimBoost g_vPhongTint_ShadowRimBoost.w
const float3 g_vFresnelRanges : register( c12 );
const float4 g_cShadowTint : register( c102 );
const float4 g_vEnvmapTerm : register( c103 );
#define g_vEnvmapLightScaleMin g_vEnvmapTerm.xxx
#define g_vEnvmapLightScaleMax g_vEnvmapTerm.yyy
#define g_fEnvmapContrast g_vEnvmapTerm.z
#define g_fEnvmapSaturation g_vEnvmapTerm.w
const float3 g_cEnvmapTint : register( c104 );
const float4 g_vRimTerms_SelfIllumTerms : register( c105 );
#define g_fRimLightExponent g_vRimTerms_SelfIllumTerms.x
#define g_fRimLightBoost g_vRimTerms_SelfIllumTerms.y
#define g_fSelfIllumBoost g_vRimTerms_SelfIllumTerms.z
#define g_fWarpIndex g_vRimTerms_SelfIllumTerms.w
const float4 g_cRimLightTint_fRimHaloBoost : register( c106 );
#define g_cRimLightTint g_cRimLightTint_fRimHaloBoost.xyz
#define g_fRimHaloBoost g_cRimLightTint_fRimHaloBoost.w
const float4 g_vFakeRimTint_ShadowScale : register( c107 );
#define g_cFakeRimTint g_vFakeRimTint_ShadowScale.rgb
#define g_fShadowScale g_vFakeRimTint_ShadowScale.w
const float4 g_FogParams : register( c19 );
PixelShaderLightInfo g_cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // (c20-c25)
const float4 g_vRimHaloBounds : register( c33 );
//const float4 cFlashlightColor : register( PSREG_FLASHLIGHT_COLOR ); // c28 - 31
const float4 g_FlashlightAttenuationFactors : register( PSREG_FLASHLIGHT_ATTENUATION );
const float4 g_FlashlightPos_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
#define g_FlashlightPos g_FlashlightPos_RimBoost.xyz
const float4x4 g_FlashlightWorldToTexture : register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE );
const float4 g_vShadowTweaks : register( c109 );
#define g_fRetroReflectivityBoost 5.0f
#define g_fRetroReflectivityPower 4.0f
struct PS_INPUT
{
float4 vTexCoord0 : TEXCOORD0;
float4 lightAtten : TEXCOORD1;
float4 tangentSpaceTranspose0_FakeRimx : TEXCOORD2; // when flashlight is on, the .w components
float4 tangentSpaceTranspose1_FakeRimy : TEXCOORD3; // hold the projection position
float4 tangentSpaceTranspose2_FakeRimz : TEXCOORD4; // instead of rim params
float4 vWorldPos_projZ : TEXCOORD5;
float4 cAmbient_fRimBoost : TEXCOORD6;
#if defined( SHADER_MODEL_PS_3_0 )
float4 vWorldTangentS_vBounceCenterx : TEXCOORD7;
float4 vWorldTangentT_vBounceCentery : TEXCOORD8;
float4 vBounceCenterDir_vBounceCenterz : TEXCOORD9;
#endif
};
float3 saturateColor( float3 c1, float fsat )
{
float3 finalColor = c1;
if ( fsat != 0 )
{
// perceptual luminance
float3 lum = float3( 0.299, 0.587, 0.114 );
float3 c2 = pow( c1, 4 );
float luminance1 = dot( c1, lum );
if ( fsat < 0 )
{
finalColor = lerp( c1, luminance1, -fsat );
}
else
{
float luminance2 = dot( c2, lum );
luminance2 = max( luminance2, 0.000001f );
c2 = c2 * luminance1 / luminance2;
finalColor = lerp( c1, c2, fsat );
}
}
return finalColor;
}
float3 tintColor( float3 c1, float3 tint, float amt )
{
// perceptual luminance
float3 lum = float3( 0.299, 0.587, 0.114 );
float3 c2 = tint;
float luminance1 = dot( c1, lum );
float luminance2 = dot( c2, lum );
luminance2 = max( luminance2, 0.000001f );
c2 = c2 * luminance1 / luminance2 ;
return lerp( c1, c2, amt );
}
void CharacterSpecularAndRimTerms( const float3 vWorldNormal, const float3 vLightDir, const float fSpecularExponent, const float3 vEyeDir,
const bool bDoSpecularWarp, in sampler specularWarpSampler,
const float3 color, const bool bDoRimLighting, const float fRimExponent, const float fWarpIndex,
const bool bDoAnisotropy, const float fAnisoAmount, const float VdotT, const float sVdotT, const float vTangent,
const bool bDoRetroReflectivity, const float fRetroReflectivityAmount, const float fRetroReflectivityFresnel,
// Outputs
out float3 specularLighting, out float3 rimLighting, out float rimHalo )
{
float3 vHalfAngle = normalize( vEyeDir.xyz + vLightDir.xyz );
float flNDotH = saturate( dot( vWorldNormal.xyz, vHalfAngle.xyz ) );
float flNDotL = saturate( dot( vWorldNormal, vLightDir ) );
specularLighting = float3( 0.0f, 0.0f, 0.0f );
if ( bDoAnisotropy )
{
float LdotT = dot( vLightDir, vTangent );
float sLdotT = sqrt( 1 - LdotT * LdotT );
float anisotropicSpecular = saturate( VdotT * LdotT + sVdotT * sLdotT );
/*if ( bDoSpecularWarp )
{
anisotropicSpecular = pow( anisotropicSpecular, 16.0f ); // need to raise it to a power to keep anisotropic feel, otherwise the falloff is too abrupt
}*/
flNDotH = lerp( flNDotH, anisotropicSpecular, fAnisoAmount );
}
// Optionally warp as function of scalar specular
if ( bDoSpecularWarp )
{
specularLighting = tex2D( specularWarpSampler, float2( flNDotH, fWarpIndex ) ).rgb;
}
else
{
specularLighting = pow( flNDotH, fSpecularExponent );
}
if ( bDoRetroReflectivity )
{
float flVDotL = saturate( dot( vEyeDir.xyz, vLightDir.xyz ) );
specularLighting = lerp( specularLighting, fRetroReflectivityFresnel * flVDotL * g_fRetroReflectivityBoost, fRetroReflectivityAmount );
}
specularLighting *= pow( flNDotL, 0.5 );
specularLighting *= color; // Modulate with light color
// Optionally do rim lighting
rimLighting = float3( 0.0, 0.0, 0.0 );
rimHalo = 0;
if ( bDoRimLighting )
{
float flNDotV = 1.0f - saturate( dot( vWorldNormal.xyz, vEyeDir.xyz ) );
rimHalo = flNDotH * flNDotL;
rimHalo *= pow( flNDotV, fRimExponent );
rimHalo *= pow( flNDotL, 0.5 );
rimLighting = rimHalo * color;
}
}
void CharacterDoSpecularLighting( const float3 worldPos, const float3 vWorldNormal, const float fSpecularExponent, const float3 vEyeDir,
const float4 lightAtten, const int nNumLights, PixelShaderLightInfo cLightInfo[3],
const bool bDoSpecularWarp, in sampler specularWarpSampler,
const bool bDoRimLighting, const float fRimExponent, const float flDirectShadow, const float fWarpIndex,
const bool bDoAnisotropy, const float fAnisoAmount, const float fAnisotropyAngle,
const float3 vTangent,
const bool bDoRetroReflectivity, const float fRetroReflectivityAmount, const float3 ambient,
// Outputs
out float3 specularLighting, out float3 rimLighting, out float rimHalo )
{
specularLighting = rimLighting = float3( 0.0f, 0.0f, 0.0f );
rimHalo = 0.0f;
float3 localSpecularTerm, localRimTerm = float3( 0.0f, 0.0f, 0.0f );
float localRimHalo = 0.0f;
float flVDotN = 0.0f;
if ( bDoRetroReflectivity )
{
flVDotN = saturate( dot( vWorldNormal.xyz, vEyeDir.xyz ) );
flVDotN = pow( flVDotN, g_fRetroReflectivityPower );
specularLighting += fRetroReflectivityAmount * flVDotN * ambient * g_fRetroReflectivityBoost;
}
float VdotT = 1;
float sVdotT = 1;
if ( bDoAnisotropy )
{
VdotT = dot( vEyeDir, vTangent );
sVdotT = sqrt( 1 - VdotT * VdotT );
}
if( nNumLights > 0 )
{
// First local light will always be forced to a directional light in CS:GO (see CanonicalizeMaterialLightingState() in shaderapidx8.cpp) - it may be completely black.
CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 0 ), fSpecularExponent, vEyeDir,
bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 0 ) * lightAtten[0],
bDoRimLighting, fRimExponent, fWarpIndex,
bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
localSpecularTerm, localRimTerm, localRimHalo );
specularLighting += localSpecularTerm * flDirectShadow; // Accumulate specular and rim terms
rimLighting += localRimTerm * flDirectShadow;
rimHalo += localRimHalo;
}
if( nNumLights > 1 )
{
CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 1 ), fSpecularExponent, vEyeDir,
bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 1 ) * lightAtten[1],
bDoRimLighting, fRimExponent, fWarpIndex,
bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
localSpecularTerm, localRimTerm, localRimHalo );
specularLighting += localSpecularTerm; // Accumulate specular and rim terms
rimLighting += localRimTerm;
rimHalo += localRimHalo;
}
if( nNumLights > 2 )
{
CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 2 ), fSpecularExponent, vEyeDir,
bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 2 ) * lightAtten[2],
bDoRimLighting, fRimExponent, fWarpIndex,
bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
localSpecularTerm, localRimTerm, localRimHalo );
specularLighting += localSpecularTerm; // Accumulate specular and rim terms
rimLighting += localRimTerm;
rimHalo += localRimHalo;
}
if( nNumLights > 3 )
{
CharacterSpecularAndRimTerms( vWorldNormal, PixelShaderGetLightVector( worldPos, cLightInfo, 3 ), fSpecularExponent, vEyeDir,
bDoSpecularWarp, specularWarpSampler, PixelShaderGetLightColor( cLightInfo, 3 ) * lightAtten[3],
bDoRimLighting, fRimExponent, fWarpIndex,
bDoAnisotropy, fAnisoAmount, VdotT, sVdotT, vTangent,
bDoRetroReflectivity, fRetroReflectivityAmount, flVDotN,
localSpecularTerm, localRimTerm, localRimHalo );
specularLighting += localSpecularTerm; // Accumulate specular and rim terms
rimLighting += localRimTerm;
rimHalo += localRimHalo;
}
}
float3 desaturateColor( float3 c1 )
{
// perceptual luminance
float3 lum = float3( 0.299, 0.587, 0.114 );
return dot( c1, lum );
}
// ======================= MAIN ======================= //
float4_color_return_type main( PS_INPUT i ) : COLOR
{
float4 vBaseTextureSample = tex2D( BaseTextureSampler, i.vTexCoord0.xy );
#if ( MASKS1 )
float4 vMasks1Params = tex2D( Masks1Sampler, i.vTexCoord0.xy );
#else
float4 vMasks1Params = float4( 1.0f, 0.0f, 1.0f, 0.0f );
#endif
#if ( BUMPMAP )
float4 vNormalSample = tex2D( NormalMapSampler, i.vTexCoord0.xy );
#else
float4 vNormalSample = float4( 0.0f, 0.0f, 1.0f, 1.0f );
#endif
#if ( DOPREVIEW )
customizeCharacter( i.vTexCoord0.xy, vBaseTextureSample, vNormalSample, vMasks1Params );
#endif
float fAlpha = vBaseTextureSample.a;
float3 cBase = vBaseTextureSample.rgb;
float fSpecMask = 1.0f;
float fEnvMask = 1.0f;
float fSelfIllumMask = 0.0f;
#if ( BASEALPHAPHONGMASK == 1 )
fSpecMask = vBaseTextureSample.a;
fAlpha = 1.0f;
#endif
#if ( BASEALPHAENVMASK == 1 )
fEnvMask = vBaseTextureSample.a;
fAlpha = 1.0f;
#endif
#if ( BASEALPHASELFILLUMMASK == 1 )
fSelfIllumMask = vBaseTextureSample.a;
#endif
float fRimMask = 1.0f;
float fMetalnessMask = 1.0f;
float fPhongAlbedoMask = 0.0f;
float fWarpIndex = g_fWarpIndex;
#if ( MASKS1 )
{
fRimMask = vMasks1Params.r;
fPhongAlbedoMask = vMasks1Params.g;
fMetalnessMask = vMasks1Params.b;
fWarpIndex = vMasks1Params.a;
}
#else
fMetalnessMask = g_fMetalness;
#endif
float3 vTangentNormal = float3( 0.0f, 0.0f, 1.0f );
#if ( BUMPMAP )
{
vTangentNormal = vNormalSample.xyz * 2.0f - 1.0f;
#if ( BASEALPHAPHONGMASK == 0 )
fSpecMask = vNormalSample.a;
#endif
#if ( BUMPALPHAENVMASK )
fEnvMask = vNormalSample.a;
#endif
}
#endif
float3x3 mTangentSpaceTranspose = float3x3( i.tangentSpaceTranspose0_FakeRimx.xyz, i.tangentSpaceTranspose1_FakeRimy.xyz, i.tangentSpaceTranspose2_FakeRimz.xyz );
float3 vWorldNormal = normalize( mul( mTangentSpaceTranspose, vTangentNormal ) );
float3 vEyeDir = normalize( g_vEyePos - i.vWorldPos_projZ.xyz );
#if ( FRESNELRANGESTEXTURE )
float fFresnel = saturate( dot( vEyeDir, vWorldNormal ) );
float3 vFresnelParams = tex2D( FresnelRangesSampler, float2( fFresnel, fWarpIndex ) );
fFresnel = vFresnelParams.y;
float fAmbientReflectionMask = vFresnelParams.z * fRimMask;
#else
float fFresnel = Fresnel( vWorldNormal, vEyeDir, g_vFresnelRanges );
float fAmbientReflectionMask = fFresnel * fRimMask;
#endif
float fCSMShadow = 1.0f;
#if ( CASCADED_SHADOW_MAPPING && DYN_CSM_ENABLED ) && defined( SHADER_MODEL_PS_3_0 )
fCSMShadow = CSMComputeShadowing( i.vWorldPos_projZ.xyz );
#endif
float3 linearLightColor = PixelShaderDoLighting( i.vWorldPos_projZ.xyz, vWorldNormal,
float3( 0.0f, 0.0f, 0.0f), false,
true, i.lightAtten, g_cAmbientCube,
NormalizeSampler, NUM_LIGHTS, g_cLightInfo, ( HALFLAMBERT == 1 ),
false, NULL, fCSMShadow );
float fShadowSaturationMask = 1.0f;
float fAnisotropyAmount = g_fAnisotropyAmount;
float fAnisotropyAngle = 1.57;
float fRetroReflectivityMask = 0.0f;
float fEnvmapLightScale = g_fEnvmapLightScale;
#if ( MASKS2 )
float4 vMasks2Params = tex2D( Masks2Sampler, i.vTexCoord0.xy );
fShadowSaturationMask *= vMasks2Params.x;
fAnisotropyAmount *= ( vMasks2Params.g > 0 );
fAnisotropyAngle = vMasks2Params.g * 3.14159;
fEnvmapLightScale *= vMasks2Params.b;
fRetroReflectivityMask = 1.0f - vMasks2Params.a;
#endif
float3 cSpecularLight = float3( 0.0f, 0.0f, 0.0f );
float3 cRimLight = float3( 0.0f, 0.0f, 0.0f );
float3 cAdditiveRimlight = float3( 0.0f, 0.0f, 0.0f );
float3 vTangent = float3( 0.0f, 0.0f, 0.0f );
float3 vReflectionEyeVec = vEyeDir;
float fRimHalo = 0;
#if ( FLASHLIGHT )
float4 flashlightSpacePosition = TransformFlashlightWorldToTexture( i.vWorldPos_projZ.xyz, g_FlashlightWorldToTexture );
float3 vProjPos = float3( i.tangentSpaceTranspose0_FakeRimx.w, i.tangentSpaceTranspose1_FakeRimy.w, i.tangentSpaceTranspose2_FakeRimz.w );
float3 vProjCoords = flashlightSpacePosition.xyz / flashlightSpacePosition.w;
float2 vScreenPos = vProjPos.xy / vProjPos.z;
bool bShadows = true;
linearLightColor += DoFlashlight( g_FlashlightPos, i.vWorldPos_projZ.xyz, flashlightSpacePosition, vWorldNormal,
g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w, FlashlightSampler, ShadowDepthSampler,
NormalizeSampler, FLASHLIGHTDEPTHFILTERMODE, bShadows,
vProjCoords.xy, false, g_vShadowTweaks, true );
#if ( PHONG )
float3 cSpecularFlashlight = float3( 0.0f, 0.0f, 0.0f );
float3 flashlightColor = tex2D( FlashlightSampler, vProjCoords.xy ).rgb;
flashlightColor *= flashlightSpacePosition.www > float3(0,0,0);
float3 vFlashlightDir = g_FlashlightPos - i.vWorldPos_projZ.xyz;
float distSquared = dot( vFlashlightDir, vFlashlightDir );
float dist = sqrt( distSquared );
float fAtten = saturate( dot( g_FlashlightAttenuationFactors.xyz, float3( 1.0f, 1.0f/dist, 1.0f/distSquared ) ) );
vFlashlightDir = normalize( vFlashlightDir );
float endFalloffFactor = RemapNormalizedValClamped( dist, g_FlashlightAttenuationFactors.w, 0.6f * g_FlashlightAttenuationFactors.w );
flashlightColor *= fAtten * endFalloffFactor * cFlashlightColor;
float VdotT = 0;
float sVdotT = 0;
float NdotL = dot( vFlashlightDir, vWorldNormal );
if ( bShadows )
{
float flShadow = DoFlashlightShadow( ShadowDepthSampler, NormalizeSampler, vProjCoords.xyz, vScreenPos, FLASHLIGHTDEPTHFILTERMODE, g_vShadowTweaks, NdotL );
float flAttenuated = lerp( flShadow, 1.0f, g_vShadowTweaks.y ); // Blend between fully attenuated and not attenuated
flShadow = saturate( lerp( flAttenuated, flShadow, fAtten ) ); // Blend between shadow and above, according to light attenuation
flashlightColor *= flShadow; // Shadow term
}
if ( ANISOTROPY == 1 )
{
VdotT = dot( vEyeDir, vTangent );
sVdotT = sqrt( 1 - VdotT * VdotT );
}
CharacterSpecularAndRimTerms( vWorldNormal, vFlashlightDir, g_fPhongExponent, vEyeDir,
( PHONGWARPTEXTURE == 1 ), PhongWarpSampler,
flashlightColor, false, g_fRimLightExponent, fWarpIndex,
( ANISOTROPY == 1 ), fAnisotropyAmount, VdotT, sVdotT, vTangent,
false, 0, 0, // TODO: enable retroreflectivity with flashlight
// Outputs
cSpecularFlashlight, cAdditiveRimlight, fRimHalo );
#endif
#endif
#if ( FAKERIM )
{
float3 localRimTerm, localSpecularTerm = float3( 0.0f, 0.0f, 0.0f );
float localRimHalo = 0;
float3 vFakeRimDir = float3( i.tangentSpaceTranspose0_FakeRimx.w, i.tangentSpaceTranspose1_FakeRimy.w, i.tangentSpaceTranspose2_FakeRimz.w );
float3 cFakeRimColor = i.cAmbient_fRimBoost.rgb * i.cAmbient_fRimBoost.a * g_cFakeRimTint;
CharacterSpecularAndRimTerms( vWorldNormal, vFakeRimDir, 1.0f, vEyeDir,
false, NULL, cFakeRimColor,
true, g_fRimLightExponent, 0.0f,
false, 0.0f, 0.0f, 0.0f, float3( 0.0f, 0.0f, 0.0f ),
false, 0.0f, 0.0f,
localSpecularTerm, localRimTerm, localRimHalo );
cAdditiveRimlight += localRimTerm * fRimMask;
// TODO: add rim saturation here?
}
#endif
#if ( ANISOTROPY )
float3 vnWorldTangentS = normalize( cross( vWorldNormal, i.vWorldTangentT_vBounceCentery.xyz ) );
float3 vnWorldTangentT = normalize( cross( vWorldNormal, vnWorldTangentS ) );
float cr, sr;
sincos( fAnisotropyAngle, cr, sr );
vTangent = normalize( cr * vnWorldTangentT + sr * vnWorldTangentS );
float3 rvec = cross( vTangent, vWorldNormal.xyz );
float3 uvec = cross( vEyeDir, rvec );
float3 evec = normalize( cross( rvec, vTangent ) );
vReflectionEyeVec = lerp( vEyeDir, evec, fAnisotropyAmount );
#endif
#if ( PHONG )
CharacterDoSpecularLighting( i.vWorldPos_projZ.xyz, vWorldNormal, g_fPhongExponent, vEyeDir,
i.lightAtten, NUM_LIGHTS, g_cLightInfo,
( PHONGWARPTEXTURE == 1 ), PhongWarpSampler,
( RIMLIGHT == 1 ), g_fRimLightExponent, fCSMShadow, fWarpIndex,
( ANISOTROPY == 1 ), fAnisotropyAmount, fAnisotropyAngle,
vTangent,
( ( MASKS2 == 1 ) && ( fRetroReflectivityMask > 0 ) ), fRetroReflectivityMask, i.cAmbient_fRimBoost.xyz,
// Outputs
cSpecularLight, cRimLight, fRimHalo );
#if ( FLASHLIGHT )
cSpecularLight += cSpecularFlashlight;
#endif
#if ( RIMLIGHT )
float fRimModulation = g_fRimLightBoost * fRimMask;
float fRimBoost = i.cAmbient_fRimBoost.w * g_fShadowRimBoost;
fRimBoost += 1.0f;
fRimModulation *= fRimBoost;
cRimLight *= fRimModulation;
#endif
float fPhongBoost = g_fPhongBoost;
cSpecularLight *= fSpecMask;
#if ( MASKS1 )
fPhongBoost = lerp( g_fPhongBoost, g_fPhongAlbedoBoost, fPhongAlbedoMask );
#endif
cSpecularLight *= fPhongBoost;
#endif
#if ( AMBIENTREFLECTION || ENVMAP )
float3 vReflection = CalcReflectionVectorUnnormalized( vWorldNormal, vReflectionEyeVec );
#endif
#if ( ENVMAP )
float3 cEnvmap = ENV_MAP_SCALE * texCUBE( EnvmapSampler, vReflection ).rgb;
cEnvmap = saturateColor( cEnvmap, g_fEnvmapSaturation );
float3 cEnvmapLight = saturate( ( ( linearLightColor + i.cAmbient_fRimBoost.xyz ) - g_vEnvmapLightScaleMin ) * g_vEnvmapLightScaleMax );
cEnvmap = lerp( cEnvmap, cEnvmap * cEnvmapLight, fEnvmapLightScale );
cEnvmap = lerp( cEnvmap, cEnvmap * cEnvmap, g_fEnvmapContrast );
cEnvmap *= fEnvMask * g_cEnvmapTint;
cSpecularLight += cEnvmap;
#endif
#if ( PHONG || ENVMAP )
#if ( MASKS2 )
fFresnel = lerp( fFresnel, 1.0f, fRetroReflectivityMask );
#endif
cSpecularLight *= fFresnel;
#endif
#if ( AMBIENTREFLECTION )
float3 cAmbientReflection = AmbientLight( vReflection, g_cAmbientCube );
float3 cAmbientLightColor = PixelShaderDoLighting( i.vWorldPos_projZ.xyz, float3( 0.0f, 0.0f, 1.0f ),
float3( 0.0f, 0.0f, 0.0f), false,
false, i.lightAtten, g_cAmbientCube,
NormalizeSampler, min( NUM_LIGHTS, 1 ), g_cLightInfo, false,
false, NULL, 1.0f );
cAmbientReflection *= cAmbientLightColor;
#if ( USEBOUNCECOLOR )
float3 vBounceCenter = float3( i.vWorldTangentS_vBounceCenterx.w, i.vWorldTangentT_vBounceCentery.w, i.vBounceCenterDir_vBounceCenterz.w );
float3 linearLightBounceModulate = PixelShaderDoLighting( vBounceCenter, -i.vBounceCenterDir_vBounceCenterz.xyz,
float3( 0.0f, 0.0f, 0.0f), false,
false, i.lightAtten, g_cAmbientCube,
NormalizeSampler, min( NUM_LIGHTS, 1 ), g_cLightInfo, false,
false, NULL, 1.0f );
float fBounceTerm = saturate( dot( vWorldNormal, i.vBounceCenterDir_vBounceCenterz.xyz ) );
float3 cBounce = g_cBounce * i.cAmbient_fRimBoost.xyz * linearLightBounceModulate;
cAmbientReflection = lerp( cAmbientReflection, cBounce, fBounceTerm );
#endif
cAmbientReflection *= g_fAmbientBounceBoost * fAmbientReflectionMask;
cSpecularLight += cAmbientReflection;
#endif
float fRimLightAlbedo = g_fRimLightAlbedo;
#if ( MASKS1 )
cSpecularLight *= lerp( float3( 1.0f, 1.0f, 1.0f ), cBase, fPhongAlbedoMask );
fRimLightAlbedo = g_fRimLightAlbedo * fPhongAlbedoMask;
#endif
cRimLight *= lerp( g_cRimLightTint, cBase * fRimLightAlbedo, saturate( fRimLightAlbedo ) );
float fShadowScale = saturate( g_fShadowScale + i.cAmbient_fRimBoost.w ); // If we darken shadows to increase contrast, don't do it in very dark areas
float lightIntensity = desaturateColor( linearLightColor + cRimLight );
float fShadeLevels = smoothstep( 0.3, 0.0, lightIntensity );
#if ( SHADOWSATURATION )
lightIntensity = desaturateColor( linearLightColor ).g;
// dark-to-mid blend
float fShadeLevelsDark = smoothstep( g_vShadowSaturationBounds.x, g_vShadowSaturationBounds.y, lightIntensity );
// mid-to-light blend
float fShadeLevelsLight = smoothstep( g_vShadowSaturationBounds.w, g_vShadowSaturationBounds.z, lightIntensity );
#if ( RIMLIGHT )
// don't just use linear lighting, make a nice saturated halo on the rimlight too
float rimHalo = smoothstep( g_vRimHaloBounds.x, g_vRimHaloBounds.y, fRimHalo );
rimHalo *= smoothstep( g_vRimHaloBounds.w, g_vRimHaloBounds.z, fRimHalo );
rimHalo *= desaturateColor( cRimLight ).g;
rimHalo *= g_fRimHaloBoost;
lightIntensity += rimHalo;
fShadeLevelsLight = fShadeLevelsLight + rimHalo;
#endif
cBase = lerp( cBase, saturateColor( cBase, g_fShadowSaturation ), fShadeLevelsDark * fShadeLevelsLight * fShadowSaturationMask );
cBase = lerp( cBase, tintColor( cBase, g_cShadowTint.rgb, g_cShadowTint.a ) * fShadowScale, fShadeLevels );
#else
cBase = lerp( cBase, tintColor( cBase, g_cShadowTint.rgb, g_cShadowTint.a ) * fShadowScale, fShadeLevels );
#endif
linearLightColor += i.cAmbient_fRimBoost.xyz;
cBase *= fMetalnessMask;
float3 finalColor = ( cBase * linearLightColor ) + cSpecularLight + cRimLight + cAdditiveRimlight;
#if ( BASEALPHASELFILLUMMASK )
finalColor = lerp( finalColor, vBaseTextureSample.rgb * ( 1.0f + g_fSelfIllumBoost ), fSelfIllumMask );
#endif
float flVertexFogFactor = 0.0f;
#if ( !HARDWAREFOGBLEND && !DOPIXELFOG )
flVertexFogFactor = i.worldPos_vertexFogFactor.w;
#endif
fAlpha *= g_vDiffuseModulation.a;
finalColor *= g_vDiffuseModulation.rgb;
float fogFactor = CalcPixelFogFactorSupportsVertexFog( PIXELFOGTYPE, g_FogParams, g_vEyePos.xyz, i.vWorldPos_projZ.xyz, i.vWorldPos_projZ.w, flVertexFogFactor );
#if ( WRITEWATERFOGTODESTALPHA && ( PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT ) )
fAlpha = fogFactor;
#endif
return FinalOutput( float4( finalColor, fAlpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, false, i.vWorldPos_projZ.w );
}