mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 20:16:10 +08:00
742 lines
28 KiB
Plaintext
742 lines
28 KiB
Plaintext
![]() |
//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
|
||
|
|
||
|
#include "common_fog_ps_fxc.h"
|
||
|
// STATIC: "ALPHABLEND" "0..1"
|
||
|
// STATIC: "TRANSMAT" "0..1"
|
||
|
// STATIC: "FRESNEL_WARP" "0..1"
|
||
|
// STATIC: "EFFECTS" "0..1"
|
||
|
// STATIC: "TINTING" "0..1"
|
||
|
// STATIC: "IRIDESCENCE" "0..1"
|
||
|
// STATIC: "BACK_SCATTER" "0..1"
|
||
|
// STATIC: "FORWARD_SCATTER" "0..1"
|
||
|
// STATIC: "HIGH_PRECISION_DEPTH" "0..1"
|
||
|
// STATIC: "INTERIOR_LAYER" "0..1"
|
||
|
// STATIC: "OPACITY_TEXTURE" "0..1"
|
||
|
// STATIC: "NORMAL2SOFT" "0..1"
|
||
|
// STATIC: "DETAIL" "0..1"
|
||
|
// STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps20b] [PC]
|
||
|
// STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps30] [PC]
|
||
|
// STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..0" [ps20b] [XBOX]
|
||
|
// DYNAMIC: "NUM_LIGHTS" "0..4" [ps20b]
|
||
|
// DYNAMIC: "NUM_LIGHTS" "0..4" [ps30]
|
||
|
// DYNAMIC: "FLASHLIGHT" "0..1"
|
||
|
// DYNAMIC: "FLASHLIGHTSHADOWS" "0..1"
|
||
|
|
||
|
#include "common_ps_fxc.h"
|
||
|
#include "common_vertexlitgeneric_dx9.h"
|
||
|
#include "common_flashlight_fxc.h"
|
||
|
#include "shader_constant_register_map.h"
|
||
|
|
||
|
// SAMPLERS
|
||
|
sampler g_tBase : register( s0 );
|
||
|
sampler g_tBump : register( s1 );
|
||
|
sampler g_tScreen : register( s2 );
|
||
|
sampler g_tTransMatMasks : register( s3 ); // Effect masks for material changes: fresnel hue-shift, jellyfish, forward scatter and back scatter
|
||
|
sampler g_tColorWarp : register( s4 ); // Color warp 3D texture
|
||
|
sampler g_tFresnelColorWarp : register( s5 ); // Fresnel color warp 3D texture
|
||
|
sampler g_tOpacity : register( s6 );
|
||
|
sampler g_tShadowDepth : register( s7 ); // Flashlight shadow depth map sampler
|
||
|
sampler g_tNormalizeRandRot : register( s8 ); // Normalization / RandomRotation samplers
|
||
|
sampler g_tFlashlightCookie : register( s9 ); // Flashlight cookie
|
||
|
sampler g_tEffectMasks : register( s10 ); // Special effect masks for self-illum, color warping, iridescence and clearcoat
|
||
|
sampler g_tIridescentWarp : register( s11 ); // 2D gradient for iridescent color
|
||
|
sampler g_tDetail : register( s12 ); // Detail texture
|
||
|
|
||
|
// SHADER CONSTANTS
|
||
|
|
||
|
#define flOverBright 2.0f //overbright lights consistent with vertexlitgeneric
|
||
|
|
||
|
const float4 g_vMisc : register( c0 );
|
||
|
#define g_flBumpStrength g_vMisc.x
|
||
|
#define g_flDepthScale g_vMisc.y
|
||
|
#define g_flInnerFogStrength g_vMisc.z
|
||
|
#define g_flRefractStrength g_vMisc.w
|
||
|
|
||
|
const float4 g_vTranslucentFresnelParams_InteriorBoost : register( c1 );
|
||
|
#define g_vTranslucentFresnelParams g_vTranslucentFresnelParams_InteriorBoost.xyz
|
||
|
#define g_flInteriorBoost g_vTranslucentFresnelParams_InteriorBoost.w
|
||
|
|
||
|
const float4 g_vMisc2 : register( c3 );
|
||
|
#define g_flRimLightExp g_vMisc2.x
|
||
|
#define g_flRimLightScale g_vMisc2.y
|
||
|
#define g_flSpecScale g_vMisc2.z
|
||
|
#define g_flSpecExp2 g_vMisc2.w
|
||
|
|
||
|
const float4 g_vMisc3 : register( c10 );
|
||
|
#define g_flSpecScale2 g_vMisc3.x
|
||
|
#define g_flFresnelBumpStrength g_vMisc3.y
|
||
|
#define g_flDiffuseSoftNormal g_vMisc3.z
|
||
|
#define g_flInteriorAmbientScale g_vMisc3.w
|
||
|
|
||
|
const float4 g_vEyePos : register( PSREG_EYEPOS_SPEC_EXPONENT );
|
||
|
#define g_vEyePos g_vEyePos.xyz
|
||
|
//#define UNUSED g_vEyePos.w
|
||
|
|
||
|
const float4 g_vPhongFresnel_ShaderControls : register( c12 );
|
||
|
#define g_vPhongFresnel g_vPhongFresnel_ShaderControls.xyz
|
||
|
#define g_fWriteDepthToAlpha g_vPhongFresnel_ShaderControls.w
|
||
|
|
||
|
const float4 g_vPhongTint_InteriorBackLightScale : register( c19 );
|
||
|
#define g_cPhongTint g_vPhongTint_InteriorBackLightScale.rgb
|
||
|
#define g_flInteriorBackLightScale g_vPhongTint_InteriorBackLightScale.w
|
||
|
|
||
|
// TODO: pass in FOV so that we can account for it properly
|
||
|
#define g_flHalfWindowWidth 1 /* tan(fov/2) */
|
||
|
|
||
|
const float4 g_vFresnelFx : register( c26 );
|
||
|
#define g_flIridBoost g_vFresnelFx.x
|
||
|
#define g_flIridExp g_vFresnelFx.y
|
||
|
#define g_flFresnelWarpScale g_vFresnelFx.z
|
||
|
#define g_flFresnelWarpExp g_vFresnelFx.w
|
||
|
|
||
|
const float4 g_vSelfIllumTint_DiffuseBias : register( c27 );
|
||
|
#define g_cSelfIllumTint g_vSelfIllumTint_DiffuseBias.rgb
|
||
|
#define g_flDiffuseBias g_vSelfIllumTint_DiffuseBias.w
|
||
|
|
||
|
const float4 g_vInteriorColor_RefractBlur : register( c32 );
|
||
|
#define g_cInteriorColor g_vInteriorColor_RefractBlur.rgb
|
||
|
#define g_flRefractBlur g_vInteriorColor_RefractBlur.w
|
||
|
|
||
|
const float3 cAmbientCube[6] : register( PSREG_AMBIENT_CUBE );
|
||
|
|
||
|
const PixelShaderLightInfo g_sLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 2 registers each - 6 registers total
|
||
|
|
||
|
const float4 g_vFlashlightAttenuationFactors_FarZ : register( PSREG_FLASHLIGHT_ATTENUATION );
|
||
|
#define g_vFlashlightAttenuationFactors g_vFlashlightAttenuationFactors_FarZ.xyz
|
||
|
#define g_flFlashlightFarZ g_vFlashlightAttenuationFactors_FarZ.w
|
||
|
|
||
|
const float4 g_vFlashlightPos : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
|
||
|
|
||
|
const float4x4 g_mFlashlightWorldToTexture : register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE );
|
||
|
|
||
|
const float4 g_vShadowTweaks : register( PSREG_ENVMAP_TINT__SHADOW_TWEAKS );
|
||
|
|
||
|
const float3x3 g_mView : register( c33 );
|
||
|
|
||
|
const float4 g_FogParams : register( c36 );
|
||
|
|
||
|
const float4 g_vPhongFresnel2_Phong2Softness : register( c42 );
|
||
|
#define g_vPhongFresnel2 g_vPhongFresnel2_Phong2Softness.xyz
|
||
|
#define g_vPhong2Softness g_vPhongFresnel2_Phong2Softness.w
|
||
|
|
||
|
const float4 g_vFleshLightingParams : register( c43 );
|
||
|
#define g_flDiffuseExponent g_vFleshLightingParams.x
|
||
|
#define g_flNormal2Softness g_vFleshLightingParams.y
|
||
|
#define g_flAmbientBoost g_vFleshLightingParams.z
|
||
|
#define g_flMaskMode g_vFleshLightingParams.w
|
||
|
|
||
|
const float4 g_vFleshSSParams : register( c44 );
|
||
|
#define g_flForwardScatter g_vFleshSSParams.x
|
||
|
#define g_flBackScatter g_vFleshSSParams.y
|
||
|
#define g_flSSDepth g_vFleshSSParams.z
|
||
|
#define g_flBentNormalScale g_vFleshSSParams.w
|
||
|
|
||
|
const float4 g_vFleshSSColor_TintByAlbedo : register( c45 );
|
||
|
#define g_cSSColor g_vFleshSSColor_TintByAlbedo.xyz
|
||
|
#define g_flSSTintByAlbedo g_vFleshSSColor_TintByAlbedo.w
|
||
|
|
||
|
const float4 g_vDetailBlendInfo_SpecExp : register( c46 );
|
||
|
#define g_flDetailMode g_vDetailBlendInfo_SpecExp.x
|
||
|
#define g_flDetailBlendAmt g_vDetailBlendInfo_SpecExp.y
|
||
|
//#define UNUSED g_vDetailBlendInfo_SpecExp.z
|
||
|
#define g_flSpecExp g_vDetailBlendInfo_SpecExp.w
|
||
|
|
||
|
// For now, use vertex UVs rather than position-derived UVs
|
||
|
#define USE_AUTHORED_UVS 1
|
||
|
|
||
|
// COMBO-DERIVED CONSTANTS
|
||
|
static const bool bAlphaBlend = ALPHABLEND ? true : false;
|
||
|
static const bool bFlashLight = FLASHLIGHT ? true : false;
|
||
|
static const bool bInterior = INTERIOR_LAYER ? true : false;
|
||
|
static const bool bOpacityTexture = OPACITY_TEXTURE ? true : false;
|
||
|
|
||
|
// INPUT STRUCT
|
||
|
struct PS_INPUT
|
||
|
{
|
||
|
float4 vWorldNormal : TEXCOORD0; // w is proj. z coord (for depth stuff)
|
||
|
float4 vVertexColor : TEXCOORD1;
|
||
|
float4 vWorldPos : TEXCOORD2; // w is proj. w coord
|
||
|
float4 vUV0 : TEXCOORD3;
|
||
|
float2 vUV1 : TEXCOORD4;
|
||
|
float4 vLightAtten : TEXCOORD5;
|
||
|
float3 vLightCube : TEXCOORD6;
|
||
|
float3 vWorldTangent : TEXCOORD7;
|
||
|
float3 vWorldBinormal : TEXCOORD8;
|
||
|
};
|
||
|
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float Luminance( const float3 colour )
|
||
|
{
|
||
|
return dot( colour, float3( 0.3, 0.59, 0.11 ) );
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float3 BumpedToWorldNormal( float3 vBumpedNormal, float3 vWorldNormal, float3 vWorldTangent, float3 vWorldBinormal )
|
||
|
{
|
||
|
float3x3 mTanToWorld;
|
||
|
mTanToWorld[2] = vWorldNormal;
|
||
|
mTanToWorld[0] = vWorldTangent;
|
||
|
mTanToWorld[1] = vWorldBinormal;
|
||
|
return normalize( mul( vBumpedNormal, mTanToWorld ) );
|
||
|
}
|
||
|
|
||
|
void ApplyDetail( float4 cDetail, float flMode, float flAmt, inout float3 cBase, inout float flSelfIllum, inout float3 flSelfIllumColor )
|
||
|
{
|
||
|
if ( flMode == 1 )
|
||
|
{
|
||
|
cBase.rgb *= lerp( 1.0f, cDetail.rgb * 2.0f, flAmt );
|
||
|
cBase.rgb = saturate( cBase.rgb );
|
||
|
return;
|
||
|
}
|
||
|
if ( flMode == 2 )
|
||
|
{
|
||
|
cBase.rgb += lerp( 0.0f, cDetail.rgb * flAmt, saturate( flAmt ) );
|
||
|
cBase.rgb = saturate( cBase.rgb );
|
||
|
return;
|
||
|
}
|
||
|
if ( flMode == 3 )
|
||
|
{
|
||
|
cBase.rgb = lerp( cBase.rgb, cDetail.rgb, saturate( flAmt * cDetail.a ) );
|
||
|
return;
|
||
|
}
|
||
|
if( flMode == 4 )
|
||
|
{
|
||
|
cBase.rgb = lerp( cBase.rgb, cDetail.rgb, saturate( flAmt ) );
|
||
|
return;
|
||
|
}
|
||
|
if( flMode == 5 )
|
||
|
{
|
||
|
cBase.rgb += lerp( 0.0f, cDetail.rgb * ( 1.0 + flAmt ), saturate( flAmt ) );
|
||
|
float flAddSelfIllum = saturate( Luminance( cBase.rgb ) - 1.0f );
|
||
|
flSelfIllum += flAddSelfIllum;
|
||
|
flSelfIllumColor.rgb = lerp( flSelfIllumColor.rgb, cBase.rgb, flAddSelfIllum );
|
||
|
cBase.rgb = saturate( cBase.rgb );
|
||
|
return;
|
||
|
}
|
||
|
if( flMode == 6 )
|
||
|
{
|
||
|
cBase.rgb *= ( 1.0f, cDetail.rgb, flAmt );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
void ComputeOpacityAndFresnel( float2 vUV0, float3 vEyeDir, float3 vWorldNormal,
|
||
|
// Function outputs:
|
||
|
out float flSkinOpacity, inout float flFresnel )
|
||
|
{
|
||
|
flSkinOpacity = 1;
|
||
|
if ( ( bOpacityTexture ) && ( bInterior || bAlphaBlend ) )
|
||
|
{
|
||
|
flSkinOpacity = tex2D( g_tOpacity, vUV0.xy );
|
||
|
}
|
||
|
|
||
|
float fTranslucentFresnel;
|
||
|
fTranslucentFresnel = lerp( g_vTranslucentFresnelParams.x, g_vTranslucentFresnelParams.y, pow( flFresnel, g_vTranslucentFresnelParams.z ) );
|
||
|
|
||
|
#if ( INTERIOR_LAYER )
|
||
|
{
|
||
|
flSkinOpacity = flSkinOpacity*fTranslucentFresnel;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float3 BlobAmbientLight( float3 vVertexAmbient, float3 vEyeDir, float3 vWorldNormal, float flFresnel )
|
||
|
{
|
||
|
// Ambient lighting now comes from VS
|
||
|
float3 cAmbient = vVertexAmbient;
|
||
|
|
||
|
// TODO: Replace lambert diffuse with pixelshader-ambient term of full lighting env.
|
||
|
//float3 cAmbient = PixelShaderAmbientLight( vBumpedWorldNormal, cAmbientCube );
|
||
|
|
||
|
//float3 cAmbientSheen = PixelShaderAmbientLight( reflect( -vEyeDir, vBumpedWorldNormal ), cAmbientCube );
|
||
|
//cAmbient = lerp( cAmbient, cAmbientSheen, flFresnel );
|
||
|
|
||
|
return cAmbient;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float BlobPhongFresnel( float flFresnel, float3 vPhongFresnelParams )
|
||
|
{
|
||
|
float flFresnelTerm = lerp( vPhongFresnelParams.y, vPhongFresnelParams.x, saturate( flFresnel ) );
|
||
|
flFresnelTerm = lerp( flFresnelTerm, vPhongFresnelParams.z, saturate( -flFresnel ) );
|
||
|
return flFresnelTerm;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
void BlobLight( float3 vWorldPos, float3 vEyeDir, float3 vBumpedWorldNormal, float3 vBumpedWorldNormal2,
|
||
|
float flCurvature, float flForwardSSMask, float flBackSSMask, float3 cLightColor, float3 cLightColorScattered,
|
||
|
float3 vLightDirection, float flIridMask,
|
||
|
// Outputs:
|
||
|
inout float3 cDiffuse, inout float3 cSpec, inout float3 cSpec2, inout float3 cShadowTerminator, inout float3 cRim, inout float3 cIrid )
|
||
|
{
|
||
|
float NdotL = dot( vBumpedWorldNormal, vLightDirection );
|
||
|
float NdotLSoft = NdotL;
|
||
|
float flInvNdotLSoft = 0.0f;
|
||
|
float HNdotL = NdotL * 0.5f + 0.5f;
|
||
|
float HNdotLSoft = NdotL;
|
||
|
#if( NORMAL2SOFT )
|
||
|
{
|
||
|
NdotLSoft = dot( vBumpedWorldNormal2, vLightDirection );
|
||
|
}
|
||
|
#endif
|
||
|
#if FORWARD_SCATTER || BACK_SCATTER
|
||
|
{
|
||
|
flInvNdotLSoft = saturate( 1.0f - NdotLSoft );
|
||
|
}
|
||
|
#endif
|
||
|
NdotL = saturate( NdotL );
|
||
|
|
||
|
float SSNdotL = 0.0f;
|
||
|
float flInvSSCurvature = 1.0f;
|
||
|
#if FORWARD_SCATTER || BACK_SCATTER
|
||
|
{
|
||
|
flInvSSCurvature = 1.0f / ( flCurvature * g_flSSDepth );
|
||
|
float flLocalizedBentNormalScale = g_flBentNormalScale * ( flCurvature ); // less view-dependance on highly curved areas
|
||
|
float3 vSSNormal = lerp( vBumpedWorldNormal2.rgb, vEyeDir.rgb, flLocalizedBentNormalScale ); // partially view-dependent normal for ss lighting calc
|
||
|
vSSNormal = normalize( vSSNormal );
|
||
|
SSNdotL = 1.0f - abs( dot( vSSNormal, vLightDirection ) );
|
||
|
SSNdotL = pow( SSNdotL, flInvSSCurvature );
|
||
|
float cSSMask = 1.0f;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if( NORMAL2SOFT )
|
||
|
{
|
||
|
HNdotLSoft = NdotLSoft * 0.5f + 0.5f;
|
||
|
NdotLSoft = saturate( NdotLSoft );
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
NdotLSoft = NdotL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
float3 vHalf = normalize( vEyeDir.xyz + vLightDirection.xyz );
|
||
|
float NdotH = saturate( dot( vHalf.xyz, vBumpedWorldNormal.xyz ) );
|
||
|
float NdotHSoft = NdotH;
|
||
|
|
||
|
float VdotN = dot( vEyeDir, vBumpedWorldNormal );
|
||
|
VdotN = saturate( VdotN );
|
||
|
|
||
|
float flSSMask = 0.0f;
|
||
|
#if( FORWARD_SCATTER )
|
||
|
{
|
||
|
flSSMask += flInvNdotLSoft * SSNdotL * flForwardSSMask * cLightColorScattered.rgb; // back half of terminator
|
||
|
}
|
||
|
#endif
|
||
|
#if( BACK_SCATTER )
|
||
|
{
|
||
|
flSSMask += SSNdotL * NdotLSoft * flBackSSMask * cLightColor.rgb;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if FORWARD_SCATTER || BACK_SCATTER
|
||
|
{
|
||
|
cShadowTerminator.rgb += flSSMask;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if( NORMAL2SOFT )
|
||
|
{
|
||
|
float3 vHalfSoft = normalize( vEyeDir.xyz + vLightDirection.xyz );
|
||
|
NdotHSoft = saturate( dot( vHalfSoft.xyz, vBumpedWorldNormal2.xyz ) );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//dual spec
|
||
|
float flFresnel = saturate( VdotN ) * 2.0f - 1.0f;
|
||
|
cSpec += pow( NdotH, g_flSpecExp ) * NdotL * cLightColor * BlobPhongFresnel( flFresnel, g_vPhongFresnel );
|
||
|
float flSpec2Soft = lerp( NdotH, NdotHSoft, g_vPhong2Softness );
|
||
|
float flSpec2Limit = lerp( NdotL, NdotLSoft, g_vPhong2Softness );
|
||
|
cSpec2 += pow( flSpec2Soft, g_flSpecExp2 ) * flSpec2Limit * cLightColor * BlobPhongFresnel( flFresnel, g_vPhongFresnel2 );
|
||
|
|
||
|
#if( IRIDESCENCE )
|
||
|
{
|
||
|
float flIridCoord = dot( vHalf, vLightDirection ) * flIridMask;
|
||
|
cIrid = tex2Dlod( g_tIridescentWarp, float4( flIridCoord, 0.5f, 0.0f, 0.0f ) ).rgb;
|
||
|
cIrid *= smoothstep( 0.1, 0.2, flIridMask ); // one channel describes thin film variation and masking, with values below 0.1 meaning "off"
|
||
|
cIrid *= pow( VdotN, g_flIridExp ) * g_flIridBoost;
|
||
|
cIrid *= cLightColor;
|
||
|
cIrid *= HNdotL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//diffuse
|
||
|
//float flDiffuseLevel = lerp( NdotL, NdotLSoft, g_flDiffuseSoftNormal );
|
||
|
float flDiffuseLevel = lerp( HNdotL, HNdotLSoft, g_flDiffuseSoftNormal );
|
||
|
flDiffuseLevel -= g_flDiffuseBias;
|
||
|
flDiffuseLevel = saturate( flDiffuseLevel );
|
||
|
flDiffuseLevel = pow( flDiffuseLevel, g_flDiffuseExponent );
|
||
|
cDiffuse.rgb += flDiffuseLevel * cLightColor.rgb;
|
||
|
|
||
|
//rim
|
||
|
float flRim = saturate( 1.0f - VdotN );
|
||
|
flRim = pow( flRim, g_flRimLightExp );
|
||
|
flRim *= NdotL;
|
||
|
cRim += flRim * cLightColor.rgb;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float4 BlobBlurFlashlight( sampler tFlashlightCookie, float2 flProjUv )
|
||
|
{
|
||
|
// TODO: get framebuffer res from constants
|
||
|
float2 vScreenRes = float2( 1600, 1200 );
|
||
|
float2 g_vInvScreenRes = 1.0 / vScreenRes;
|
||
|
|
||
|
static const float2 vPoissonOffset[8] = { float2( 0.3475f, 0.0042f ), float2( 0.8806f, 0.3430f ),
|
||
|
float2( -0.0041f, -0.6197f ), float2( 0.0472f, 0.4964f ),
|
||
|
float2( -0.3730f, 0.0874f ), float2( -0.9217f, -0.3177f ),
|
||
|
float2( -0.6289f, 0.7388f ), float2( 0.5744f, -0.7741f ) };
|
||
|
|
||
|
float4 cOut = 0;
|
||
|
float blurFactor = g_flSSDepth * 50;
|
||
|
for( int i = 0; i < 8; i++ )
|
||
|
{
|
||
|
cOut += 1.0/8.0 * tex2D( tFlashlightCookie, flProjUv + blurFactor * g_vInvScreenRes.xy * vPoissonOffset[i] );
|
||
|
}
|
||
|
return cOut;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float4 SampleBackgroundBlurred( float2 vBumpedTSNormal, float3 vWorldNormal, float2 vScreenPos, float flBlurDepth )
|
||
|
{
|
||
|
static const float2 vPoissonOffset[8] = { float2( 0.3475f, 0.0042f ), float2( 0.8806f, 0.3430f ),
|
||
|
float2( -0.0041f, -0.6197f ), float2( 0.0472f, 0.4964f ),
|
||
|
float2( -0.3730f, 0.0874f ), float2( -0.9217f, -0.3177f ),
|
||
|
float2( -0.6289f, 0.7388f ), float2( 0.5744f, -0.7741f ) };
|
||
|
// TODO: get framebuffer res from constants
|
||
|
float2 vScreenRes = float2( 1600, 1200 );
|
||
|
float2 g_vInvScreenRes = 1.0 / vScreenRes;
|
||
|
|
||
|
// Project world-space blur radius into screen space.
|
||
|
float flBlurRadius = g_flRefractBlur * flBlurDepth * ( vScreenRes.x / g_flHalfWindowWidth );
|
||
|
|
||
|
// Bumped refract
|
||
|
float flRefractStrength = g_flRefractStrength * flBlurDepth / g_flHalfWindowWidth;
|
||
|
float2 vBackgroundUV = flRefractStrength * vBumpedTSNormal + vScreenPos.xy;
|
||
|
|
||
|
float4 cOut = 0;
|
||
|
for( int i = 0; i < 8; i++ )
|
||
|
{
|
||
|
cOut += 1.0/8.0 * tex2D( g_tScreen, vBackgroundUV + flBlurRadius * g_vInvScreenRes.xy * vPoissonOffset[i] );
|
||
|
}
|
||
|
return cOut;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float3 CubeAverage( void )
|
||
|
{
|
||
|
// TODO: Pass this average light color in as a const
|
||
|
float3 cAvgLight = 0.0;
|
||
|
for( int j = 0; j < 6; j++ )
|
||
|
{
|
||
|
cAvgLight += cAmbientCube[j] / 6.0;
|
||
|
}
|
||
|
return cAvgLight;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float3 BlobInterior( float3 vWorldNormal, float2 vBumpedTSNormal, float3 vEyeDir,
|
||
|
float2 vScreenPos, float flPixelDepth, float flCamDist )
|
||
|
{
|
||
|
float3 cInterior = float3( 0.0f, 0.0f, 0.0f );
|
||
|
|
||
|
// Sample the background (and inner blob brain/tentacles)
|
||
|
// Boost bright background pixels
|
||
|
float4 cBackground = tex2D( g_tScreen, vScreenPos.xy );
|
||
|
float flLuminance = Luminance( cBackground.rgb );
|
||
|
cBackground.rgb *= 1.0 + g_flInteriorBoost * flLuminance * flLuminance;
|
||
|
|
||
|
// Fake refract-like vector without any total internal reflection crappiness
|
||
|
float3 vRefract = normalize( -( vEyeDir + vWorldNormal ) );
|
||
|
|
||
|
// Interior lighting through ambient cube
|
||
|
float3 cAvgLight = CubeAverage();
|
||
|
float3 cBackLight = g_flInteriorAmbientScale * cAvgLight.rgb;
|
||
|
cBackLight *= g_cInteriorColor.rgb;
|
||
|
|
||
|
//float flFogAtten = BlobInteriorFog( cBackground.a, flPixelDepth );
|
||
|
|
||
|
float flFogAtten = 1.0f - saturate( flLuminance );
|
||
|
float VdotN = dot( vEyeDir, vWorldNormal );
|
||
|
flFogAtten *= VdotN;
|
||
|
cBackground = SampleBackgroundBlurred( vBumpedTSNormal, vWorldNormal, vScreenPos, flFogAtten );
|
||
|
flLuminance = Luminance( cBackground );
|
||
|
|
||
|
flFogAtten = 1.0f - saturate( flLuminance );
|
||
|
flFogAtten *= ( VdotN + g_flInnerFogStrength );
|
||
|
flFogAtten = saturate( flFogAtten );
|
||
|
|
||
|
cInterior = lerp( cBackground, cBackLight, flFogAtten );
|
||
|
|
||
|
return cInterior;
|
||
|
}
|
||
|
|
||
|
//==============================================================================================================================================================
|
||
|
float4 main( PS_INPUT i ) : COLOR
|
||
|
{
|
||
|
float4 cOut = { 0, 0, 0, 1 };
|
||
|
|
||
|
// Set up misc camera variables
|
||
|
float flPixelDepth = i.vWorldNormal.w;
|
||
|
float2 vScreenPos = i.vUV0.wz / i.vWorldPos.w;
|
||
|
float3 vEyeDir = g_vEyePos.xyz - i.vWorldPos.xyz;
|
||
|
float flCamDist = length( vEyeDir );
|
||
|
vEyeDir /= flCamDist;
|
||
|
float3 vWorldNormal = normalize( i.vWorldNormal.xyz );
|
||
|
float3 vWorldTangent = normalize( i.vWorldTangent.xyz );
|
||
|
float3 vWorldBinormal = normalize( i.vWorldBinormal.xyz );
|
||
|
|
||
|
// Base (albedo) map
|
||
|
float4 vBase = tex2D( g_tBase, i.vUV0.xy );
|
||
|
float3 cBase = vBase.rgb;
|
||
|
float flSpecMask = vBase.a;
|
||
|
|
||
|
// Normal mapping
|
||
|
float4 vNormal = tex2D( g_tBump, i.vUV0.xy );
|
||
|
float3 vBumpedTangentNormal = normalize( ( vNormal.xyz * 2.0f - 1.0f ) * float3( g_flBumpStrength, g_flBumpStrength, 1.0f ) );
|
||
|
float3 vBumpedWorldNormal = BumpedToWorldNormal( vBumpedTangentNormal, vWorldNormal, vWorldTangent, vWorldBinormal );
|
||
|
float flCurvature = 1.0f - vNormal.a + 0.01; // invert mask (makes more sense visually when white is high curvature) and
|
||
|
// make sure it is never zero (else divide by zero errors later)
|
||
|
|
||
|
// Initialize masks for fx
|
||
|
float flSelfIllum = 0;
|
||
|
float3 cSelfIllum = g_cSelfIllumTint;
|
||
|
float flTinting = 1;
|
||
|
float flIridMask = vBase.a;
|
||
|
float flSpec2Mask = 1;
|
||
|
float4 vEffectMasks = tex2D( g_tEffectMasks, i.vUV0.xy );
|
||
|
#if( EFFECTS )
|
||
|
{
|
||
|
flSelfIllum = vEffectMasks.r;
|
||
|
flTinting = vEffectMasks.g;
|
||
|
flIridMask = vEffectMasks.b;
|
||
|
flSpec2Mask = vEffectMasks.a;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Initialize masks and color for subsurface effects
|
||
|
float flFresnelWarpMask = 1.0f;
|
||
|
float flSkinOpacityMask = 1.0f;
|
||
|
float flForwardSSMask = g_flForwardScatter;
|
||
|
float flBackSSMask = g_flBackScatter;
|
||
|
float flInteriorFogMask = 0.0f;
|
||
|
float3 cSSColor = lerp( 1.0f, cBase.rgb, g_flSSTintByAlbedo ) * g_cSSColor.rgb;
|
||
|
#if ( TRANSMAT )
|
||
|
{
|
||
|
float4 vTransmatMasks = tex2D( g_tTransMatMasks, i.vUV0.xy );
|
||
|
flForwardSSMask = vTransmatMasks.r * g_flForwardScatter;
|
||
|
flInteriorFogMask = vTransmatMasks.r;
|
||
|
flSkinOpacityMask = vTransmatMasks.g;
|
||
|
flFresnelWarpMask = vTransmatMasks.b;
|
||
|
flBackSSMask = vTransmatMasks.a * g_flBackScatter;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Apply detail texture
|
||
|
#if( DETAIL )
|
||
|
{
|
||
|
float4 cDetail = tex2D( g_tDetail, i.vUV1.xy );
|
||
|
ApplyDetail( cDetail, g_flDetailMode, g_flDetailBlendAmt, cBase, flSelfIllum, cSelfIllum );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Ambient boost factor
|
||
|
float flAmbientBoost = g_flAmbientBoost;
|
||
|
if ( g_flMaskMode == 1 )
|
||
|
{
|
||
|
flAmbientBoost *= flTinting;
|
||
|
}
|
||
|
if ( g_flMaskMode == 2 )
|
||
|
{
|
||
|
flAmbientBoost *= flSkinOpacityMask;
|
||
|
}
|
||
|
if ( g_flMaskMode == 3 )
|
||
|
{
|
||
|
flAmbientBoost *= flIridMask;
|
||
|
}
|
||
|
if ( g_flMaskMode == 4 )
|
||
|
{
|
||
|
flAmbientBoost *= flSpec2Mask;
|
||
|
}
|
||
|
if ( g_flMaskMode == 5 )
|
||
|
{
|
||
|
flAmbientBoost *= flFresnelWarpMask;
|
||
|
}
|
||
|
flAmbientBoost += 1.0f; // boost, not scale!
|
||
|
|
||
|
// Soft normals
|
||
|
float3 vBumpedTangentNormal2 = vBumpedTangentNormal;
|
||
|
float3 vBumpedWorldNormal2 = vBumpedWorldNormal;
|
||
|
#if( NORMAL2SOFT )
|
||
|
{
|
||
|
float4 vNormal2 = tex2Dbias( g_tBump, float4( i.vUV0.xy, 0, g_flNormal2Softness ) );
|
||
|
vBumpedTangentNormal2 = normalize( ( vNormal2.xyz * 2.0f - 1.0f ) * float3( g_flBumpStrength, g_flBumpStrength, 1.0f ) );
|
||
|
vBumpedWorldNormal2 = BumpedToWorldNormal( vBumpedTangentNormal2, vWorldNormal, vWorldTangent, vWorldBinormal );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
float flSkinOpacity = 1.0f;
|
||
|
// Opacity and fresnel
|
||
|
float flFresnel = saturate( 1.0 - dot( vEyeDir.xyz, vWorldNormal.xyz ) );
|
||
|
float flEdgeFresnel = flFresnel;
|
||
|
ComputeOpacityAndFresnel( i.vUV0.xy, vEyeDir, vBumpedWorldNormal,
|
||
|
flSkinOpacity, flFresnel );
|
||
|
flSkinOpacity *= ( 1.0f - flSkinOpacityMask );
|
||
|
|
||
|
// Initialize lighting params
|
||
|
float3 cInterior = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cAmbient = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cDiffuse = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cSpec = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cSpec2 = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cShadowTerminator = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cRim = float3( 0.0f, 0.0f, 0.0f );
|
||
|
float3 cIrid = float3( 0.0f, 0.0f, 0.0f );
|
||
|
|
||
|
if ( FLASHLIGHT )
|
||
|
{
|
||
|
float4 vFlashlightSpacePosition = mul( float4( i.vWorldPos.xyz, 1.0f ), g_mFlashlightWorldToTexture ); // TODO: Move to vertex shader
|
||
|
float3 vProjCoords = vFlashlightSpacePosition.xyz / vFlashlightSpacePosition.w;
|
||
|
|
||
|
float3 cFlashlightColor = tex2D( g_tFlashlightCookie, vProjCoords.xyz ) * flOverBright;
|
||
|
float3 cFlashlightColorBlurred = float3( 1.0f, 1.0f, 1.0f ) * flOverBright;
|
||
|
|
||
|
float3 delta = g_vFlashlightPos.xyz - i.vWorldPos.xyz;
|
||
|
float3 vLightDirection = normalize( delta );
|
||
|
float flDistSquared = dot( delta, delta );
|
||
|
float flDist = sqrt( flDistSquared );
|
||
|
|
||
|
float endFalloffFactor = RemapValClamped( flDist, g_flFlashlightFarZ, 0.6f * g_flFlashlightFarZ, 0.0f, 1.0f );
|
||
|
|
||
|
// Attenuation for light and to fade out shadow over distance
|
||
|
float fAtten = saturate( dot( g_vFlashlightAttenuationFactors.xyz, float3( 1.0f, 1.0f/flDist, 1.0f/flDistSquared ) ) );
|
||
|
cFlashlightColor *= fAtten;
|
||
|
|
||
|
#if FORWARD_SCATTER || INTERIOR_LAYER
|
||
|
{
|
||
|
cFlashlightColorBlurred = BlobBlurFlashlight( g_tFlashlightCookie, vProjCoords.xy );
|
||
|
cFlashlightColorBlurred * fAtten;
|
||
|
flForwardSSMask *= fAtten; // forward scatter color will attenuate faster by thickness
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ( FLASHLIGHTSHADOWS )
|
||
|
{
|
||
|
float flShadow = DoFlashlightShadow( g_tShadowDepth, g_tNormalizeRandRot, vProjCoords, vScreenPos, FLASHLIGHTDEPTHFILTERMODE, g_vShadowTweaks, true, true );
|
||
|
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
|
||
|
cFlashlightColor *= flShadow; // Shadow term
|
||
|
#if FORWARD_SCATTER || BACK_SCATTER
|
||
|
{
|
||
|
float3 flScatterPos = vProjCoords;
|
||
|
flScatterPos.z -= flForwardSSMask * ( g_flSSDepth / 100 );
|
||
|
float flScatterShadow = DoFlashlightShadow( g_tShadowDepth, g_tNormalizeRandRot, flScatterPos, vScreenPos, FLASHLIGHTDEPTHFILTERMODE, g_vShadowTweaks, true, true );
|
||
|
cFlashlightColorBlurred *= flScatterShadow;
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
cFlashlightColorBlurred *= flShadow;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
BlobLight( i.vWorldPos.xyz, vEyeDir.xyz, vBumpedWorldNormal.xyz, vBumpedWorldNormal2.xyz,
|
||
|
flCurvature, flForwardSSMask, flBackSSMask, cFlashlightColor.rgb, cFlashlightColorBlurred.rgb,
|
||
|
vLightDirection.xyz, flIridMask,
|
||
|
cDiffuse, cSpec, cSpec2, cShadowTerminator, cRim, cIrid );
|
||
|
|
||
|
#if ( INTERIOR_LAYER )
|
||
|
{
|
||
|
cInterior = cFlashlightColorBlurred;
|
||
|
cInterior *= flInteriorFogMask; // forward scatter mask without modulation
|
||
|
cInterior *= g_cInteriorColor;
|
||
|
cInterior *= cFlashlightColorBlurred;
|
||
|
cInterior *= g_flInteriorBackLightScale;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cDiffuse.rgb = lerp( cDiffuse.rgb, float3( 0.0f, 0.0f, 0.0f ), flSelfIllum ); // don't over-brighten self-illuminated areas in flashlight passes
|
||
|
cOut.a = 0.0f; // don't contribute extra opacity info in flashlight passes
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Ambient light
|
||
|
cAmbient = BlobAmbientLight( i.vLightCube, vEyeDir, vBumpedWorldNormal, flFresnel );
|
||
|
|
||
|
// Dynamic lights
|
||
|
for ( int l = 0; l < NUM_LIGHTS; l++ )
|
||
|
{
|
||
|
float3 cLightColor = PixelShaderGetLightColor( g_sLightInfo, l ).rgb * i.vLightAtten[l] * flOverBright;
|
||
|
float3 vLightDirection = PixelShaderGetLightVector( i.vWorldPos.xyz, g_sLightInfo, l ).xyz;
|
||
|
BlobLight( i.vWorldPos.xyz, vEyeDir.xyz, vBumpedWorldNormal.xyz, vBumpedWorldNormal2.xyz,
|
||
|
flCurvature, flForwardSSMask, flBackSSMask, cLightColor.rgb, cLightColor.rgb, vLightDirection.xyz,
|
||
|
flIridMask,
|
||
|
cDiffuse, cSpec, cSpec2, cShadowTerminator, cRim, cIrid );
|
||
|
}
|
||
|
|
||
|
// Blob interior colour (blurred refract buffer, plus fog and glow)
|
||
|
#if ( INTERIOR_LAYER )
|
||
|
{
|
||
|
cInterior = BlobInterior( vWorldNormal, vBumpedTangentNormal, vEyeDir,
|
||
|
vScreenPos, flPixelDepth, flCamDist );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cDiffuse.rgb = lerp( cDiffuse.rgb, cSelfIllum.rgb, flSelfIllum );
|
||
|
cOut.a = bAlphaBlend ? flSkinOpacity : 1;
|
||
|
}
|
||
|
|
||
|
float4 hueShiftCoords = float4( 0, 0, 0, 0.0f );
|
||
|
hueShiftCoords.r = cBase.r;
|
||
|
hueShiftCoords.g = cBase.g;
|
||
|
hueShiftCoords.b = cBase.b;
|
||
|
hueShiftCoords = pow( hueShiftCoords, 0.4545 ); //degamma the rgb for texture lookup
|
||
|
|
||
|
#if( TINTING )
|
||
|
{
|
||
|
float3 cTintedBase = ( tex3Dlod( g_tColorWarp, hueShiftCoords.xyzw ) ).rgb;
|
||
|
cBase = lerp( cBase, cTintedBase, flTinting );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Fresnel-based Hue shift
|
||
|
#if( FRESNEL_WARP )
|
||
|
{
|
||
|
float3 cHueShiftedBase = ( tex3Dlod( g_tFresnelColorWarp, hueShiftCoords.xyzw ) ).rgb;
|
||
|
flFresnelWarpMask *= pow( flEdgeFresnel, g_flFresnelWarpExp );
|
||
|
flFresnelWarpMask *= g_flFresnelWarpScale;
|
||
|
cBase = lerp( cBase, cHueShiftedBase, flFresnelWarpMask );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cSpec.rgb *= g_flSpecScale * g_cPhongTint.rgb;
|
||
|
cSpec2.rgb *= g_flSpecScale2;
|
||
|
cSpec2.rgb *= flSpec2Mask;
|
||
|
cSpec.rgb += cSpec2.rgb;
|
||
|
cIrid.rgb *= ( cAmbient.rgb + cDiffuse.rgb );
|
||
|
cSpec.rgb *= flSpecMask;
|
||
|
cRim.rgb *= g_flRimLightScale;
|
||
|
cInterior.rgb += cRim.rgb;
|
||
|
cAmbient.rgb *= flAmbientBoost;
|
||
|
cShadowTerminator *= cSSColor;
|
||
|
// Outer diffuse lighting blended over interior/background colours, with spec added on top
|
||
|
float3 cOuterSkin = cBase.rgb * ( cAmbient.rgb + cDiffuse.rgb + cRim.rgb ) + cShadowTerminator.rgb;
|
||
|
#if( INTERIOR_LAYER )
|
||
|
{
|
||
|
cOut.rgb = lerp( cInterior.rgb, cOuterSkin.rgb, flSkinOpacity );
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
cOut.rgb = cOuterSkin.rgb;
|
||
|
}
|
||
|
#endif
|
||
|
cOut.rgb += cSpec.rgb + cIrid.rgb;
|
||
|
float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_vEyePos.xyz, i.vWorldPos.xyz, flPixelDepth );
|
||
|
return FinalOutput( cOut, fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, g_fWriteDepthToAlpha, flPixelDepth );
|
||
|
}
|