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