94 lines
3.3 KiB
HLSL
94 lines
3.3 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "/Engine/Private/Common.ush"
|
|
#include "/Engine/Private/ShadowFilteringCommon.ush"
|
|
|
|
Texture2D SceneDepthTex;
|
|
SamplerState SceneDepthSampler;
|
|
|
|
Texture2D ShadowDepthTexture;
|
|
SamplerState ShadowDepthTextureSampler;
|
|
|
|
float4 SceneDepthPositionScaleBias;
|
|
float4x4 SceneDepthScreenToWorld;
|
|
|
|
float4x4 ShadowMatrix;
|
|
float4 ShadowBufferSize;
|
|
float4 ShadowInvDeviceZToWorldZ;
|
|
float4 ShadowStrengthBias;
|
|
float3 LightWorldDirection;
|
|
|
|
uint bIsPerspectiveProjection;
|
|
|
|
// Returns the screen position for projection matrix calculations depending on the type of projection the view is using
|
|
float2 GetScreenPositionForProj(in float2 ScreenPosition, in float SceneDepth)
|
|
{
|
|
return select(bIsPerspectiveProjection == 0, ScreenPosition, ScreenPosition * SceneDepth);
|
|
}
|
|
|
|
// Calculate world position from scene depth
|
|
float4 CalcWorldFromSceneDepth(in float2 UV, in float Depth)
|
|
{
|
|
float2 ScreenPosition = (UV - SceneDepthPositionScaleBias.wz) / SceneDepthPositionScaleBias.xy;
|
|
float4 HomogeneousWorldPosition = mul(float4(GetScreenPositionForProj(ScreenPosition, Depth), Depth, 1), SceneDepthScreenToWorld);
|
|
float3 WorldPosition = HomogeneousWorldPosition.xyz / HomogeneousWorldPosition.w;
|
|
|
|
return float4(WorldPosition, 1.0);
|
|
}
|
|
|
|
// Convert device-z depth to scene depth
|
|
float ShadowDeviceZToSceneDepth(float DeviceZ)
|
|
{
|
|
return DeviceZ * ShadowInvDeviceZToWorldZ[0] + ShadowInvDeviceZToWorldZ[1] + 1.0f / (DeviceZ * ShadowInvDeviceZToWorldZ[2] - ShadowInvDeviceZToWorldZ[3]);
|
|
}
|
|
|
|
// Percentage-close filtering shadow mapping
|
|
float ManualPCF(in float4 ShadowPosition, in float NoL)
|
|
{
|
|
float SceneDepth = ShadowDeviceZToSceneDepth(ShadowPosition.z) - saturate(1 - NoL) * ShadowStrengthBias.y;
|
|
|
|
FPCFSamplerSettings Settings;
|
|
Settings.ShadowDepthTexture = ShadowDepthTexture;
|
|
Settings.ShadowDepthTextureSampler = ShadowDepthTextureSampler;
|
|
Settings.ShadowBufferSize = ShadowBufferSize;
|
|
Settings.TransitionScale = 1.0; // TODO: Parametrize like FProjectedShadowInfo::ComputeTransitionSize
|
|
Settings.SceneDepth = SceneDepth;
|
|
Settings.bSubsurface = false;
|
|
Settings.bTreatMaxDepthUnshadowed = false;
|
|
Settings.DensityMulConstant = 0;
|
|
Settings.ProjectionDepthBiasParameters = 0;
|
|
float Shadow = Manual5x5PCF(ShadowPosition.xy, Settings);
|
|
|
|
return Shadow;
|
|
}
|
|
|
|
void MainPS(
|
|
noperspective float4 InUVAndScreenPos : TEXCOORD0,
|
|
out float4 OutColor : SV_Target0)
|
|
{
|
|
float2 UV = InUVAndScreenPos.xy;
|
|
float SceneDepth = SceneDepthTex.SampleLevel(SceneDepthSampler, UV, 0).r;
|
|
|
|
float4 WorldPosition = CalcWorldFromSceneDepth(UV, SceneDepth);
|
|
float4 ShadowPosition = mul(WorldPosition, ShadowMatrix);
|
|
float2 ShadowUV = ShadowPosition.xy;
|
|
|
|
if(any(ShadowUV < 0.0) || any(ShadowUV > 1.0))
|
|
{
|
|
OutColor.rgb = 1.0;
|
|
}
|
|
else
|
|
{
|
|
float3 Ddx = ddx(WorldPosition);
|
|
float3 Ddy = ddy(WorldPosition);
|
|
float3 WorldNormal = normalize(cross(Ddx, Ddy));
|
|
const float NoL = saturate(abs(dot(WorldNormal, LightWorldDirection)));
|
|
|
|
float ShadowVisibility = ManualPCF(ShadowPosition, NoL);
|
|
|
|
OutColor.rgb = lerp(1.0, ShadowVisibility, ShadowStrengthBias.x);
|
|
}
|
|
|
|
OutColor.a = 1.0;
|
|
}
|