Files
UnrealEngineUWP/Engine/Shaders/PostProcessDOF.usf
Martin Mittring 990a6d2bda fixed UERNDR-75 The near depth of field blur should occur after separate translucency is merged in to the final frame buffer to avoid errors
We now occlude Separate Transluceny by new Gaussian DOF.

Details: optimized one full res pass if GaussianDOF with SeparateTranslucency is used. NearDOF is now occlusing/hiding SeparateTransluceny which allows DOFVignette to work better and it seems more right in general. If Far and Near DOF is used with Gaussian DOF it now requires another half res setup pass and full res composite pass.
Added enum to allow for 3 custom colors if a texture is not bound.

[CL 2656232 by Martin Mittring in Main branch]
2015-08-14 11:59:44 -04:00

228 lines
7.7 KiB
Plaintext

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PostProcessDOF.usf: PostProcessing Depth of Field
=============================================================================*/
#include "Common.usf"
#include "PostProcessCommon.usf"
#include "DeferredShadingCommon.usf" // FGBufferData
#include "DepthOfFieldCommon.usf"
// todo move to central place
float ComputeDOFNearFocalMask(float SceneDepth)
{
float NearFocalPlane = View.DepthOfFieldFocalDistance;
return saturate((NearFocalPlane - SceneDepth) / View.DepthOfFieldNearTransitionRegion);
}
// todo move to central place
float ComputeDOFFarFocalMask(float SceneDepth)
{
float FarFocalPlane = View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion;
return saturate((SceneDepth - FarFocalPlane) / View.DepthOfFieldFarTransitionRegion);
}
// @return .x:far, .y:near
float2 ComputeDOFFocalMask(float SceneDepth, float SkyWithoutHorizonMask)
{
float2 Ret = float2(ComputeDOFFarFocalMask(SceneDepth), ComputeDOFNearFocalMask(SceneDepth));
float SkyFocusDistance = DepthOfFieldParams[0].x;
// The skybox should not be faded out, expect in the horizon, this can be optimized
if(SceneDepth > SkyFocusDistance)
{
Ret.x = lerp(Ret.x, 0, SkyWithoutHorizonMask);
}
return Ret;
}
// pixel shader entry point
void SetupPS(
float4 UVAndScreenPos : TEXCOORD0
, out float4 OutColor0 : SV_Target0
#if MRT_COUNT > 0
, out float4 OutColor1 : SV_Target1
#endif
)
{
float2 UV = UVAndScreenPos.xy;
float2 Offset = 0.5f * PostprocessInput0Size.zw;
float MaskDistance = View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion * 0.5f;
float4 DepthQuad = GatherSceneDepth(UV, PostprocessInput1Size.zw);
float4 FarColor = 0;
float4 NearColor = 0;
float2 Mask;
float4 Sample;
// for each sample of the full res input image
// we compute the mask (front of back layer)
// and put into MRT0 or MRT1
// screen position in [-1, 1] screen space
float2 ScreenSpacePos = UVAndScreenPos.zw;
// can be optimized, needed to not blur the skybox
float3 ScreenVector = normalize(mul(float4(ScreenSpacePos, 1, 0), View.ScreenToWorld).xyz);
float SkyWithoutHorizonMask = saturate(ScreenVector.z * 3.0f);
// 0:see though..1:Near blurred
float VignetteMask = 0;
#if DOF_VIGNETTE
{
float DepthOfFieldVignetteMul = DepthOfFieldParams[0].y;
float DepthOfFieldVignetteAdd = DepthOfFieldParams[0].z;
// todo: we could optimize that multiplication away
float InvAspectRatio = View.ViewSizeAndInvSize.y * View.ViewSizeAndInvSize.z;
float CenterDist = length(ScreenSpacePos * float2(1, InvAspectRatio));
// We prepare the constants on CPU side and use MAD (Multiply and Add) as this is faster
VignetteMask = saturate(CenterDist * DepthOfFieldVignetteMul + DepthOfFieldVignetteAdd);
}
#endif
Mask = ComputeDOFFocalMask(DepthQuad.x, SkyWithoutHorizonMask);
Sample = float4(Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, UV + Offset * float2(-1, 1), 0).rgb, 1);
FarColor += Sample * Mask.x;
NearColor += Sample * lerp(Mask.y, 1, VignetteMask);
Mask = ComputeDOFFocalMask(DepthQuad.y, SkyWithoutHorizonMask);
Sample = float4(Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + Offset * float2(1, 1)).rgb, 1);
FarColor += Sample * Mask.x;
NearColor += Sample * lerp(Mask.y, 1, VignetteMask);
Mask = ComputeDOFFocalMask(DepthQuad.z, SkyWithoutHorizonMask);
Sample = float4(Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + Offset * float2(1, -1)).rgb, 1);
FarColor += Sample * Mask.x;
NearColor += Sample * lerp(Mask.y, 1, VignetteMask);
Mask = ComputeDOFFocalMask(DepthQuad.w, SkyWithoutHorizonMask);
Sample = float4(Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + Offset * float2(-1, -1)).rgb, 1);
FarColor += Sample * Mask.x;
NearColor += Sample * lerp(Mask.y, 1, VignetteMask);
// we average 4 samples
FarColor /= 4;
NearColor /= 4;
#if MRT_COUNT > 1
OutColor0 = FarColor;
OutColor1 = NearColor;
#else
#if NEAR_BLUR
OutColor0 = NearColor;
#else
OutColor0 = FarColor;
#endif
#endif
}
float4 DepthOfFieldUVLimit;
// pixel shader to combine the full res scene and the blurred images behind and in front of the the focal plane
void MainRecombinePS(
in float4 UVAndScreenPos : TEXCOORD0,
out float4 OutColor : SV_Target0
)
{
// SceneColor in full res
float2 PixelPosCenter = UVAndScreenPos.zw * ScreenPosToPixel.xy + ScreenPosToPixel.zw + 0.5f;
float2 FullResUV = PixelPosCenter * PostprocessInput0Size.zw;
// DOF in half res
// float2 ViewportUV = FullResUV * float2(1, DepthOfFieldParams[1].z);// - 0.5 * PostprocessInput1Size.zw;
// float2 ViewportUV = (PixelPos * 0.5f + 0.5f) * PostprocessInput1Size.zw;
float2 ViewportUV = UVAndScreenPos.xy;
// Clamp UV to avoid pulling bad data.
ViewportUV.x = clamp(ViewportUV.x, DepthOfFieldUVLimit.x, DepthOfFieldUVLimit.z);
ViewportUV.y = clamp(ViewportUV.y, DepthOfFieldUVLimit.y, DepthOfFieldUVLimit.w);
float4 SceneColorAndDepth = float4(Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, FullResUV).rgb, CalcSceneDepth(FullResUV));
float3 UnfocusedSceneColor = SceneColorAndDepth.rgb;
// I'm presuming all that matters here is the W==0 bit to mask out this value
// TODO: Should check that compiler is doing a good job of removing the usages of this
// from the rest of the code. It has no reason not to be able to do so...
float4 DOFAccumLayer1 = float4(0,0,0,0);
float4 DOFAccumLayer3 = float4(0,0,0,0);
#if FAR_BLUR
DOFAccumLayer1 = Texture2DSample(PostprocessInput1, PostprocessInput1Sampler, ViewportUV);
#endif
#if NEAR_BLUR
DOFAccumLayer3 = Texture2DSample(PostprocessInput2, PostprocessInput2Sampler, ViewportUV);
#endif
float Layer1Mask = DOFAccumLayer1.a;
float Layer2Mask = 1.0f - ComputeDOFFarFocalMask(SceneColorAndDepth.a);
// float Layer2Mask = 1.0f - DOFAccumLayer1.a;
float Layer3Mask = DOFAccumLayer3.a;
float PerPixelNearMask = ComputeDOFNearFocalMask(SceneColorAndDepth.a);
// 3 layers
float Div0Bias = 0.0001f;
// RGB color, A how much the full resolution showes through
float3 LayerMerger = 0;
// Layer 1: half res background
LayerMerger = (UnfocusedSceneColor * Div0Bias + DOFAccumLayer1.rgb) / (DOFAccumLayer1.a + Div0Bias);
// Needed to cope with the skybox not being blurred, the tweak value
// avoids having a discontinuity between blurry far objects and the skybox
// and is choosen to not produce too much blobby looking out of focus rendering.
float Blend = DOFAccumLayer1.a;
// Magic function to transform alpha into smooth blend function against in-focus skybox.
Blend = sqrt(Blend);
Blend = sqrt(Blend);
Blend = Blend * Blend * (3.0 - 2.0 * Blend);
LayerMerger = lerp(UnfocusedSceneColor, LayerMerger, Blend);
// Layer 2: then we add the focused scene to fill the empty areas
float Smash = 0.25;
Layer2Mask = saturate((Layer2Mask - (1.0 - Smash)) * rcp(Smash));
Layer2Mask *= Layer2Mask;
// LayerMerger = lerp(LayerMerger, SceneColorAndDepth.rgb, Layer2Mask * (1 - PerPixelNearMask));
LayerMerger = lerp(LayerMerger, SceneColorAndDepth.rgb, Layer2Mask);
// apply SeparateTransluceny (todo: shader permutation to save a bit of performance if the feature is disabled)
{
float4 SeparateTranslucency = Texture2DSample(PostprocessInput3, PostprocessInput3Sampler, FullResUV);
// add RGB, darken by A (this allows to represent translucent and additive blending)
LayerMerger.rgb = LayerMerger.rgb * SeparateTranslucency.a + SeparateTranslucency.rgb;
}
float3 FrontLayer = (UnfocusedSceneColor * Div0Bias + DOFAccumLayer3.rgb) / (DOFAccumLayer3.a + Div0Bias);
// Layer 3: on top of that blend the front half res layer
LayerMerger = lerp(LayerMerger, FrontLayer, saturate(Layer3Mask * 5));
OutColor.rgb = LayerMerger;
OutColor.a = 0;
}