//======= Copyright © 1996-2008, Valve Corporation, All rights reserved. ====== // STATIC: "CUBEMAP" "0..1" // STATIC: "DIFFUSELIGHTING" "0..1" // STATIC: "LIGHTWARPTEXTURE" "0..1" // STATIC: "SELFILLUM" "0..1" // STATIC: "SELFILLUMFRESNEL" "0..1" // STATIC: "NORMALMAPALPHAENVMAPMASK" "0..1" // STATIC: "HALFLAMBERT" "0..1" // STATIC: "FLASHLIGHT" "0..1" // STATIC: "DETAILTEXTURE" "0..1" // STATIC: "DETAIL_BLEND_MODE" "0..6" // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps20b] [PC] // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" [ps30] [PC] // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..0" [ps20b] [XBOX] // STATIC: "BLENDTINTBYBASEALPHA" "0..1" // DYNAMIC: "PIXELFOGTYPE" "0..1" [ps20] // DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1" [ps20] // DYNAMIC: "NUM_LIGHTS" "0..2" [ps20] // DYNAMIC: "NUM_LIGHTS" "0..4" [ps20b] // DYNAMIC: "NUM_LIGHTS" "0..4" [ps30] // DYNAMIC: "AMBIENT_LIGHT" "0..1" // DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" [ps20b] // DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" [ps30] [PC] // We don't use light combos when doing the flashlight // SKIP: ( $FLASHLIGHT != 0 ) && ( $NUM_LIGHTS > 0 ) [PC] // We don't care about flashlight depth unless the flashlight is on // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps20b] // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps30] // Flashlight shadow filter mode is irrelevant if there is no flashlight // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps20b] // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps30] // SKIP: (! $DETAILTEXTURE) && ( $DETAIL_BLEND_MODE != 0 ) // Don't do diffuse warp on flashlight // SKIP: ( $FLASHLIGHT == 1 ) && ( $LIGHTWARPTEXTURE == 1 ) [PC] // Only warp diffuse if we have it at all // SKIP: ( $DIFFUSELIGHTING == 0 ) && ( $LIGHTWARPTEXTURE == 1 ) // Skip this since it blows ps20 instruction limits // SKIP: ( $SELFILLUMFRESNEL == 1 ) && ( $LIGHTWARPTEXTURE == 1 ) // Only need self illum fresnel when self illum enabled // SKIP: ( $SELFILLUM == 0 ) && ( $SELFILLUMFRESNEL == 1 ) // SKIP: ( $FLASHLIGHT == 1 ) && ( $SELFILLUMFRESNEL == 1 ) [PC] // SKIP: ( $FLASHLIGHT == 1 ) && ( $SELFILLUM == 1 ) [PC] // SKIP: ( $SELFILLUMFRESNEL == 1 ) && ( $DETAILTEXTURE == 1 ) // SKIP: ( $SELFILLUMFRESNEL == 1 ) && ( $NORMALMAPALPHAENVMAPMASK == 1 ) // BlendTintByBaseAlpha is incompatible with other interpretations of alpha // SKIP: ($BLENDTINTBYBASEALPHA) && ($SELFILLUM) // Only _XBOX allows flashlight and cubemap in the current implementation // SKIP: $FLASHLIGHT && $CUBEMAP [PC] // Meaningless combinations // SKIP: $NORMALMAPALPHAENVMAPMASK && !$CUBEMAP #include "common_flashlight_fxc.h" #include "common_vertexlitgeneric_dx9.h" const float4 g_EnvmapTint_TintReplaceFactor : register( c0 ); const float4 g_DiffuseModulation : register( c1 ); const float4 g_EnvmapContrast_ShadowTweaks : register( c2 ); const float3 g_EnvmapSaturation : register( c3 ); const float4 g_SelfIllumTint_and_BlendFactor : register( c4 ); #define g_SelfIllumTint ( g_SelfIllumTint_and_BlendFactor.rgb) #define g_DetailBlendFactor (g_SelfIllumTint_and_BlendFactor.w) const float3 cAmbientCube[6] : register( c5 ); // 11, 12 not used? #if ( SELFILLUMFRESNEL == 1 ) const float4 g_SelfIllumScaleBiasExpBrightness : register( c11 ); #endif const float4 g_ShaderControls : register( c12 ); #define g_fPixelFogType g_ShaderControls.x #define g_fWriteDepthToAlpha g_ShaderControls.y #define g_fWriteWaterFogToDestAlpha g_ShaderControls.z // 2 registers each - 6 registers total PixelShaderLightInfo cLightInfo[3] : register( c13 ); // through c18 const float3 g_EyePos : register( c20 ); const float4 g_FogParams : register( c21 ); const float4 g_FlashlightAttenuationFactors : register( c22 ); const float3 g_FlashlightPos : register( c23 ); const float4x4 g_FlashlightWorldToTexture : register( c24 ); // through c27 sampler BaseTextureSampler : register( s0 ); sampler EnvmapSampler : register( s1 ); sampler DetailSampler : register( s2 ); sampler BumpmapSampler : register( s3 ); sampler EnvmapMaskSampler : register( s4 ); sampler NormalizeSampler : register( s5 ); sampler RandRotSampler : register( s6 ); // RandomRotation sampler sampler FlashlightSampler : register( s7 ); sampler ShadowDepthSampler : register( s8 ); // Flashlight shadow depth map sampler sampler DiffuseWarpSampler : register( s9 ); // Lighting warp sampler (1D texture for diffuse lighting modification) struct PS_INPUT { float4 baseTexCoord2_tangentSpaceVertToEyeVectorXY : TEXCOORD0; float3 lightAtten : TEXCOORD1; float4 worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ : TEXCOORD2; float3 vWorldNormal : TEXCOORD3; // World-space normal float4 vWorldTangent : TEXCOORD4; #if ((defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0))) float4 vProjPos : TEXCOORD5; #else float3 vWorldBinormal : TEXCOORD5; #endif float4 worldPos_projPosZ : TEXCOORD6; float3 detailTexCoord_atten3 : TEXCOORD7; float4 fogFactorW : COLOR1; #if defined( _X360 ) #if FLASHLIGHT float4 flashlightSpacePos : TEXCOORD8; #endif #endif }; // Calculate both types of Fog and lerp to get result float CalcPixelFogFactorConst( float fPixelFogType, const float4 fogParams, const float flEyePosZ, const float flWorldPosZ, const float flProjPosZ ) { float fRangeFog = CalcRangeFog( flProjPosZ, fogParams.x, fogParams.z, fogParams.w ); float fHeightFog = CalcWaterFogAlpha( fogParams.y, flEyePosZ, flWorldPosZ, flProjPosZ, fogParams.w ); return lerp( fRangeFog, fHeightFog, fPixelFogType ); } // Blend both types of Fog and lerp to get result float3 BlendPixelFogConst( const float3 vShaderColor, float pixelFogFactor, const float3 vFogColor, float fPixelFogType ) { pixelFogFactor = saturate( pixelFogFactor ); float3 fRangeResult = lerp( vShaderColor.rgb, vFogColor.rgb, pixelFogFactor * pixelFogFactor ); //squaring the factor will get the middle range mixing closer to hardware fog float3 fHeightResult = lerp( vShaderColor.rgb, vFogColor.rgb, saturate( pixelFogFactor ) ); return lerp( fRangeResult, fHeightResult, fPixelFogType ); } float4 FinalOutputConst( const float4 vShaderColor, float pixelFogFactor, float fPixelFogType, const int iTONEMAP_SCALE_TYPE, float fWriteDepthToDestAlpha, const float flProjZ ) { float4 result = vShaderColor; if( iTONEMAP_SCALE_TYPE == TONEMAP_SCALE_LINEAR ) { result.rgb *= LINEAR_LIGHT_SCALE; } else if( iTONEMAP_SCALE_TYPE == TONEMAP_SCALE_GAMMA ) { result.rgb *= GAMMA_LIGHT_SCALE; } result.a = lerp( result.a, DepthToDestAlpha( flProjZ ), fWriteDepthToDestAlpha ); result.rgb = BlendPixelFogConst( result.rgb, pixelFogFactor, g_LinearFogColor.rgb, fPixelFogType ); result.rgb = SRGBOutput( result.rgb ); //SRGB in pixel shader conversion return result; } float4 main( PS_INPUT i ) : COLOR { bool bCubemap = CUBEMAP ? true : false; bool bDiffuseLighting = DIFFUSELIGHTING ? true : false; bool bDoDiffuseWarp = LIGHTWARPTEXTURE ? true : false; bool bSelfIllum = SELFILLUM ? true : false; bool bSelfIllumFresnel = SELFILLUMFRESNEL ? true : false; bool bNormalMapAlphaEnvmapMask = NORMALMAPALPHAENVMAPMASK ? true : false; bool bHalfLambert = HALFLAMBERT ? true : false; bool bFlashlight = (FLASHLIGHT!=0) ? true : false; bool bAmbientLight = AMBIENT_LIGHT ? true : false; bool bDetailTexture = DETAILTEXTURE ? true : false; bool bBlendTintByBaseAlpha = BLENDTINTBYBASEALPHA ? true : false; int nNumLights = NUM_LIGHTS; #if ((defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0))) float3 vWorldBinormal = cross( i.vWorldNormal.xyz, i.vWorldTangent.xyz ) * i.vWorldTangent.w; #else float3 vWorldBinormal = i.vWorldBinormal; #endif // Unpack four light attenuations float4 vLightAtten = float4( i.lightAtten, i.detailTexCoord_atten3.z ); float4 baseColor = float4( 1.0f, 1.0f, 1.0f, 1.0f ); baseColor = tex2D( BaseTextureSampler, i.baseTexCoord2_tangentSpaceVertToEyeVectorXY.xy ); #if DETAILTEXTURE float4 detailColor = tex2D( DetailSampler, i.detailTexCoord_atten3.xy ); baseColor = TextureCombine( baseColor, detailColor, DETAIL_BLEND_MODE, g_DetailBlendFactor ); #endif float specularFactor = 1.0f; float4 normalTexel = tex2D( BumpmapSampler, i.baseTexCoord2_tangentSpaceVertToEyeVectorXY.xy ); float3 tangentSpaceNormal = normalTexel * 2.0f - 1.0f; if ( bNormalMapAlphaEnvmapMask ) specularFactor = normalTexel.a; float3 diffuseLighting = float3( 1.0f, 1.0f, 1.0f ); float3 worldSpaceNormal = float3( 0.0f, 0.0f, 1.0f ); if ( bDiffuseLighting || bFlashlight || bCubemap || bSelfIllumFresnel ) { worldSpaceNormal = Vec3TangentToWorld( tangentSpaceNormal, i.vWorldNormal, i.vWorldTangent, vWorldBinormal ); #if ( defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0) ) worldSpaceNormal = normalize( worldSpaceNormal ); #else worldSpaceNormal = NormalizeWithCubemap( NormalizeSampler, worldSpaceNormal ); #endif } if ( bDiffuseLighting ) { diffuseLighting = PixelShaderDoLighting( i.worldPos_projPosZ.xyz, worldSpaceNormal, float3( 0.0f, 0.0f, 0.0f ), false, bAmbientLight, vLightAtten, cAmbientCube, NormalizeSampler, nNumLights, cLightInfo, bHalfLambert, false, 1.0f, bDoDiffuseWarp, DiffuseWarpSampler ); } float3 albedo = baseColor; if (bBlendTintByBaseAlpha) { float3 tintedColor = albedo * g_DiffuseModulation.rgb; tintedColor = lerp(tintedColor, g_DiffuseModulation.rgb, g_EnvmapTint_TintReplaceFactor.w); albedo = lerp(albedo, tintedColor, baseColor.a); } else { albedo = albedo * g_DiffuseModulation.rgb; } float alpha = g_DiffuseModulation.a; if ( !bSelfIllum && !bBlendTintByBaseAlpha ) { alpha *= baseColor.a; } #if FLASHLIGHT if( bFlashlight ) { int nShadowSampleLevel = 0; bool bDoShadows = false; float2 vProjPos = float2(0, 0); // On ps_2_b, we can do shadow mapping #if ( FLASHLIGHTSHADOWS && (defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0) ) ) nShadowSampleLevel = FLASHLIGHTDEPTHFILTERMODE; bDoShadows = FLASHLIGHTSHADOWS; vProjPos = i.vProjPos.xy / i.vProjPos.w; // Screen-space position for shadow map noise #endif #if defined ( _X360 ) float4 flashlightSpacePosition = i.flashlightSpacePos; #else float4 flashlightSpacePosition = mul( float4( i.worldPos_projPosZ.xyz, 1.0f ), g_FlashlightWorldToTexture ); #endif float3 flashlightColor = DoFlashlight( g_FlashlightPos, i.worldPos_projPosZ.xyz, flashlightSpacePosition, worldSpaceNormal, g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w, FlashlightSampler, ShadowDepthSampler, RandRotSampler, nShadowSampleLevel, bDoShadows, false, vProjPos, false, g_EnvmapContrast_ShadowTweaks ); #if defined ( _X360 ) diffuseLighting += flashlightColor; #else diffuseLighting = flashlightColor; #endif } #endif float3 diffuseComponent = albedo * diffuseLighting; #if !FLASHLIGHT || defined ( _X360 ) if ( bSelfIllum ) { #if ( SELFILLUMFRESNEL == 1 ) // To free up the constant register...see top of file // This will apply a fresnel term based on the vertex normal (not the per-pixel normal!) to help fake and internal glow look #if ((defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0))) float3 vVertexNormal = normalize( i.vWorldNormal.xyz ); float flSelfIllumFresnel = ( pow( saturate( dot( vVertexNormal.xyz, normalize( i.worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ.xyz ) ) ), g_SelfIllumScaleBiasExpBrightness.z ) * g_SelfIllumScaleBiasExpBrightness.x ) + g_SelfIllumScaleBiasExpBrightness.y; float3 selfIllumComponent = g_SelfIllumTint * albedo * g_SelfIllumScaleBiasExpBrightness.w; diffuseComponent = lerp( diffuseComponent, selfIllumComponent, baseColor.a * saturate( flSelfIllumFresnel ) ); #else float3 vVertexNormal = i.vWorldNormal.xyz; float flSelfIllumFresnel = ( pow( saturate( dot( vVertexNormal.xyz, ( i.worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ.xyz ) ) ), g_SelfIllumScaleBiasExpBrightness.z ) * g_SelfIllumScaleBiasExpBrightness.x ) + g_SelfIllumScaleBiasExpBrightness.y; float3 selfIllumComponent = g_SelfIllumTint * albedo * g_SelfIllumScaleBiasExpBrightness.w; diffuseComponent = lerp( diffuseComponent, selfIllumComponent, baseColor.a * saturate( flSelfIllumFresnel ) ); #endif #else float3 selfIllumComponent = g_SelfIllumTint * albedo; diffuseComponent = lerp( diffuseComponent, selfIllumComponent, baseColor.a ); #endif } #endif float3 specularLighting = float3( 0.0f, 0.0f, 0.0f ); #if !FLASHLIGHT || defined ( _X360 ) if( bCubemap ) { float3 reflectVect = CalcReflectionVectorUnnormalized( worldSpaceNormal, i.worldVertToEyeVectorXYZ_tangentSpaceVertToEyeVectorZ.xyz ); specularLighting = ENV_MAP_SCALE * texCUBE( EnvmapSampler, reflectVect ); specularLighting *= specularFactor; specularLighting *= g_EnvmapTint_TintReplaceFactor.rgb; float3 specularLightingSquared = specularLighting * specularLighting; specularLighting = lerp( specularLighting, specularLightingSquared, g_EnvmapContrast_ShadowTweaks ); float3 greyScale = dot( specularLighting, float3( 0.299f, 0.587f, 0.114f ) ); specularLighting = lerp( greyScale, specularLighting, g_EnvmapSaturation ); } #endif float3 result = diffuseComponent + specularLighting; #if defined(SHADER_MODEL_PS_2_0) float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.z, i.worldPos_projPosZ.z, i.worldPos_projPosZ.w ); #else float fogFactor = CalcPixelFogFactorConst( g_fPixelFogType, g_FogParams, g_EyePos.z, i.worldPos_projPosZ.z, i.worldPos_projPosZ.w ); #endif #if defined( SHADER_MODEL_PS_2_0 ) #if WRITEWATERFOGTODESTALPHA && (PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT) alpha = fogFactor; #endif #else // 2b or higher alpha = lerp( alpha, fogFactor, g_fPixelFogType * g_fWriteWaterFogToDestAlpha ); // Use the fog factor if it's height fog #endif #if defined( SHADER_MODEL_PS_2_0 ) return FinalOutput( float4( result.rgb, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, false, i.worldPos_projPosZ.w ); #else return FinalOutputConst( float4( result.rgb, alpha ), fogFactor, g_fPixelFogType, TONEMAP_SCALE_LINEAR, g_fWriteDepthToAlpha, i.worldPos_projPosZ.w ); #endif }