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.
381 lines
11 KiB
381 lines
11 KiB
//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
|
|
|
|
// STATIC: "ADDITIVE" "0..1"
|
|
// STATIC: "DETAIL1" "0..1"
|
|
// STATIC: "DETAIL1BLENDMODE" "0..1"
|
|
// STATIC: "DETAIL2" "0..1"
|
|
// STATIC: "DETAIL2BLENDMODE" "0..1"
|
|
// STATIC: "TANGENTTOPACITY" "0..1"
|
|
// STATIC: "TANGENTSOPACITY" "0..1"
|
|
// STATIC: "FRESNELOPACITY" "0..1"
|
|
// STATIC: "DEPTHBLEND" "0..1" [CONSOLE]
|
|
// STATIC: "DEPTHBLEND" "0..0" [PC]
|
|
// STATIC: "VERTEXCOLOR" "0..1"
|
|
// STATIC: "FLOWMAP" "0..1"
|
|
// STATIC: "FLOW_CHEAP" "0..1" [PC]
|
|
// STATIC: "FLOW_CHEAP" "0..0" [CONSOLE]
|
|
|
|
// DYNAMIC: "ACTIVE" "0..1"
|
|
// DYNAMIC: "POWERUP" "0..1"
|
|
// DYNAMIC: "VORTEX1" "0..1"
|
|
// DYNAMIC: "VORTEX2" "0..1"
|
|
|
|
// SKIP: ( ( $DETAIL1 == 0 ) && ( $DETAIL2 != 0 ) )
|
|
// SKIP: ( ( $DETAIL1 == 0 ) && ( $DETAIL1BLENDMODE != 0 ) )
|
|
// SKIP: ( ( $DETAIL2 == 0 ) && ( $DETAIL2BLENDMODE != 0 ) )
|
|
// SKIP: ( $TANGENTTOPACITY && $TANGENTSOPACITY )
|
|
// SKIP: ( $FRESNELOPACITY ) && ( $TANGENTTOPACITY || $TANGENTSOPACITY )
|
|
// SKIP: ( $FLOWMAP && ( $DETAIL1 || $DETAIL2 ) )
|
|
// SKIP: ( $FLOW_CHEAP && !$FLOWMAP )
|
|
// SKIP: ( ( $FLOWMAP == 0 ) && ( $VORTEX1 || $VORTEX2 || $POWERUP ) )
|
|
// SKIP: ( ( $ACTIVE == 0 ) && ( $VORTEX1 || $VORTEX2 || $POWERUP ) )
|
|
|
|
#include "common_fog_ps_fxc.h"
|
|
|
|
#include "shader_constant_register_map.h"
|
|
|
|
// SAMPLERS
|
|
sampler g_tBase : register( s0 );
|
|
#if DETAIL1
|
|
sampler g_tDetail1 : register( s1 );
|
|
#endif
|
|
#if DEPTHBLEND
|
|
sampler g_tDepth : register( s3 );
|
|
#endif
|
|
#if DETAIL2
|
|
sampler g_tDetail2 : register( s4 );
|
|
#endif
|
|
#if FLOWMAP
|
|
sampler g_tFlowMap : register( s5 );
|
|
sampler g_tFlowNoise : register( s6 );
|
|
sampler g_tFlowBounds : register( s7 );
|
|
#endif
|
|
|
|
// SHADER CONSTANTS
|
|
const float4 g_vTangentTOpacityRanges : register( c0 );
|
|
const float4 g_vTangentSOpacityRanges : register( c1 );
|
|
const float4 g_vFresnelOpacityRanges : register( c2 );
|
|
|
|
const float4 g_vWriteDepthToAlpha_FlowParams : register( c3 );
|
|
#define g_bWriteDepthToAlpha ( g_vWriteDepthToAlpha_FlowParams.x )
|
|
#define g_flTime ( g_vWriteDepthToAlpha_FlowParams.y )
|
|
#define g_flPowerUp ( g_vWriteDepthToAlpha_FlowParams.z )
|
|
#define g_flIntensity ( g_vWriteDepthToAlpha_FlowParams.w )
|
|
|
|
const float4 g_DepthFeatheringConstants : register( c4 );
|
|
const float4 g_DiffuseModulation : register( c5 );
|
|
|
|
const float4 g_vFlowParams1 : register( c6 );
|
|
#define g_flWorldUvScale ( g_vFlowParams1.x ) // 1.0f / 10.0f
|
|
#define g_flNormalUvScale ( g_vFlowParams1.y ) // 1.0f / 1.15f
|
|
//#define UNUSED g_vFlowParams1.z
|
|
#define g_flOutputIntensity ( g_vFlowParams1.w )
|
|
|
|
const float4 g_vFlowParams2 : register( c7 );
|
|
#define g_flFlowTimeIntervalInSeconds ( g_vFlowParams2.x ) // 0.4f // Number of seconds to lerp from texture 1 to texture 2
|
|
#define g_flFlowUvScrollDistance ( g_vFlowParams2.y ) // 0.25f // Distance in uv space to fetch
|
|
//#define UNUSED ( g_vFlowParams2.z )
|
|
#define g_flColorFlowLerpExp ( g_vFlowParams2.w )
|
|
|
|
const float4 g_vFlowColor : register( c8 );
|
|
#define g_cFlow ( g_vFlowColor.xyz )
|
|
//#define UNUSED g_cFlow.w
|
|
|
|
const float4 g_vVortexParams : register( c9 );
|
|
#define g_cVortex ( g_vVortexParams.xyz )
|
|
#define g_flVortexSize ( g_vVortexParams.w )
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 vUV0_UV1 : TEXCOORD0;
|
|
float4 vFlowUV_UV2 : TEXCOORD1;
|
|
float4 vIteratedProjPos : TEXCOORD2;
|
|
#if ( VORTEX1 )
|
|
float3 vVortexPositions1 : TEXCOORD3;
|
|
#endif
|
|
#if ( VORTEX2 )
|
|
float3 vVortexPositions2 : TEXCOORD4;
|
|
#endif
|
|
#if ( TANGENTSOPACITY || TANGENTTOPACITY || FRESNELOPACITY )
|
|
float4 vWorldNormal_worldEyeX : TEXCOORD5;
|
|
float4 vWorldTangent_worldEyeY : TEXCOORD6;
|
|
float4 vTangentAlignedView_worldEyeZ : TEXCOORD7;
|
|
#endif
|
|
#if ( VERTEXCOLOR )
|
|
float4 vColor : COLOR0;
|
|
#endif
|
|
};
|
|
|
|
float4_color_return_type main( PS_INPUT i ) : COLOR
|
|
{
|
|
float4 cOut = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
float4 cBase = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
float3 vWorldEyeDir = float3( 0.0f, 0.0f, 0.0f );
|
|
float3 vWorldNormal = float3( 0.0f, 0.0f, 0.0f );
|
|
float3 vWorldTangent = float3( 0.0f, 0.0f, 0.0f );
|
|
|
|
#if( TANGENTSOPACITY || TANGENTTOPACITY || FRESNELOPACITY )
|
|
vWorldEyeDir = float3( i.vWorldNormal_worldEyeX.w, i.vWorldTangent_worldEyeY.w, i.vTangentAlignedView_worldEyeZ.w );
|
|
vWorldNormal = i.vWorldNormal_worldEyeX.xyz;
|
|
vWorldTangent = i.vWorldTangent_worldEyeY.xyz;
|
|
#endif
|
|
|
|
float fBackfaceRatio = 0.0f;
|
|
|
|
#if ( ACTIVE )
|
|
{
|
|
#if ( FLOWMAP )
|
|
{
|
|
float4 vBoundsTexel = tex2D( g_tFlowBounds, i.vUV0_UV1.xy );
|
|
float2 vFlowVectorTs = float2( 0.0f, 0.0f );
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
float2 vFlowUV = i.vFlowUV_UV2.xy * g_flWorldUvScale;
|
|
float4 vFlowTexel = tex2D( g_tFlowMap, vFlowUV.xy );
|
|
vFlowVectorTs = ( vFlowTexel.rg * 2.0f ) - 1.0f;
|
|
vFlowVectorTs *= vBoundsTexel.r; // slow flow
|
|
}
|
|
#endif
|
|
float flVortexIntensity = 0.0f;
|
|
|
|
// vortex 1
|
|
#if ( VORTEX1 )
|
|
{
|
|
float flVortex1Intensity = saturate( g_flVortexSize / length( i.vVortexPositions1.xyz ) - 0.5f );
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
vFlowVectorTs = lerp( vFlowVectorTs, normalize( i.vVortexPositions1.xy ), flVortex1Intensity * 0.5f );
|
|
}
|
|
#endif
|
|
flVortexIntensity += flVortex1Intensity;
|
|
}
|
|
#endif
|
|
#if ( VORTEX2 )
|
|
{
|
|
float flVortex2Intensity = saturate( g_flVortexSize / length( i.vVortexPositions2.xyz ) - 0.5f );
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
vFlowVectorTs = lerp( vFlowVectorTs, normalize( i.vVortexPositions2.xy ), flVortex2Intensity * 0.5f );
|
|
}
|
|
#endif
|
|
flVortexIntensity += flVortex2Intensity;
|
|
}
|
|
#endif
|
|
|
|
// Unpack world flow vector from texture
|
|
float flNoise = tex2D( g_tFlowNoise, i.vFlowUV_UV2.zw ).g;
|
|
|
|
// Every interval has a unique offset so we don't see the same bump texels repeating continuously
|
|
float flTimeInIntervals = ( g_flTime / ( g_flFlowTimeIntervalInSeconds * 2.0f ) ) + flNoise;
|
|
float flScrollTime1 = frac( flTimeInIntervals ) - 0.5;
|
|
float flScrollTime2 = frac( flTimeInIntervals + 0.5f ) - 0.5; // Half an interval off from texture 1
|
|
|
|
float flOffset1 = 0.0f;
|
|
float flOffset2 = 0.5f;
|
|
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
flOffset1 = floor( flTimeInIntervals ) * 0.311f;
|
|
flOffset2 = floor( flTimeInIntervals + 0.5f ) * 0.311f + 0.5f; // The +0.5 is to match the phase offset
|
|
}
|
|
#endif
|
|
|
|
float flColorFlowLerpExp = g_flColorFlowLerpExp;
|
|
|
|
float flWeight1 = abs( ( 2.0f * frac( flTimeInIntervals + 0.5f ) ) - 1.0f );
|
|
float flWeight2 = abs( ( 2.0f * frac( flTimeInIntervals ) ) - 1.0f );
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
flWeight1 = pow( flWeight1, g_flColorFlowLerpExp );
|
|
flWeight2 = pow( flWeight2, g_flColorFlowLerpExp );
|
|
}
|
|
#else
|
|
{
|
|
flWeight1 *= flWeight1;
|
|
flWeight2 *= flWeight2;
|
|
}
|
|
#endif
|
|
|
|
float flFlowUvScrollDistance = g_flFlowUvScrollDistance;
|
|
float2 vFlowUV0 = i.vUV0_UV1.zw + flOffset1;
|
|
float2 vFlowUV1 = i.vUV0_UV1.zw + flOffset2;
|
|
|
|
#if ( !FLOW_CHEAP )
|
|
{
|
|
flFlowUvScrollDistance *= ( 1.0f + flVortexIntensity );
|
|
vFlowUV0 += ( flScrollTime1 * ( flFlowUvScrollDistance * vFlowVectorTs.xy ) );
|
|
vFlowUV1 += ( flScrollTime2 * ( flFlowUvScrollDistance * vFlowVectorTs.xy ) );
|
|
}
|
|
#endif
|
|
|
|
cBase.rgba = tex2D( g_tBase, vFlowUV0 ) * flWeight1;
|
|
cBase.rgba += tex2D( g_tBase, vFlowUV1 ) * flWeight2;
|
|
|
|
#if ( POWERUP )
|
|
{
|
|
float flNoiseReveal = ( flNoise + ( 1.0f - vBoundsTexel.g ) ) * 0.5;
|
|
float flPowerStage1 = saturate( 0.7f - g_flPowerUp );
|
|
float flPowerStage2 = saturate( g_flPowerUp * 3.0f );
|
|
float flPowerUpRange1 = smoothstep( 0.02f, 0.0f, abs( flNoiseReveal - g_flPowerUp ) );
|
|
float flPowerUpRange2 = smoothstep( 0.02f, 0.0f, ( flNoiseReveal - g_flPowerUp ) );
|
|
|
|
cBase.ag += flPowerUpRange1 * g_flPowerUp * (1.0f - g_flPowerUp );
|
|
cBase.ag *= flPowerStage2 * flPowerUpRange2;
|
|
cBase.ag += vBoundsTexel.g * flPowerStage2;
|
|
}
|
|
#else
|
|
{
|
|
cBase.ag += vBoundsTexel.g;
|
|
}
|
|
#endif
|
|
|
|
float3 cFlowField = cBase.a * g_cFlow.rgb;
|
|
#if( VORTEX1 || VORTEX2 )
|
|
{
|
|
float3 cVortex = cBase.g * g_cVortex.rgb;
|
|
cBase.rgb = lerp( cFlowField, cVortex, flVortexIntensity );
|
|
}
|
|
#else
|
|
{
|
|
cBase.rgb = cFlowField;
|
|
}
|
|
#endif
|
|
cBase.rgb *= vBoundsTexel.b * g_flIntensity;
|
|
}
|
|
#else
|
|
{
|
|
cBase = tex2D( g_tBase, i.vUV0_UV1.xy );
|
|
}
|
|
#endif
|
|
|
|
#if( TANGENTTOPACITY || TANGENTSOPACITY || FRESNELOPACITY )
|
|
{
|
|
vWorldEyeDir.xyz = normalize( vWorldEyeDir.xyz );
|
|
vWorldNormal.xyz = normalize( vWorldNormal.xyz );
|
|
fBackfaceRatio = dot( vWorldEyeDir.xyz, vWorldNormal.xyz ) * 0.5f + 0.5f;
|
|
fBackfaceRatio *= fBackfaceRatio;
|
|
}
|
|
#endif
|
|
|
|
#if( TANGENTSOPACITY || TANGENTTOPACITY )
|
|
{
|
|
vWorldTangent.xyz = normalize( vWorldTangent.xyz );
|
|
}
|
|
#endif
|
|
|
|
//alpha
|
|
float alpha = 1.0f;
|
|
float fBackfaceAlpha = 1.0f;
|
|
#if TANGENTTOPACITY
|
|
{
|
|
float fTTFacing = abs( dot( vWorldTangent, normalize( i.vTangentAlignedView_worldEyeZ.xyz ) ) );
|
|
alpha *= lerp( g_vTangentTOpacityRanges.x, g_vTangentTOpacityRanges.y, pow( fTTFacing, g_vTangentTOpacityRanges.z ) );
|
|
fBackfaceAlpha = lerp( 1.0f, g_vTangentTOpacityRanges.w, fBackfaceRatio );
|
|
}
|
|
#endif
|
|
|
|
#if TANGENTSOPACITY
|
|
{
|
|
float fTSFacing = abs( dot( vWorldTangent, normalize( i.vTangentAlignedView_worldEyeZ.xyz ) ) );
|
|
alpha *= lerp( g_vTangentSOpacityRanges.x, g_vTangentSOpacityRanges.y, pow( fTSFacing, g_vTangentTOpacityRanges.z ) );
|
|
fBackfaceAlpha = min( fBackfaceAlpha, lerp( g_vTangentSOpacityRanges.w, 1.0f, fBackfaceRatio ) );
|
|
}
|
|
#endif
|
|
|
|
#if FRESNELOPACITY
|
|
{
|
|
float tNFacing = abs( dot( vWorldNormal, vWorldEyeDir.xyz ) );
|
|
alpha *= lerp( g_vFresnelOpacityRanges.x, g_vFresnelOpacityRanges.y, pow( tNFacing, g_vFresnelOpacityRanges.z ) );
|
|
fBackfaceAlpha = min( fBackfaceAlpha, lerp( g_vFresnelOpacityRanges.w, 1.0f, dot( vWorldEyeDir.xyz, vWorldNormal.xyz ) * 0.5f + 0.5f ) );
|
|
}
|
|
#endif
|
|
|
|
alpha *= fBackfaceAlpha;
|
|
|
|
#if DEPTHBLEND
|
|
{
|
|
alpha *= DepthFeathering( g_tDepth, i.vIteratedProjPos, g_DepthFeatheringConstants );
|
|
}
|
|
#endif
|
|
|
|
#if ( !FLOWMAP && !TANGENTTOPACITY && !TANGENTSOPACITY && !FRESNELOPACITY && !( DETAIL1 && DETAIL1BLENDMODE == 1 ) )
|
|
alpha *= cBase.a;
|
|
#endif
|
|
|
|
float flCameraFade = ComputeCameraFade( i.vIteratedProjPos );
|
|
|
|
//color
|
|
float4 cDetail1 = float4( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
float4 cDetail2 = float4( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
|
|
#if( DETAIL2 )
|
|
{
|
|
cDetail2 = tex2D( g_tDetail2, i.vFlowUV_UV2.zw );
|
|
}
|
|
#endif
|
|
|
|
#if( DETAIL1 )
|
|
{
|
|
cDetail1 = tex2D( g_tDetail1, i.vUV0_UV1.zw );
|
|
#if( DETAIL1BLENDMODE == 0 )
|
|
{
|
|
cBase.rgb *= 2.0f * cDetail1.rgb;
|
|
}
|
|
#else
|
|
{
|
|
cBase.rgb = lerp( cBase.rgb * cDetail1.rgb, cBase.rgb, cBase.a );
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if( DETAIL2 )
|
|
{
|
|
#if( DETAIL2BLENDMODE == 0 )
|
|
{
|
|
#if( DETAIL1 )
|
|
{
|
|
cDetail2.rgb *= cDetail1.rgb;
|
|
}
|
|
#endif
|
|
cBase.rgb += cDetail2.rgb;
|
|
}
|
|
#else
|
|
{
|
|
cBase.rgb *= cDetail2.rgb;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
cOut.a = alpha;
|
|
cOut.rgb = cBase.rgb;
|
|
#if ( POWERUP && !FLOWMAP )
|
|
{
|
|
cOut.rgb *= g_flPowerUp;
|
|
}
|
|
#endif
|
|
|
|
#if ( ADDITIVE )
|
|
{
|
|
cOut.rgb *= ( 1.0f + alpha ) * flCameraFade;
|
|
cOut.a = 1.0f;
|
|
}
|
|
#endif
|
|
|
|
#if ( VERTEXCOLOR )
|
|
{
|
|
// fun with saturation:
|
|
float3 vColor = pow( i.vColor.rgb, ( 2.0f - alpha ) * 2.0f );
|
|
cOut.rgb *= vColor.rgb;
|
|
}
|
|
#endif
|
|
}
|
|
#endif // ACTIVE
|
|
|
|
// Limit tonemap scalar to 0.0-1.0 so the colors don't oversaturate, but let it drop down to 0 in case we're fading
|
|
float flTonemapScalar = saturate( LINEAR_LIGHT_SCALE );
|
|
|
|
// g_flOutputIntensity is normally 1.0f, except to work around overall intensity problems on platforms that blend in gamma space (such as PS3).
|
|
return FinalOutput( cOut, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE ) * flTonemapScalar * g_flOutputIntensity;
|
|
}
|