/*============================================================================= ModShadowCommon.usf: modulated shadow helper functions. Copyright 1998-2010 Epic Games, Inc. All Rights Reserved. =============================================================================*/ #ifndef MODSHADOW_LIGHTTYPE_DIRECTIONAL #define MODSHADOW_LIGHTTYPE_DIRECTIONAL 0 #endif #ifndef MODSHADOW_LIGHTTYPE_POINT #define MODSHADOW_LIGHTTYPE_POINT 0 #endif #ifndef MODSHADOW_LIGHTTYPE_SPOT #define MODSHADOW_LIGHTTYPE_SPOT 0 #endif /** color to modulate shadowed areas on screen */ float4 ShadowModulateColor; /** world position of light casting a shadow. Note: w = 1.0 / Radius */ float4 LightPosition; /** needed to get world positions from deferred scene depth values */ float4x4 ScreenToWorld; /** Falloff parameters for light casting a shadow */ half3 FalloffParameters; static half FalloffExponent = FalloffParameters.x; static half FalloffDistanceScale = FalloffParameters.y; static half FalloffDistanceBias = FalloffParameters.z; /** spot light direction vector in world space */ float3 SpotDirection; /** spot light cone cut-off angles */ float2 SpotAngles; float ShadowAttenuation(float4 ScreenPositionVec,float SceneDepth) { // derive world position from scene depth float4 WorldPosition = MulMatrix(ScreenToWorld,float4((ScreenPositionVec.xy/ScreenPositionVec.w)*SceneDepth,SceneDepth,1)); // vector from world position to light float4 WorldLightVector = float4((LightPosition.xyz - WorldPosition.xyz),0) * LightPosition.w; // mul world vector by 1/radius to get distance attenuation // BIOSTART - August 25, 2010 - Wihlidal, Graham - PS3 Fragment and Vertex Shader Optimizations // GW: Use half precision pow half Attenuation = pow( saturate(1.0f - Square(max(0,length(WorldLightVector) * FalloffDistanceScale + FalloffDistanceBias)) ), FalloffExponent ); // BIOEND #if MODSHADOW_LIGHTTYPE_SPOT // radial attenuation based on inner/outer cone angles for spot lights Attenuation *= Square(clamp((dot(normalize((float3)WorldLightVector.xyz), -SpotDirection) - SpotAngles.x) * SpotAngles.y,0,1)); #endif // attenuation result as a percentage of world light vector length to light radius return Attenuation; } #if XBOX /* Whether to apply the emissive masking */ bool bApplyEmissiveToShadowCoverage; /* Scale emissive mask alpha by scene color bias */ float EmissiveAlphaMaskScale; #endif /** * Applies emissive masking based on a bit in scene color alpha on xbox */ half ApplyEmissiveToShadowCoverage(float4 ScreenPosition, half ShadowCoverage) { #if XBOX // Using a static branch to keep from incurring this overhead with normal modulated shadows, without having to compile out extra shaders. if (bApplyEmissiveToShadowCoverage) { // read the scene alpha value written during the base pass. // scale by EmissiveAlphaMaskScale is needed to convert to unit range. half SceneAlpha = PreviousLighting(ScreenPosition).a * EmissiveAlphaMaskScale; // if SceneAlpha >= 0.666, then the emissive bit is set. // The next lower value possible is 0.333 - so we can round the alpha value // to the nearest whole value. Getting 1 when the emissive bit is not set and 0 when it isn't half EmissiveBit = round(SceneAlpha); // when EmissiveBit is 1.0, return 1.0 otherwise return ShadowCoverage ShadowCoverage = max(ShadowCoverage, EmissiveBit); } #endif return ShadowCoverage; }