2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
PostProcessing . cpp : The center for all post processing activities .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "RendererPrivate.h"
# include "ScenePrivate.h"
# include "PostProcessing.h"
# include "PostProcessAA.h"
# include "PostProcessTonemap.h"
# include "PostProcessMaterial.h"
# include "PostProcessInput.h"
# include "PostProcessWeightedSampleSum.h"
# include "PostProcessBloomSetup.h"
# include "PostProcessMobile.h"
# include "PostProcessDownsample.h"
# include "PostProcessHistogram.h"
# include "PostProcessHistogramReduce.h"
# include "PostProcessVisualizeHDR.h"
# include "PostProcessSelectionOutline.h"
# include "PostProcessGBufferHints.h"
# include "PostProcessVisualizeBuffer.h"
# include "PostProcessEyeAdaptation.h"
# include "PostProcessLensFlares.h"
# include "PostProcessLensBlur.h"
# include "PostProcessBokehDOF.h"
# include "PostProcessBokehDOFRecombine.h"
# include "PostProcessCombineLUTs.h"
# include "BatchedElements.h"
# include "ScreenRendering.h"
# include "PostProcessTemporalAA.h"
# include "PostProcessMotionBlur.h"
# include "PostProcessDOF.h"
# include "PostProcessUpscale.h"
# include "PostProcessHMD.h"
# include "PostProcessVisualizeComplexity.h"
# include "PostProcessCompositeEditorPrimitives.h"
# include "PostProcessPassThrough.h"
# include "PostProcessAmbientOcclusion.h"
# include "ScreenSpaceReflections.h"
# include "PostProcessTestImage.h"
# include "HighResScreenshot.h"
2014-08-22 14:15:05 -04:00
# include "PostProcessSubsurface.h"
2014-04-23 17:31:09 -04:00
# include "PostProcessMorpheus.h"
2014-04-23 17:32:55 -04:00
# include "IHeadMountedDisplay.h"
2014-08-21 06:03:00 -04:00
# include "BufferVisualizationData.h"
2014-04-23 17:31:09 -04:00
2014-03-14 14:13:41 -04:00
/** The global center for all post processing activities. */
FPostProcessing GPostProcessing ;
2014-09-18 17:49:40 -04:00
static TAutoConsoleVariable < int32 > CVarUseMobileBloom (
TEXT ( " r.UseMobileBloom " ) ,
0 ,
TEXT ( " HACK: Set to 1 to use mobile bloom. " ) ,
ECVF_Scalability | ECVF_RenderThreadSafe ) ;
static TAutoConsoleVariable < float > CVarDepthOfFieldMaxSize (
TEXT ( " r.DepthOfField.MaxSize " ) ,
100.0f ,
TEXT ( " Allows to clamp the gaussian depth of field radius (for better performance), default: 100 " ) ,
ECVF_Scalability | ECVF_RenderThreadSafe ) ;
2014-03-14 14:13:41 -04:00
static TAutoConsoleVariable < int32 > CVarRenderTargetSwitchWorkaround (
TEXT ( " r.RenderTargetSwitchWorkaround " ) ,
0 ,
TEXT ( " Workaround needed on some mobile platforms to avoid a performance drop related to switching render targets. \n " )
TEXT ( " Only enabled on some hardware. This affects the bloom quality a bit. It runs slower than the normal code path but \n " )
TEXT ( " still faster as it avoids the many render target switches. (Default: 0) \n " )
TEXT ( " We want this enabled (1) on all 32 bit iOS devices (implemented through DeviceProfiles). " ) ,
ECVF_RenderThreadSafe ) ;
2014-11-03 16:17:18 -05:00
static TAutoConsoleVariable < float > CVarUpscaleCylinder (
TEXT ( " r.Upscale.Cylinder " ) ,
0 ,
TEXT ( " Allows to apply a cylindrical distortion to the rendered image. Values between 0 and 1 allow to fade the effect (lerp). \n " )
TEXT ( " There is a quality loss that can be compensated by adjusting r.ScreenPercentage (>100). \n " )
TEXT ( " 0: off(default) \n " )
TEXT ( " >0: enabled (requires an extra post processing pass if upsampling wasn't used - see r.ScreenPercentage) \n " )
TEXT ( " 1: full effect " ) ,
ECVF_RenderThreadSafe ) ;
static TAutoConsoleVariable < int32 > CVarUpscaleQuality (
TEXT ( " r.Upscale.Quality " ) ,
2014-06-25 05:47:33 -04:00
3 ,
TEXT ( " 0: Nearest filtering \n " )
TEXT ( " 1: Simple Bilinear \n " )
TEXT ( " 2: 4 tap bilinear \n " )
TEXT ( " 3: Directional blur with unsharp mask upsample. (default) " ) ,
ECVF_Scalability | ECVF_RenderThreadSafe ) ;
static TAutoConsoleVariable < float > CVarMotionBlurSoftEdgeSize (
TEXT ( " r.MotionBlurSoftEdgeSize " ) ,
1.0f ,
2014-10-24 11:35:45 -04:00
TEXT ( " Defines how wide the object motion blur is blurred (percent of screen width) to allow soft edge motion blur. \n " )
2014-06-25 05:47:33 -04:00
TEXT ( " This scales linearly with the size (up to a maximum of 32 samples, 2.5 is about 18 samples) and with screen resolution \n " )
TEXT ( " Smaller values are better for performance and provide more accurate motion vectors but the blurring outside the object is reduced. \n " )
TEXT ( " If needed this can be exposed like the other motionblur settings. \n " )
TEXT ( " 0:off (not free and does never completely disable), >0, 1.0 (default) " ) ,
ECVF_RenderThreadSafe ) ;
2015-01-12 20:35:04 -05:00
static TAutoConsoleVariable < float > CVarBloomCross (
TEXT ( " r.Bloom.Cross " ) ,
0.0f ,
TEXT ( " Experimental feature to give bloom kernel a more bright center sample (values between 1 and 3 work without causing aliasing) \n " )
TEXT ( " Existing bloom get lowered to match the same brightness \n " )
TEXT ( " <0 for a anisomorphic lens flare look (X only) \n " )
TEXT ( " 0 off (default) \n " )
TEXT ( " >0 for a cross look (X and Y) " ) ,
ECVF_RenderThreadSafe ) ;
2014-03-14 14:13:41 -04:00
IMPLEMENT_SHADER_TYPE ( , FPostProcessVS , TEXT ( " PostProcessBloom " ) , TEXT ( " MainPostprocessCommonVS " ) , SF_Vertex ) ;
// -------------------------------------------------------
FPostprocessContext : : FPostprocessContext ( class FRenderingCompositionGraph & InGraph , const FViewInfo & InView )
: Graph ( InGraph )
, View ( InView )
2014-10-24 11:35:45 -04:00
, SceneColor ( 0 )
, SceneDepth ( 0 )
2014-03-14 14:13:41 -04:00
{
2014-10-24 11:35:45 -04:00
if ( GSceneRenderTargets . IsSceneColorAllocated ( ) )
{
SceneColor = Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSceneRenderTargets . GetSceneColor ( ) ) ) ;
}
2014-03-14 14:13:41 -04:00
SceneDepth = Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSceneRenderTargets . SceneDepthZ ) ) ;
FinalOutput = FRenderingCompositeOutputRef ( SceneColor ) ;
}
static FRenderingCompositeOutputRef RenderHalfResBloomThreshold ( FPostprocessContext & Context , FRenderingCompositeOutputRef SceneColorHalfRes , FRenderingCompositeOutputRef EyeAdaptation )
{
// todo: optimize later, the missing node causes some wrong behavior
// if(Context.View.FinalPostProcessSettings.BloomIntensity <= 0.0f)
// {
// // this pass is not required
// return FRenderingCompositeOutputRef();
// }
// bloom threshold
FRenderingCompositePass * PostProcessBloomSetup = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomSetup ( ) ) ;
PostProcessBloomSetup - > SetInput ( ePId_Input0 , SceneColorHalfRes ) ;
PostProcessBloomSetup - > SetInput ( ePId_Input1 , EyeAdaptation ) ;
return FRenderingCompositeOutputRef ( PostProcessBloomSetup ) ;
}
// 2 pass Gaussian blur using uni-linear filtering
2015-01-12 20:35:04 -05:00
// @param CrossCenterWeight see r.Bloom.Cross (positive for X and Y, otherwise for X only)
2014-03-14 14:13:41 -04:00
static FRenderingCompositeOutputRef RenderGaussianBlur (
FPostprocessContext & Context ,
const TCHAR * DebugNameX ,
const TCHAR * DebugNameY ,
const FRenderingCompositeOutputRef & Input ,
float SizeScale ,
FLinearColor Tint = FLinearColor : : White ,
2015-01-12 20:35:04 -05:00
const FRenderingCompositeOutputRef Additive = FRenderingCompositeOutputRef ( ) ,
float CrossCenterWeight = 0.0f )
2014-03-14 14:13:41 -04:00
{
// Gaussian blur in x
2014-09-10 12:31:36 -04:00
FRCPassPostProcessWeightedSampleSum * PostProcessBlurX = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessWeightedSampleSum ( EFS_Horiz , EFCM_Weighted , SizeScale , DebugNameX ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessBlurX - > SetInput ( ePId_Input0 , Input ) ;
2015-01-12 20:35:04 -05:00
if ( CrossCenterWeight > 0 )
{
PostProcessBlurX - > SetCrossCenterWeight ( CrossCenterWeight ) ;
}
2014-03-14 14:13:41 -04:00
// Gaussian blur in y
2014-09-10 12:31:36 -04:00
FRCPassPostProcessWeightedSampleSum * PostProcessBlurY = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessWeightedSampleSum ( EFS_Vert , EFCM_Weighted , SizeScale , DebugNameY , Tint ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessBlurY - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( PostProcessBlurX ) ) ;
PostProcessBlurY - > SetInput ( ePId_Input1 , Additive ) ;
2015-01-12 20:35:04 -05:00
PostProcessBlurY - > SetCrossCenterWeight ( FMath : : Abs ( CrossCenterWeight ) ) ;
2014-03-14 14:13:41 -04:00
return FRenderingCompositeOutputRef ( PostProcessBlurY ) ;
}
// render one bloom pass and add another optional texture to it
static FRenderingCompositeOutputRef RenderBloom (
FPostprocessContext & Context ,
const FRenderingCompositeOutputRef & PreviousBloom ,
float Size ,
FLinearColor Tint = FLinearColor : : White ,
const FRenderingCompositeOutputRef Additive = FRenderingCompositeOutputRef ( ) )
{
2015-01-12 20:35:04 -05:00
const float CrossBloom = CVarBloomCross . GetValueOnRenderThread ( ) ;
return RenderGaussianBlur ( Context , TEXT ( " BloomBlurX " ) , TEXT ( " BloomBlurY " ) , PreviousBloom , Size , Tint , Additive , CrossBloom ) ;
2014-03-14 14:13:41 -04:00
}
static void AddTonemapper (
FPostprocessContext & Context ,
const FRenderingCompositeOutputRef & BloomOutputCombined ,
2014-09-03 18:16:55 -04:00
const FRenderingCompositeOutputRef & EyeAdaptation )
2014-03-14 14:13:41 -04:00
{
2015-04-28 15:27:19 -04:00
FRenderingCompositePass * CombinedLUT = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCombineLUTs ( Context . View . GetShaderPlatform ( ) ) ) ;
2014-09-03 18:16:55 -04:00
FRCPassPostProcessTonemap * PostProcessTonemap = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessTonemap ( Context . View ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessTonemap - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
PostProcessTonemap - > SetInput ( ePId_Input1 , BloomOutputCombined ) ;
PostProcessTonemap - > SetInput ( ePId_Input2 , EyeAdaptation ) ;
2015-04-28 15:27:19 -04:00
PostProcessTonemap - > SetInput ( ePId_Input3 , CombinedLUT ) ;
2014-03-14 14:13:41 -04:00
Context . FinalOutput = FRenderingCompositeOutputRef ( PostProcessTonemap ) ;
}
static void AddSelectionOutline ( FPostprocessContext & Context )
{
FRenderingCompositePass * SelectionColorPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSelectionOutlineColor ( ) ) ;
SelectionColorPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSelectionOutline ( ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Node - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( FRenderingCompositeOutputRef ( SelectionColorPass ) ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
static void AddGammaOnlyTonemapper ( FPostprocessContext & Context )
{
2014-09-03 18:16:55 -04:00
FRenderingCompositePass * PostProcessTonemap = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessTonemap ( Context . View , true ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessTonemap - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( PostProcessTonemap ) ;
}
static void AddPostProcessAA ( FPostprocessContext & Context )
{
// console variable override
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.PostProcessAAQuality " ) ) ;
uint32 Quality = FMath : : Clamp ( CVar - > GetValueOnRenderThread ( ) , 1 , 6 ) ;
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessAA ( Quality ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
static FRenderingCompositeOutputRef AddPostProcessEyeAdaptation ( FPostprocessContext & Context , FRenderingCompositeOutputRef & Histogram )
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessEyeAdaptation ( ) ) ;
Node - > SetInput ( ePId_Input0 , Histogram ) ;
return FRenderingCompositeOutputRef ( Node ) ;
}
2015-01-25 14:54:46 -05:00
static void AddVisualizeBloomSetup ( FPostprocessContext & Context )
{
2015-01-25 16:45:04 -05:00
auto Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeBloomSetup ( ) ) ;
2015-01-25 14:54:46 -05:00
Node - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2015-01-25 16:45:04 -05:00
static void AddVisualizeBloomOverlay ( FPostprocessContext & Context , FRenderingCompositeOutputRef & HDRColor , FRenderingCompositeOutputRef & BloomOutputCombined )
{
auto Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeBloomOverlay ( ) ) ;
Node - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Node - > SetInput ( ePId_Input1 , HDRColor ) ;
Node - > SetInput ( ePId_Input2 , BloomOutputCombined ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2015-02-18 14:37:44 -05:00
static void AddPostProcessDepthOfFieldBokeh ( FPostprocessContext & Context , FRenderingCompositeOutputRef & SeparateTranslucency , FRenderingCompositeOutputRef & VelocityInput )
2014-03-14 14:13:41 -04:00
{
// downsample, mask out the in focus part, depth in alpha
FRenderingCompositePass * DOFSetup = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBokehDOFSetup ( ) ) ;
DOFSetup - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
DOFSetup - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . SceneDepth ) ) ;
FSceneViewState * ViewState = ( FSceneViewState * ) Context . View . State ;
FRenderingCompositePass * DOFInputPass = DOFSetup ;
if ( Context . View . FinalPostProcessSettings . AntiAliasingMethod = = AAM_TemporalAA & & ViewState )
{
FRenderingCompositePass * HistoryInput ;
if ( ViewState - > DOFHistoryRT & & ViewState - > bBokehDOFHistory & & ! Context . View . bCameraCut )
{
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > DOFHistoryRT ) ) ;
}
else
{
// No history so use current as history
HistoryInput = DOFSetup ;
}
FRenderingCompositePass * NodeTemporalAA = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFTemporalAA ) ;
NodeTemporalAA - > SetInput ( ePId_Input0 , DOFSetup ) ;
NodeTemporalAA - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
NodeTemporalAA - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
2015-02-18 14:37:44 -05:00
NodeTemporalAA - > SetInput ( ePId_Input3 , VelocityInput ) ;
2014-03-14 14:13:41 -04:00
DOFInputPass = NodeTemporalAA ;
ViewState - > bBokehDOFHistory = true ;
}
FRenderingCompositePass * NodeBlurred = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBokehDOF ( ) ) ;
NodeBlurred - > SetInput ( ePId_Input0 , DOFInputPass ) ;
NodeBlurred - > SetInput ( ePId_Input1 , Context . SceneColor ) ;
NodeBlurred - > SetInput ( ePId_Input2 , Context . SceneDepth ) ;
FRenderingCompositePass * NodeRecombined = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBokehDOFRecombine ( ) ) ;
NodeRecombined - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
NodeRecombined - > SetInput ( ePId_Input1 , NodeBlurred ) ;
NodeRecombined - > SetInput ( ePId_Input2 , SeparateTranslucency ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( NodeRecombined ) ;
}
2015-02-18 14:37:44 -05:00
static void AddPostProcessDepthOfFieldGaussian ( FPostprocessContext & Context , FDepthOfFieldStats & Out , FRenderingCompositeOutputRef & VelocityInput )
2014-03-14 14:13:41 -04:00
{
float FarSize = Context . View . FinalPostProcessSettings . DepthOfFieldFarBlurSize ;
float NearSize = Context . View . FinalPostProcessSettings . DepthOfFieldNearBlurSize ;
2014-09-18 17:49:40 -04:00
float MaxSize = CVarDepthOfFieldMaxSize . GetValueOnRenderThread ( ) ;
2014-03-14 14:13:41 -04:00
2014-09-18 17:49:40 -04:00
FarSize = FMath : : Min ( FarSize , MaxSize ) ;
NearSize = FMath : : Min ( NearSize , MaxSize ) ;
Out . bFar = FarSize > = 0.01f ;
Out . bNear = NearSize > = GetCachedScalabilityCVars ( ) . GaussianDOFNearThreshold ;
if ( ! Out . bFar & & ! Out . bNear )
2014-03-14 14:13:41 -04:00
{
return ;
}
if ( Context . View . Family - > EngineShowFlags . VisualizeDOF )
{
// no need for this pass
return ;
}
2014-09-18 17:49:40 -04:00
FRenderingCompositePass * DOFSetup = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFSetup ( Out . bNear ) ) ;
2014-03-14 14:13:41 -04:00
DOFSetup - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
// We need the depth to create the near and far mask
DOFSetup - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . SceneDepth ) ) ;
FSceneViewState * ViewState = ( FSceneViewState * ) Context . View . State ;
FRenderingCompositePass * DOFInputPass = DOFSetup ;
if ( Context . View . FinalPostProcessSettings . AntiAliasingMethod = = AAM_TemporalAA & & ViewState )
{
FRenderingCompositePass * HistoryInput ;
if ( ViewState - > DOFHistoryRT & & ! ViewState - > bBokehDOFHistory & & ! Context . View . bCameraCut )
{
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > DOFHistoryRT ) ) ;
}
else
{
// No history so use current as history
HistoryInput = DOFSetup ;
}
FRenderingCompositePass * NodeTemporalAA = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFTemporalAA ) ;
NodeTemporalAA - > SetInput ( ePId_Input0 , DOFSetup ) ;
NodeTemporalAA - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
NodeTemporalAA - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
2015-02-18 14:37:44 -05:00
NodeTemporalAA - > SetInput ( ePId_Input3 , VelocityInput ) ;
2014-03-14 14:13:41 -04:00
DOFInputPass = NodeTemporalAA ;
ViewState - > bBokehDOFHistory = false ;
}
2014-11-03 11:26:08 -05:00
FRenderingCompositePass * DOFInputPass2 = DOFSetup ;
EPassOutputId DOFInputPassId = ePId_Output1 ;
if ( Context . View . FinalPostProcessSettings . AntiAliasingMethod = = AAM_TemporalAA & & ViewState )
{
FRenderingCompositePass * HistoryInput ;
EPassOutputId DOFInputPassId2 = ePId_Output1 ;
if ( ViewState - > DOFHistoryRT2 & & ! ViewState - > bBokehDOFHistory2 & & ! Context . View . bCameraCut )
{
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > DOFHistoryRT2 ) ) ;
DOFInputPassId2 = ePId_Output0 ;
}
else
{
// No history so use current as history
HistoryInput = DOFSetup ;
DOFInputPassId2 = ePId_Output1 ;
}
FRenderingCompositePass * NodeTemporalAA = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFTemporalAANear ) ;
NodeTemporalAA - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( DOFSetup , ePId_Output1 ) ) ;
NodeTemporalAA - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( HistoryInput , DOFInputPassId2 ) ) ;
NodeTemporalAA - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( HistoryInput , DOFInputPassId2 ) ) ;
2015-02-18 14:37:44 -05:00
NodeTemporalAA - > SetInput ( ePId_Input3 , VelocityInput ) ;
2014-11-03 11:26:08 -05:00
DOFInputPass2 = NodeTemporalAA ;
ViewState - > bBokehDOFHistory2 = false ;
DOFInputPassId = ePId_Output0 ;
}
2014-03-14 14:13:41 -04:00
FRenderingCompositeOutputRef Far ( DOFInputPass , ePId_Output0 ) ;
FRenderingCompositeOutputRef Near ; // Don't need to bind a dummy here as we use a different permutation which doesn't read from this input when near DOF is disabled
// far
2014-09-18 17:49:40 -04:00
if ( Out . bFar )
2014-03-14 14:13:41 -04:00
{
2014-09-10 12:31:36 -04:00
Far = RenderGaussianBlur ( Context , TEXT ( " FarDOFBlurX " ) , TEXT ( " FarDOFBlurY " ) , FRenderingCompositeOutputRef ( DOFInputPass , ePId_Output0 ) , FarSize ) ;
2014-03-14 14:13:41 -04:00
}
// near
2014-09-18 17:49:40 -04:00
if ( Out . bNear )
2014-03-14 14:13:41 -04:00
{
2014-11-03 11:26:08 -05:00
Near = RenderGaussianBlur ( Context , TEXT ( " NearDOFBlurX " ) , TEXT ( " NearDOFBlurY " ) , FRenderingCompositeOutputRef ( DOFInputPass2 , DOFInputPassId ) , NearSize ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-18 17:49:40 -04:00
FRenderingCompositePass * NodeRecombined = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFRecombine ( Out . bNear ) ) ;
2014-03-14 14:13:41 -04:00
NodeRecombined - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
NodeRecombined - > SetInput ( ePId_Input1 , Far ) ;
NodeRecombined - > SetInput ( ePId_Input2 , Near ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( NodeRecombined ) ;
}
2015-02-18 14:37:44 -05:00
static void AddPostProcessDepthOfFieldCircle ( FPostprocessContext & Context , FDepthOfFieldStats & Out , FRenderingCompositeOutputRef & VelocityInput )
2015-01-27 17:42:51 -05:00
{
if ( Context . View . Family - > EngineShowFlags . VisualizeDOF )
{
// no need for this pass
return ;
}
2015-02-06 17:14:45 -05:00
FRenderingCompositePass * DOFSetup = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCircleDOFSetup ( false ) ) ;
2015-01-27 17:42:51 -05:00
DOFSetup - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
DOFSetup - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . SceneDepth ) ) ;
FSceneViewState * ViewState = ( FSceneViewState * ) Context . View . State ;
FRenderingCompositePass * DOFInputPass = DOFSetup ;
if ( Context . View . FinalPostProcessSettings . AntiAliasingMethod = = AAM_TemporalAA & & ViewState )
{
FRenderingCompositePass * HistoryInput ;
if ( ViewState - > DOFHistoryRT & & ! ViewState - > bBokehDOFHistory & & ! Context . View . bCameraCut )
{
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > DOFHistoryRT ) ) ;
}
else
{
// No history so use current as history
HistoryInput = DOFSetup ;
}
FRenderingCompositePass * NodeTemporalAA = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDOFTemporalAA ) ;
NodeTemporalAA - > SetInput ( ePId_Input0 , DOFSetup ) ;
NodeTemporalAA - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
NodeTemporalAA - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
2015-02-18 14:37:44 -05:00
NodeTemporalAA - > SetInput ( ePId_Input3 , VelocityInput ) ;
2015-01-27 17:42:51 -05:00
DOFInputPass = NodeTemporalAA ;
ViewState - > bBokehDOFHistory = false ;
}
FRenderingCompositeOutputRef Far ;
FRenderingCompositeOutputRef Near ;
2015-02-06 17:14:45 -05:00
FRenderingCompositePass * DOFNear = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCircleDOFDilate ( ) ) ;
DOFNear - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( DOFInputPass , ePId_Output0 ) ) ;
Near = FRenderingCompositeOutputRef ( DOFNear , ePId_Output0 ) ;
2015-01-27 17:42:51 -05:00
2015-02-06 17:14:45 -05:00
FRenderingCompositePass * DOFApply = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCircleDOF ( false ) ) ;
DOFApply - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( DOFInputPass , ePId_Output0 ) ) ;
DOFApply - > SetInput ( ePId_Input1 , Near ) ;
Far = FRenderingCompositeOutputRef ( DOFApply , ePId_Output0 ) ;
FRenderingCompositePass * NodeRecombined = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCircleDOFRecombine ( false ) ) ;
2015-01-27 17:42:51 -05:00
NodeRecombined - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
NodeRecombined - > SetInput ( ePId_Input1 , Far ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( NodeRecombined ) ;
}
2014-03-14 14:13:41 -04:00
static FRenderingCompositeOutputRef AddBloom ( FPostprocessContext Context , FRenderingCompositeOutputRef PostProcessDownsample0 )
{
// Quality level to bloom stages table. Note: 0 is omitted, ensure element count tallys with the range documented with 'r.BloomQuality' definition.
const static uint32 BloomQualityStages [ ] =
{
3 , // Q1
3 , // Q2
4 , // Q3
2015-01-26 18:20:53 -05:00
5 , // Q4
6 , // Q5
2014-03-14 14:13:41 -04:00
} ;
int32 BloomQuality ;
{
// console variable override
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.BloomQuality " ) ) ;
BloomQuality = FMath : : Clamp ( CVar - > GetValueOnRenderThread ( ) , 0 , ( int32 ) ARRAY_COUNT ( BloomQualityStages ) ) ;
}
// Perform down sample. Used by both bloom and lens flares.
2015-01-26 18:20:53 -05:00
static const int32 DownSampleStages = 6 ;
2014-03-14 14:13:41 -04:00
FRenderingCompositeOutputRef PostProcessDownsamples [ DownSampleStages ] = { PostProcessDownsample0 } ;
for ( int i = 1 ; i < DownSampleStages ; i + + )
{
static const TCHAR * PassLabels [ ] =
2015-01-26 18:20:53 -05:00
{ NULL , TEXT ( " BloomDownsample1 " ) , TEXT ( " BloomDownsample2 " ) , TEXT ( " BloomDownsample3 " ) , TEXT ( " BloomDownsample4 " ) , TEXT ( " BloomDownsample5 " ) } ;
2014-06-16 08:04:54 -04:00
static_assert ( ARRAY_COUNT ( PassLabels ) = = DownSampleStages , " PassLabel count must be equal to DownSampleStages. " ) ;
2014-09-10 12:31:36 -04:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDownsample ( PF_Unknown , 1 , PassLabels [ i ] ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , PostProcessDownsamples [ i - 1 ] ) ;
PostProcessDownsamples [ i ] = FRenderingCompositeOutputRef ( Pass ) ;
}
2015-01-27 11:57:06 -05:00
const bool bVisualizeBloom = Context . View . Family - > EngineShowFlags . VisualizeBloom ;
2014-03-14 14:13:41 -04:00
FRenderingCompositeOutputRef BloomOutput ;
if ( BloomQuality = = 0 )
{
// No bloom, provide substitute source for lens flare.
BloomOutput = PostProcessDownsamples [ 0 ] ;
}
else
{
// Perform bloom blur + accumulate.
struct FBloomStage
{
float BloomSize ;
const FLinearColor * Tint ;
} ;
const FFinalPostProcessSettings & Settings = Context . View . FinalPostProcessSettings ;
2015-01-26 17:53:20 -05:00
2014-03-14 14:13:41 -04:00
FBloomStage BloomStages [ ] =
{
2015-01-26 18:20:53 -05:00
{ Settings . Bloom6Size , & Settings . Bloom6Tint } ,
2014-03-14 14:13:41 -04:00
{ Settings . Bloom5Size , & Settings . Bloom5Tint } ,
{ Settings . Bloom4Size , & Settings . Bloom4Tint } ,
{ Settings . Bloom3Size , & Settings . Bloom3Tint } ,
{ Settings . Bloom2Size , & Settings . Bloom2Tint } ,
{ Settings . Bloom1Size , & Settings . Bloom1Tint } ,
} ;
static const uint32 NumBloomStages = ARRAY_COUNT ( BloomStages ) ;
const uint32 BloomStageCount = BloomQualityStages [ BloomQuality - 1 ] ;
check ( BloomStageCount < = NumBloomStages ) ;
float TintScale = 1.0f / NumBloomStages ;
for ( uint32 i = 0 , SourceIndex = NumBloomStages - 1 ; i < BloomStageCount ; i + + , SourceIndex - - )
{
FBloomStage & Op = BloomStages [ i ] ;
2015-01-26 17:53:20 -05:00
FLinearColor Tint = ( * Op . Tint ) * TintScale ;
if ( bVisualizeBloom )
{
float LumScale = Tint . ComputeLuminance ( ) ;
// R is used to pass down the reference, G is the emulated bloom
Tint . R = 0 ;
Tint . G = LumScale ;
Tint . B = 0 ;
}
BloomOutput = RenderBloom ( Context , PostProcessDownsamples [ SourceIndex ] , Op . BloomSize * Settings . BloomSizeScale , Tint , BloomOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
// Lens Flares
FLinearColor LensFlareHDRColor = Context . View . FinalPostProcessSettings . LensFlareTint * Context . View . FinalPostProcessSettings . LensFlareIntensity ;
static const int32 MaxLensFlareQuality = 3 ;
int32 LensFlareQuality ;
{
// console variable override
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.LensFlareQuality " ) ) ;
LensFlareQuality = FMath : : Clamp ( CVar - > GetValueOnRenderThread ( ) , 0 , MaxLensFlareQuality ) ;
}
2015-01-27 11:57:06 -05:00
if ( ! LensFlareHDRColor . IsAlmostBlack ( ) & & LensFlareQuality > 0 & & ! bVisualizeBloom )
2014-03-14 14:13:41 -04:00
{
float PercentKernelSize = Context . View . FinalPostProcessSettings . LensFlareBokehSize ;
bool bLensBlur = PercentKernelSize > 0.3f ;
FRenderingCompositePass * PostProcessFlares = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessLensFlares ( bLensBlur ? 2.0f : 1.0f ) ) ;
PostProcessFlares - > SetInput ( ePId_Input0 , BloomOutput ) ;
FRenderingCompositeOutputRef LensFlareInput = PostProcessDownsamples [ MaxLensFlareQuality - LensFlareQuality ] ;
if ( bLensBlur )
{
float Threshold = Context . View . FinalPostProcessSettings . LensFlareThreshold ;
FRenderingCompositePass * PostProcessLensBlur = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessLensBlur ( PercentKernelSize , Threshold ) ) ;
PostProcessLensBlur - > SetInput ( ePId_Input0 , LensFlareInput ) ;
PostProcessFlares - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( PostProcessLensBlur ) ) ;
}
else
{
// fast: no blurring or blurring shared from bloom
PostProcessFlares - > SetInput ( ePId_Input1 , LensFlareInput ) ;
}
BloomOutput = FRenderingCompositeOutputRef ( PostProcessFlares ) ;
}
return BloomOutput ;
}
static void AddTemporalAA ( FPostprocessContext & Context , FRenderingCompositeOutputRef & VelocityInput )
{
check ( VelocityInput . IsValid ( ) ) ;
FSceneViewState * ViewState = ( FSceneViewState * ) Context . View . State ;
FRenderingCompositePass * HistoryInput ;
if ( ViewState & & ViewState - > TemporalAAHistoryRT & & ! Context . View . bCameraCut )
{
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > TemporalAAHistoryRT ) ) ;
}
else
{
// No history so use current as history
2014-05-06 11:27:50 -04:00
HistoryInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSceneRenderTargets . GetSceneColor ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
FRenderingCompositePass * TemporalAAPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessTemporalAA ) ;
TemporalAAPass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
TemporalAAPass - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
TemporalAAPass - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( HistoryInput ) ) ;
TemporalAAPass - > SetInput ( ePId_Input3 , VelocityInput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( TemporalAAPass ) ;
}
FPostProcessMaterialNode * IteratePostProcessMaterialNodes ( const FFinalPostProcessSettings & Dest , EBlendableLocation InLocation , FBlendableEntry * & Iterator )
{
for ( ; ; )
{
FPostProcessMaterialNode * DataPtr = Dest . BlendableManager . IterateBlendables < FPostProcessMaterialNode > ( Iterator ) ;
2014-09-09 18:35:58 -04:00
if ( ! DataPtr | | DataPtr - > GetLocation ( ) = = InLocation )
2014-03-14 14:13:41 -04:00
{
return DataPtr ;
}
}
}
2014-09-26 15:22:35 -04:00
static FRenderingCompositePass * AddSinglePostProcessMaterial ( FPostprocessContext & Context , EBlendableLocation InLocation )
{
if ( ! Context . View . Family - > EngineShowFlags . PostProcessing | | ! Context . View . Family - > EngineShowFlags . PostProcessMaterial )
{
return 0 ;
}
FBlendableEntry * Iterator = 0 ;
FPostProcessMaterialNode PPNode ;
while ( FPostProcessMaterialNode * Data = IteratePostProcessMaterialNodes ( Context . View . FinalPostProcessSettings , InLocation , Iterator ) )
{
check ( Data - > GetMaterialInterface ( ) ) ;
if ( PPNode . IsValid ( ) )
{
FPostProcessMaterialNode : : FCompare Dummy ;
// take the one with the highest priority
if ( ! Dummy . operator ( ) ( PPNode , * Data ) )
{
continue ;
}
}
PPNode = * Data ;
}
if ( UMaterialInterface * MaterialInterface = PPNode . GetMaterialInterface ( ) )
{
FMaterialRenderProxy * Proxy = MaterialInterface - > GetRenderProxy ( false ) ;
check ( Proxy ) ;
const FMaterial * Material = Proxy - > GetMaterial ( Context . View . GetFeatureLevel ( ) ) ;
check ( Material ) ;
if ( Material - > NeedsGBuffer ( ) )
{
// AdjustGBufferRefCount(-1) call is done when the pass gets executed
GSceneRenderTargets . AdjustGBufferRefCount ( 1 ) ;
}
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( MaterialInterface , Context . View . GetFeatureLevel ( ) ) ) ;
2014-09-26 15:22:35 -04:00
return Node ;
}
return 0 ;
}
2014-03-14 14:13:41 -04:00
static void AddPostProcessMaterial ( FPostprocessContext & Context , EBlendableLocation InLocation , FRenderingCompositeOutputRef SeparateTranslucency )
{
if ( ! Context . View . Family - > EngineShowFlags . PostProcessing | | ! Context . View . Family - > EngineShowFlags . PostProcessMaterial )
{
return ;
}
2014-09-09 18:35:58 -04:00
// hard coded - this should be a reasonable limit
2014-03-14 14:13:41 -04:00
const uint32 MAX_PPMATERIALNODES = 10 ;
2014-09-09 18:35:58 -04:00
FBlendableEntry * Iterator = 0 ;
FPostProcessMaterialNode PPNodes [ MAX_PPMATERIALNODES ] ;
2014-03-14 14:13:41 -04:00
uint32 PPNodeCount = 0 ;
2014-09-09 18:35:58 -04:00
if ( Context . View . Family - > EngineShowFlags . VisualizeBuffer )
{
// Apply requested material to the full screen
UMaterial * Material = GetBufferVisualizationData ( ) . GetMaterial ( Context . View . CurrentBufferVisualizationMode ) ;
if ( Material & & Material - > BlendableLocation = = InLocation )
{
PPNodes [ 0 ] = FPostProcessMaterialNode ( Material , InLocation , Material - > BlendablePriority ) ;
+ + PPNodeCount ;
}
}
2014-03-14 14:13:41 -04:00
for ( ; PPNodeCount < MAX_PPMATERIALNODES ; + + PPNodeCount )
{
FPostProcessMaterialNode * Data = IteratePostProcessMaterialNodes ( Context . View . FinalPostProcessSettings , InLocation , Iterator ) ;
if ( ! Data )
{
break ;
}
2014-09-09 18:35:58 -04:00
check ( Data - > GetMaterialInterface ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-09-09 18:35:58 -04:00
PPNodes [ PPNodeCount ] = * Data ;
2014-03-14 14:13:41 -04:00
}
2014-09-09 18:35:58 -04:00
: : Sort ( PPNodes , PPNodeCount , FPostProcessMaterialNode : : FCompare ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-30 11:04:47 -04:00
ERHIFeatureLevel : : Type FeatureLevel = Context . View . GetFeatureLevel ( ) ;
2014-03-14 14:13:41 -04:00
for ( uint32 i = 0 ; i < PPNodeCount ; + + i )
{
2014-09-09 18:35:58 -04:00
UMaterialInterface * MaterialInterface = PPNodes [ i ] . GetMaterialInterface ( ) ;
2014-05-16 17:29:16 -04:00
FMaterialRenderProxy * Proxy = MaterialInterface - > GetRenderProxy ( false ) ;
check ( Proxy ) ;
const FMaterial * Material = Proxy - > GetMaterial ( Context . View . GetFeatureLevel ( ) ) ;
check ( Material ) ;
if ( Material - > NeedsGBuffer ( ) )
{
// AdjustGBufferRefCount(-1) call is done when the pass gets executed
GSceneRenderTargets . AdjustGBufferRefCount ( 1 ) ;
}
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( MaterialInterface , FeatureLevel ) ) ;
2014-03-14 14:13:41 -04:00
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
// We are binding separate translucency here because the post process SceneTexture node can reference
// the separate translucency buffers through ePId_Input1.
// TODO: Check if material actually uses this texture and only bind if needed.
Node - > SetInput ( ePId_Input1 , SeparateTranslucency ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
}
static void AddHighResScreenshotMask ( FPostprocessContext & Context , FRenderingCompositeOutputRef & SeparateTranslucencyInput )
{
if ( Context . View . Family - > EngineShowFlags . HighResScreenshotMask ! = 0 )
{
check ( Context . View . FinalPostProcessSettings . HighResScreenshotMaterial ) ;
FRenderingCompositeOutputRef Input = Context . FinalOutput ;
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * CompositePass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( Context . View . FinalPostProcessSettings . HighResScreenshotMaterial , Context . View . GetFeatureLevel ( ) ) ) ;
2014-03-14 14:13:41 -04:00
CompositePass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Input ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( CompositePass ) ;
if ( GIsHighResScreenshot )
{
check ( Context . View . FinalPostProcessSettings . HighResScreenshotMaskMaterial ) ;
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * MaskPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( Context . View . FinalPostProcessSettings . HighResScreenshotMaskMaterial , Context . View . GetFeatureLevel ( ) ) ) ;
2014-03-14 14:13:41 -04:00
MaskPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Input ) ) ;
CompositePass - > AddDependency ( MaskPass ) ;
FString BaseFilename = FString ( Context . View . FinalPostProcessSettings . BufferVisualizationDumpBaseFilename ) ;
MaskPass - > SetOutputColorArray ( ePId_Output0 , FScreenshotRequest : : GetHighresScreenshotMaskColorArray ( ) ) ;
}
}
// Draw the capture region if a material was supplied
if ( Context . View . FinalPostProcessSettings . HighResScreenshotCaptureRegionMaterial )
{
2014-11-13 04:51:52 -05:00
auto Material = Context . View . FinalPostProcessSettings . HighResScreenshotCaptureRegionMaterial ;
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * CaptureRegionVisualizationPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( Material , Context . View . GetFeatureLevel ( ) ) ) ;
2014-03-14 14:13:41 -04:00
CaptureRegionVisualizationPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( CaptureRegionVisualizationPass ) ;
2014-11-13 04:51:52 -05:00
auto Proxy = Material - > GetRenderProxy ( false ) ;
const FMaterial * RendererMaterial = Proxy - > GetMaterial ( Context . View . GetFeatureLevel ( ) ) ;
if ( RendererMaterial - > NeedsGBuffer ( ) )
{
// AdjustGBufferRefCount(-1) call is done when the pass gets executed
GSceneRenderTargets . AdjustGBufferRefCount ( 1 ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-09-09 18:35:58 -04:00
static void AddGBufferVisualizationOverview ( FPostprocessContext & Context , FRenderingCompositeOutputRef & SeparateTranslucencyInput )
2014-03-14 14:13:41 -04:00
{
static const auto CVarDumpFrames = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.BufferVisualizationDumpFrames " ) ) ;
2014-08-12 08:36:24 -04:00
static const auto CVarDumpFramesAsHDR = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.BufferVisualizationDumpFramesAsHDR " ) ) ;
2014-03-14 14:13:41 -04:00
bool bVisualizationEnabled = Context . View . Family - > EngineShowFlags . VisualizeBuffer ;
bool bOverviewModeEnabled = bVisualizationEnabled & & ( Context . View . CurrentBufferVisualizationMode = = NAME_None ) ;
bool bHighResBufferVisualizationDumpRequried = GIsHighResScreenshot & & GetHighResScreenshotConfig ( ) . bDumpBufferVisualizationTargets ;
bool bDumpFrames = Context . View . FinalPostProcessSettings . bBufferVisualizationDumpRequired & & ( CVarDumpFrames - > GetValueOnRenderThread ( ) | | bHighResBufferVisualizationDumpRequried ) ;
2014-08-12 08:36:24 -04:00
bool bCaptureAsHDR = CVarDumpFramesAsHDR - > GetValueOnRenderThread ( ) | | GetHighResScreenshotConfig ( ) . bCaptureHDR ;
2014-03-14 14:13:41 -04:00
FString BaseFilename ;
if ( bDumpFrames )
{
BaseFilename = FString ( Context . View . FinalPostProcessSettings . BufferVisualizationDumpBaseFilename ) ;
}
if ( bDumpFrames | | bVisualizationEnabled )
{
FRenderingCompositeOutputRef IncomingStage = Context . FinalOutput ;
if ( bDumpFrames | | bOverviewModeEnabled )
{
FRenderingCompositePass * CompositePass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeBuffer ( ) ) ;
CompositePass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( IncomingStage ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( CompositePass ) ;
2014-08-12 08:36:24 -04:00
EPixelFormat OutputFormat = bCaptureAsHDR ? PF_FloatRGBA : PF_Unknown ;
2014-03-14 14:13:41 -04:00
// Loop over materials, creating stages for generation and downsampling of the tiles.
for ( TArray < UMaterialInterface * > : : TConstIterator It = Context . View . FinalPostProcessSettings . BufferVisualizationOverviewMaterials . CreateConstIterator ( ) ; It ; + + It )
{
2014-05-19 09:42:34 -04:00
auto MaterialInterface = * It ;
if ( MaterialInterface )
2014-03-14 14:13:41 -04:00
{
// Apply requested material
2015-03-30 11:04:47 -04:00
FRenderingCompositePass * MaterialPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMaterial ( * It , Context . View . GetFeatureLevel ( ) , OutputFormat ) ) ;
2014-03-14 14:13:41 -04:00
MaterialPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( IncomingStage ) ) ;
MaterialPass - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( SeparateTranslucencyInput ) ) ;
2014-05-19 09:42:34 -04:00
auto Proxy = MaterialInterface - > GetRenderProxy ( false ) ;
const FMaterial * Material = Proxy - > GetMaterial ( Context . View . GetFeatureLevel ( ) ) ;
if ( Material - > NeedsGBuffer ( ) )
{
// AdjustGBufferRefCount(-1) call is done when the pass gets executed
GSceneRenderTargets . AdjustGBufferRefCount ( 1 ) ;
}
2014-03-14 14:13:41 -04:00
if ( BaseFilename . Len ( ) )
{
2014-10-23 14:51:48 -04:00
FString MaterialFilename = BaseFilename + TEXT ( " _ " ) + ( * It ) - > GetName ( ) + TEXT ( " .png " ) ;
2014-03-14 14:13:41 -04:00
MaterialPass - > SetOutputDumpFilename ( ePId_Output0 , * MaterialFilename ) ;
}
// If the overview mode is activated, downsample the material pass to quarter size
if ( bOverviewModeEnabled )
{
// Down-sample to 1/2 size
2014-09-10 12:31:36 -04:00
FRenderingCompositePass * HalfSize = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDownsample ( PF_Unknown , 0 , TEXT ( " MaterialHalfSize " ) ) ) ;
2014-03-14 14:13:41 -04:00
HalfSize - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( MaterialPass ) ) ;
// Down-sample to 1/4 size
2014-09-10 12:31:36 -04:00
FRenderingCompositePass * QuarterSize = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDownsample ( PF_Unknown , 0 , TEXT ( " MaterialQuarterSize " ) ) ) ;
2014-03-14 14:13:41 -04:00
QuarterSize - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( HalfSize ) ) ;
// Mark the quarter size target as the dependency for the composite pass
( ( FRCPassPostProcessVisualizeBuffer * ) CompositePass ) - > AddVisualizationBuffer ( FRenderingCompositeOutputRef ( QuarterSize ) , ( * It ) - > GetName ( ) ) ;
}
else
{
// We are just dumping the frames, so the material pass is the dependency of the composite
CompositePass - > AddDependency ( MaterialPass ) ;
}
}
else
{
if ( bOverviewModeEnabled )
{
( ( FRCPassPostProcessVisualizeBuffer * ) CompositePass ) - > AddVisualizationBuffer ( FRenderingCompositeOutputRef ( ) , FString ( ) ) ;
}
}
}
}
}
}
// could be moved into the graph
// allows for Framebuffer blending optimization with the composition graph
void OverrideRenderTarget ( FRenderingCompositeOutputRef It , TRefCountPtr < IPooledRenderTarget > & RT , FPooledRenderTargetDesc & Desc )
{
for ( ; ; )
{
It . GetOutput ( ) - > PooledRenderTarget = RT ;
It . GetOutput ( ) - > RenderTargetDesc = Desc ;
if ( ! It . GetPass ( ) - > FrameBufferBlendingWithInput0 ( ) )
{
break ;
}
It = * It . GetPass ( ) - > GetInput ( ePId_Input0 ) ;
}
}
2014-08-28 13:54:31 -04:00
bool FPostProcessing : : AllowFullPostProcessing ( const FViewInfo & View , ERHIFeatureLevel : : Type FeatureLevel )
{
return View . Family - > EngineShowFlags . PostProcessing
& & FeatureLevel > = ERHIFeatureLevel : : SM4
& & ! View . Family - > EngineShowFlags . VisualizeDistanceFieldAO
2014-12-16 20:00:22 -05:00
& & ! View . Family - > EngineShowFlags . VisualizeDistanceFieldGI
2014-08-28 13:54:31 -04:00
& & ! View . Family - > EngineShowFlags . VisualizeMeshDistanceFields ;
}
2015-02-22 17:53:26 -05:00
static TAutoConsoleVariable < int32 > CVarMotionBlurNew (
TEXT ( " r.MotionBlurNew " ) ,
0 ,
TEXT ( " " ) ,
ECVF_RenderThreadSafe
) ;
2015-02-24 16:28:47 -05:00
static TAutoConsoleVariable < int32 > CVarMotionBlurScatter (
TEXT ( " r.MotionBlurScatter " ) ,
1 ,
TEXT ( " " ) ,
ECVF_RenderThreadSafe
) ;
static TAutoConsoleVariable < int32 > CVarMotionBlurDilate (
TEXT ( " r.MotionBlurDilate " ) ,
0 ,
TEXT ( " " ) ,
ECVF_RenderThreadSafe
) ;
2014-08-12 18:24:52 -04:00
void FPostProcessing : : Process ( FRHICommandListImmediate & RHICmdList , FViewInfo & View , TRefCountPtr < IPooledRenderTarget > & VelocityRT )
2014-03-14 14:13:41 -04:00
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_PostProcessing_Process ) ;
check ( IsInRenderingThread ( ) ) ;
2014-05-08 09:05:50 -04:00
const auto FeatureLevel = View . GetFeatureLevel ( ) ;
2014-04-23 19:52:11 -04:00
GRenderTargetPool . AddPhaseEvent ( TEXT ( " PostProcessing " ) ) ;
2014-03-14 14:13:41 -04:00
// This page: https://udn.epicgames.com/Three/RenderingOverview#Rendering%20state%20defaults
// describes what state a pass can expect and to what state it need to be set back.
// All post processing is happening on the render thread side. All passes can access FinalPostProcessSettings and all
// view settings. Those are copies for the RT then never get access by the main thread again.
// Pointers to other structures might be unsafe to touch.
// so that the passes can register themselves to the graph
{
FMemMark Mark ( FMemStack : : Get ( ) ) ;
2014-06-27 11:07:13 -04:00
FRenderingCompositePassContext CompositeContext ( RHICmdList , View ) ;
2014-03-14 14:13:41 -04:00
FPostprocessContext Context ( CompositeContext . Graph , View ) ;
// not always valid
FRenderingCompositeOutputRef HDRColor ;
// not always valid
2014-10-20 16:39:50 -04:00
FRenderingCompositeOutputRef HistogramOverScreen ;
// not always valid
2014-03-14 14:13:41 -04:00
FRenderingCompositeOutputRef Histogram ;
// not always valid
FRenderingCompositeOutputRef EyeAdaptation ;
// not always valid
FRenderingCompositeOutputRef SeparateTranslucency ;
2015-01-25 16:45:04 -05:00
// optional
FRenderingCompositeOutputRef BloomOutputCombined ;
2014-03-14 14:13:41 -04:00
bool bAllowTonemapper = true ;
EStereoscopicPass StereoPass = View . StereoPass ;
FSceneViewState * ViewState = ( FSceneViewState * ) Context . View . State ;
{
if ( ViewState & & ViewState - > SeparateTranslucencyRT )
{
FRenderingCompositePass * NodeSeparateTranslucency = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > SeparateTranslucencyRT ) ) ;
SeparateTranslucency = FRenderingCompositeOutputRef ( NodeSeparateTranslucency ) ;
// the node keeps another reference so the RT will not be release too early
ViewState - > FreeSeparateTranslucency ( ) ;
check ( ! ViewState - > SeparateTranslucencyRT ) ;
}
}
2014-10-20 17:40:17 -04:00
bool bVisualizeHDR = View . Family - > EngineShowFlags . VisualizeHDR & & FeatureLevel > = ERHIFeatureLevel : : SM5 ;
2015-01-25 14:54:46 -05:00
bool bVisualizeBloom = View . Family - > EngineShowFlags . VisualizeBloom & & FeatureLevel > = ERHIFeatureLevel : : SM4 ;
2014-10-20 17:40:17 -04:00
if ( bVisualizeHDR )
{
bAllowTonemapper = false ;
}
2014-03-14 14:13:41 -04:00
// add the passes we want to add to the graph (commenting a line means the pass is not inserted into the graph) ---------
2014-08-28 13:54:31 -04:00
if ( AllowFullPostProcessing ( View , FeatureLevel ) )
2014-03-14 14:13:41 -04:00
{
FRenderingCompositeOutputRef VelocityInput ;
if ( VelocityRT )
{
2014-09-02 16:37:25 -04:00
VelocityInput = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( VelocityRT ) ) ;
2014-03-14 14:13:41 -04:00
}
if ( Context . View . FinalPostProcessSettings . AntiAliasingMethod ! = AAM_TemporalAA & & ViewState )
{
if ( ViewState - > DOFHistoryRT )
{
ViewState - > DOFHistoryRT . SafeRelease ( ) ;
}
if ( ViewState - > TemporalAAHistoryRT )
{
ViewState - > TemporalAAHistoryRT . SafeRelease ( ) ;
}
}
AddPostProcessMaterial ( Context , BL_BeforeTranslucency , SeparateTranslucency ) ;
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.DepthOfFieldQuality " ) ) ;
check ( CVar )
bool bDepthOfField = View . Family - > EngineShowFlags . DepthOfField & & CVar - > GetValueOnRenderThread ( ) > 0 ;
2014-09-18 17:49:40 -04:00
FDepthOfFieldStats DepthOfFieldStat ;
2014-03-14 14:13:41 -04:00
if ( bDepthOfField & & View . FinalPostProcessSettings . DepthOfFieldMethod ! = DOFM_BokehDOF )
{
2015-01-27 17:42:51 -05:00
bool bCircleDOF = View . FinalPostProcessSettings . DepthOfFieldMethod = = DOFM_CircleDOF ;
if ( ! bCircleDOF )
{
2015-02-18 14:37:44 -05:00
if ( VelocityInput . IsValid ( ) )
{
AddPostProcessDepthOfFieldGaussian ( Context , DepthOfFieldStat , VelocityInput ) ;
}
else
{
// black is how we clear the velocity buffer so this means no velocity
FRenderingCompositePass * NoVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSystemTextures . BlackDummy ) ) ;
FRenderingCompositeOutputRef NoVelocityRef ( NoVelocity ) ;
AddPostProcessDepthOfFieldGaussian ( Context , DepthOfFieldStat , NoVelocityRef ) ;
}
2015-01-27 17:42:51 -05:00
}
else
{
2015-02-18 14:37:44 -05:00
if ( VelocityInput . IsValid ( ) )
{
AddPostProcessDepthOfFieldCircle ( Context , DepthOfFieldStat , VelocityInput ) ;
}
else
{
// black is how we clear the velocity buffer so this means no velocity
FRenderingCompositePass * NoVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSystemTextures . BlackDummy ) ) ;
FRenderingCompositeOutputRef NoVelocityRef ( NoVelocity ) ;
AddPostProcessDepthOfFieldCircle ( Context , DepthOfFieldStat , NoVelocityRef ) ;
}
2015-01-27 17:42:51 -05:00
}
2014-03-14 14:13:41 -04:00
}
bool bBokehDOF = bDepthOfField
& & View . FinalPostProcessSettings . DepthOfFieldScale > 0
& & View . FinalPostProcessSettings . DepthOfFieldMethod = = DOFM_BokehDOF
& & ! Context . View . Family - > EngineShowFlags . VisualizeDOF ;
if ( bBokehDOF )
{
2015-02-18 14:37:44 -05:00
if ( VelocityInput . IsValid ( ) )
{
AddPostProcessDepthOfFieldBokeh ( Context , SeparateTranslucency , VelocityInput ) ;
}
else
{
// black is how we clear the velocity buffer so this means no velocity
FRenderingCompositePass * NoVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSystemTextures . BlackDummy ) ) ;
FRenderingCompositeOutputRef NoVelocityRef ( NoVelocity ) ;
AddPostProcessDepthOfFieldBokeh ( Context , SeparateTranslucency , NoVelocityRef ) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
if ( SeparateTranslucency . IsValid ( ) )
{
// separate translucency is done here or in AddPostProcessDepthOfFieldBokeh()
FRenderingCompositePass * NodeRecombined = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBokehDOFRecombine ( ) ) ;
NodeRecombined - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
NodeRecombined - > SetInput ( ePId_Input2 , SeparateTranslucency ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( NodeRecombined ) ;
}
}
AddPostProcessMaterial ( Context , BL_BeforeTonemapping , SeparateTranslucency ) ;
EAntiAliasingMethod AntiAliasingMethod = Context . View . FinalPostProcessSettings . AntiAliasingMethod ;
if ( AntiAliasingMethod = = AAM_TemporalAA & & ViewState )
{
if ( VelocityInput . IsValid ( ) )
{
AddTemporalAA ( Context , VelocityInput ) ;
}
else
{
// black is how we clear the velocity buffer so this means no velocity
FRenderingCompositePass * NoVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( GSystemTextures . BlackDummy ) ) ;
FRenderingCompositeOutputRef NoVelocityRef ( NoVelocity ) ;
AddTemporalAA ( Context , NoVelocityRef ) ;
}
}
if ( IsMotionBlurEnabled ( View ) & & VelocityInput . IsValid ( ) )
{
2015-02-22 17:53:26 -05:00
// Motion blur
2014-03-14 14:13:41 -04:00
2015-04-14 09:03:46 -04:00
if ( CVarMotionBlurNew . GetValueOnRenderThread ( ) & & FeatureLevel > = ERHIFeatureLevel : : SM5 )
2014-03-14 14:13:41 -04:00
{
2015-02-22 17:53:26 -05:00
FRenderingCompositeOutputRef MaxTileVelocity ;
FRenderingCompositeOutputRef SceneDepth ( Context . SceneDepth ) ;
2014-03-14 14:13:41 -04:00
{
2015-02-22 17:53:26 -05:00
FRenderingCompositePass * VelocityFlattenPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVelocityFlatten ( ) ) ;
VelocityFlattenPass - > SetInput ( ePId_Input0 , VelocityInput ) ;
VelocityFlattenPass - > SetInput ( ePId_Input1 , SceneDepth ) ;
2015-02-24 16:28:47 -05:00
VelocityInput = FRenderingCompositeOutputRef ( VelocityFlattenPass , ePId_Output0 ) ;
MaxTileVelocity = FRenderingCompositeOutputRef ( VelocityFlattenPass , ePId_Output1 ) ;
}
if ( CVarMotionBlurScatter . GetValueOnRenderThread ( ) )
{
FRenderingCompositePass * VelocityScatterPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVelocityScatter ( ) ) ;
VelocityScatterPass - > SetInput ( ePId_Input0 , MaxTileVelocity ) ;
MaxTileVelocity = FRenderingCompositeOutputRef ( VelocityScatterPass ) ;
}
if ( CVarMotionBlurDilate . GetValueOnRenderThread ( ) )
{
FRenderingCompositePass * VelocityDilatePass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVelocityDilate ( ) ) ;
VelocityDilatePass - > SetInput ( ePId_Input0 , MaxTileVelocity ) ;
MaxTileVelocity = FRenderingCompositeOutputRef ( VelocityDilatePass ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-22 17:53:26 -05:00
{
FRenderingCompositePass * MotionBlurPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMotionBlurNew ( GetMotionBlurQualityFromCVar ( ) ) ) ;
MotionBlurPass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
MotionBlurPass - > SetInput ( ePId_Input1 , SceneDepth ) ;
MotionBlurPass - > SetInput ( ePId_Input2 , VelocityInput ) ;
MotionBlurPass - > SetInput ( ePId_Input3 , MaxTileVelocity ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( MotionBlurPass ) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2015-02-22 17:53:26 -05:00
FRenderingCompositeOutputRef SoftEdgeVelocity ;
2014-03-14 14:13:41 -04:00
2015-02-22 17:53:26 -05:00
FRenderingCompositeOutputRef MotionBlurHalfVelocity ;
FRenderingCompositeOutputRef MotionBlurColorDepth ;
2014-03-14 14:13:41 -04:00
2015-02-22 17:53:26 -05:00
// down sample screen space velocity and extend outside of borders to allows soft edge motion blur
{
// Down sample and prepare for soft masked blurring
FRenderingCompositePass * HalfResVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMotionBlurSetup ( ) ) ;
HalfResVelocity - > SetInput ( ePId_Input0 , VelocityInput ) ;
HalfResVelocity - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
// only for Depth of Field we need the depth in the alpha channel
HalfResVelocity - > SetInput ( ePId_Input2 , FRenderingCompositeOutputRef ( Context . SceneDepth ) ) ;
MotionBlurHalfVelocity = FRenderingCompositeOutputRef ( HalfResVelocity , ePId_Output0 ) ;
MotionBlurColorDepth = FRenderingCompositeOutputRef ( HalfResVelocity , ePId_Output1 ) ;
FRenderingCompositePass * QuarterResVelocity = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDownsample ( PF_Unknown , 0 , TEXT ( " QuarterResVelocity " ) ) ) ;
QuarterResVelocity - > SetInput ( ePId_Input0 , HalfResVelocity ) ;
SoftEdgeVelocity = FRenderingCompositeOutputRef ( QuarterResVelocity ) ;
float MotionBlurSoftEdgeSize = CVarMotionBlurSoftEdgeSize . GetValueOnRenderThread ( ) ;
if ( MotionBlurSoftEdgeSize > 0.01f )
{
SoftEdgeVelocity = RenderGaussianBlur ( Context , TEXT ( " VelocityBlurX " ) , TEXT ( " VelocityBlurY " ) , QuarterResVelocity , MotionBlurSoftEdgeSize ) ;
}
}
// doing the actual motion blur sampling, alpha to mask out the blurred areas
FRenderingCompositePass * MotionBlurPass ;
if ( View . Family - > EngineShowFlags . VisualizeMotionBlur )
{
MotionBlurPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeMotionBlur ( ) ) ;
bAllowTonemapper = false ;
}
else
{
int32 MotionBlurQuality = GetMotionBlurQualityFromCVar ( ) ;
MotionBlurPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMotionBlur ( MotionBlurQuality ) ) ;
}
MotionBlurPass - > SetInput ( ePId_Input0 , MotionBlurColorDepth ) ;
2014-03-14 14:13:41 -04:00
2015-04-23 17:34:26 -04:00
if ( VelocityInput . IsValid ( ) )
{
// blurred screen space velocity for soft masked motion blur
MotionBlurPass - > SetInput ( ePId_Input1 , SoftEdgeVelocity ) ;
// screen space velocity input from per object velocity rendering
MotionBlurPass - > SetInput ( ePId_Input2 , MotionBlurHalfVelocity ) ;
}
2014-03-14 14:13:41 -04:00
2015-02-22 17:53:26 -05:00
FRenderingCompositePass * MotionBlurRecombinePass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessMotionBlurRecombine ( ) ) ;
MotionBlurRecombinePass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
MotionBlurRecombinePass - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( MotionBlurPass ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( MotionBlurRecombinePass ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-25 14:54:46 -05:00
if ( bVisualizeBloom )
{
AddVisualizeBloomSetup ( Context ) ;
}
2014-03-14 14:13:41 -04:00
// down sample Scene color from full to half res
FRenderingCompositeOutputRef SceneColorHalfRes ;
{
// doesn't have to be as high quality as the Scene color
2014-09-10 12:31:36 -04:00
FRenderingCompositePass * HalfResPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDownsample ( PF_FloatRGB , 1 , TEXT ( " SceneColorHalfRes " ) ) ) ;
2014-03-14 14:13:41 -04:00
HalfResPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
SceneColorHalfRes = FRenderingCompositeOutputRef ( HalfResPass ) ;
}
{
2014-10-20 17:40:17 -04:00
bool bHistogramNeeded = false ;
2014-03-14 14:13:41 -04:00
if ( View . Family - > EngineShowFlags . EyeAdaptation
2014-06-11 11:48:46 -04:00
& & View . FinalPostProcessSettings . AutoExposureMinBrightness < View . FinalPostProcessSettings . AutoExposureMaxBrightness
2015-01-26 17:53:20 -05:00
& & ! View . bIsSceneCapture // Eye adaption is not available for scene captures.
& & ! bVisualizeBloom )
2014-03-14 14:13:41 -04:00
{
bHistogramNeeded = true ;
}
if ( ! bAllowTonemapper )
{
bHistogramNeeded = false ;
}
2014-10-20 17:40:17 -04:00
if ( View . Family - > EngineShowFlags . VisualizeHDR )
{
bHistogramNeeded = true ;
}
2014-05-08 09:05:50 -04:00
if ( ! GIsHighResScreenshot & & bHistogramNeeded & & FeatureLevel > = ERHIFeatureLevel : : SM5 & & StereoPass ! = eSSP_RIGHT_EYE )
2014-03-14 14:13:41 -04:00
{
2014-10-20 16:39:50 -04:00
FRenderingCompositePass * NodeHistogram = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessHistogram ( ) ) ;
NodeHistogram - > SetInput ( ePId_Input0 , SceneColorHalfRes ) ;
HistogramOverScreen = FRenderingCompositeOutputRef ( NodeHistogram ) ;
FRenderingCompositePass * NodeHistogramReduce = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessHistogramReduce ( ) ) ;
NodeHistogramReduce - > SetInput ( ePId_Input0 , NodeHistogram ) ;
Histogram = FRenderingCompositeOutputRef ( NodeHistogramReduce ) ;
2014-03-14 14:13:41 -04:00
}
}
// some views don't have a state (thumbnail rendering)
2014-11-07 15:01:06 -05:00
if ( ! GIsHighResScreenshot & & View . State & & ( StereoPass ! = eSSP_RIGHT_EYE ) )
2014-03-14 14:13:41 -04:00
{
// we always add eye adaptation, if the engine show flag is disabled we set the ExposureScale in the texture to a fixed value
EyeAdaptation = AddPostProcessEyeAdaptation ( Context , Histogram ) ;
}
if ( View . Family - > EngineShowFlags . Bloom )
{
2014-09-18 17:49:40 -04:00
if ( CVarUseMobileBloom . GetValueOnRenderThread ( ) = = 0 )
{
FRenderingCompositeOutputRef HalfResBloomThreshold = RenderHalfResBloomThreshold ( Context , SceneColorHalfRes , EyeAdaptation ) ;
BloomOutputCombined = AddBloom ( Context , HalfResBloomThreshold ) ;
}
else
{
FIntPoint PrePostSourceViewportSize = View . ViewRect . Size ( ) ;
2014-03-14 14:13:41 -04:00
2014-09-18 17:49:40 -04:00
// Bloom.
FRenderingCompositeOutputRef PostProcessDownsample2 ;
FRenderingCompositeOutputRef PostProcessDownsample3 ;
FRenderingCompositeOutputRef PostProcessDownsample4 ;
FRenderingCompositeOutputRef PostProcessDownsample5 ;
FRenderingCompositeOutputRef PostProcessUpsample4 ;
FRenderingCompositeOutputRef PostProcessUpsample3 ;
FRenderingCompositeOutputRef PostProcessUpsample2 ;
FRenderingCompositeOutputRef PostProcessSunMerge ;
float DownScale = 0.66f * 4.0f ;
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 4 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , SceneColorHalfRes ) ;
PostProcessDownsample2 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 8 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample2 ) ;
PostProcessDownsample3 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 16 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample3 ) ;
PostProcessDownsample4 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 32 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample4 ) ;
PostProcessDownsample5 = FRenderingCompositeOutputRef ( Pass ) ;
}
const FFinalPostProcessSettings & Settings = Context . View . FinalPostProcessSettings ;
float UpScale = 0.66f * 2.0f ;
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom4Tint . R , Settings . Bloom4Tint . G , Settings . Bloom4Tint . B , 0.0f ) ;
FVector4 TintB = FVector4 ( Settings . Bloom5Tint . R , Settings . Bloom5Tint . G , Settings . Bloom5Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
TintB * = View . FinalPostProcessSettings . BloomIntensity ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 32 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample4 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessDownsample5 ) ;
PostProcessUpsample4 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom3Tint . R , Settings . Bloom3Tint . G , Settings . Bloom3Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
FVector4 TintB = FVector4 ( 1.0f , 1.0f , 1.0f , 0.0f ) ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 16 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample3 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessUpsample4 ) ;
PostProcessUpsample3 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom2Tint . R , Settings . Bloom2Tint . G , Settings . Bloom2Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
// Scaling Bloom2 by extra factor to match filter area difference between PC default and mobile.
TintA * = 0.5 ;
FVector4 TintB = FVector4 ( 1.0f , 1.0f , 1.0f , 0.0f ) ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 8 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample2 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessUpsample3 ) ;
PostProcessUpsample2 = FRenderingCompositeOutputRef ( Pass ) ;
}
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunMergeES2 ( PrePostSourceViewportSize ) ) ;
Pass - > SetInput ( ePId_Input1 , SceneColorHalfRes ) ;
Pass - > SetInput ( ePId_Input2 , PostProcessUpsample2 ) ;
PostProcessSunMerge = FRenderingCompositeOutputRef ( Pass ) ;
BloomOutputCombined = PostProcessSunMerge ;
}
}
2014-03-14 14:13:41 -04:00
}
HDRColor = Context . FinalOutput ;
2014-05-08 09:05:50 -04:00
if ( bAllowTonemapper & & FeatureLevel > = ERHIFeatureLevel : : SM4 )
2014-03-14 14:13:41 -04:00
{
2014-09-26 15:22:35 -04:00
auto Node = AddSinglePostProcessMaterial ( Context , BL_ReplacingTonemapper ) ;
if ( Node )
{
// a custom tonemapper is provided
Node - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
// We are binding separate translucency here because the post process SceneTexture node can reference
// the separate translucency buffers through ePId_Input1.
// TODO: Check if material actually uses this texture and only bind if needed.
Node - > SetInput ( ePId_Input1 , SeparateTranslucency ) ;
Node - > SetInput ( ePId_Input2 , BloomOutputCombined ) ;
Context . FinalOutput = Node ;
}
else
{
AddTonemapper ( Context , BloomOutputCombined , EyeAdaptation ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-06-18 16:37:53 -04:00
if ( AntiAliasingMethod = = AAM_FXAA )
2014-03-14 14:13:41 -04:00
{
AddPostProcessAA ( Context ) ;
}
if ( bDepthOfField & & Context . View . Family - > EngineShowFlags . VisualizeDOF )
{
2014-09-18 17:49:40 -04:00
FRenderingCompositePass * VisualizeNode = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeDOF ( DepthOfFieldStat ) ) ;
2014-03-14 14:13:41 -04:00
VisualizeNode - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
// PassThrough is needed to upscale the half res texture
2014-05-06 11:27:50 -04:00
FPooledRenderTargetDesc Desc = GSceneRenderTargets . GetSceneColor ( ) - > GetDesc ( ) ;
2014-03-14 14:13:41 -04:00
Desc . Format = PF_B8G8R8A8 ;
FRenderingCompositePass * NullPass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessPassThrough ( Desc ) ) ;
NullPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( VisualizeNode ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( NullPass ) ;
}
}
else
{
if ( ViewState )
{
check ( ! ViewState - > SeparateTranslucencyRT ) ;
}
AddGammaOnlyTonemapper ( Context ) ;
}
if ( View . Family - > EngineShowFlags . StationaryLightOverlap )
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeComplexity ( GEngine - > StationaryLightOverlapColors ) ) ;
2014-05-14 14:53:31 -04:00
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . SceneColor ) ) ;
2014-03-14 14:13:41 -04:00
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
if ( View . Family - > EngineShowFlags . ShaderComplexity )
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeComplexity ( GEngine - > ShaderComplexityColors ) ) ;
2014-05-14 14:53:31 -04:00
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . SceneColor ) ) ;
2014-03-14 14:13:41 -04:00
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
// Show the selection outline if it is in the editor and we arent in wireframe
// If the engine is in demo mode and game view is on we also do not show the selection outline
2015-01-25 14:54:46 -05:00
if ( GIsEditor
& & View . Family - > EngineShowFlags . SelectionOutline
& & ! ( View . Family - > EngineShowFlags . Wireframe )
& & ( ! GIsDemoMode | | ( GIsDemoMode & & ! View . Family - > EngineShowFlags . Game ) )
2015-01-29 12:37:11 -05:00
& & ! bVisualizeBloom
& & ! View . Family - > EngineShowFlags . VisualizeHDR )
2014-03-14 14:13:41 -04:00
{
// Selection outline is after bloom, but before AA
AddSelectionOutline ( Context ) ;
}
// Composite editor primitives if we had any to draw and compositing is enabled
2015-01-25 14:54:46 -05:00
if ( FSceneRenderer : : ShouldCompositeEditorPrimitives ( View ) & & ! bVisualizeBloom )
2014-03-14 14:13:41 -04:00
{
2015-01-13 10:44:59 -05:00
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCompositeEditorPrimitives ( true ) ) ;
2014-03-14 14:13:41 -04:00
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
//Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.SceneDepth));
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2014-07-30 15:42:04 -04:00
if ( View . Family - > EngineShowFlags . GBufferHints & & FeatureLevel > = ERHIFeatureLevel : : SM4 )
2014-03-14 14:13:41 -04:00
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessGBufferHints ( ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
// Ideally without lighting as we want the emissive, we should do that later.
Node - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . SceneColor ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
AddPostProcessMaterial ( Context , BL_AfterTonemapping , SeparateTranslucency ) ;
2015-01-25 16:45:04 -05:00
if ( bVisualizeBloom )
{
AddVisualizeBloomOverlay ( Context , HDRColor , BloomOutputCombined ) ;
}
2014-11-19 17:00:58 -05:00
if ( View . Family - > EngineShowFlags . VisualizeSSS )
2014-08-22 14:15:05 -04:00
{
// the setup pass also does visualization, based on EngineShowFlags.VisualizeSSS
2014-10-15 16:18:43 -04:00
FRenderingCompositePass * PassVisualize = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSubsurfaceVisualize ( ) ) ;
2014-08-22 14:15:05 -04:00
PassVisualize - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( PassVisualize ) ;
}
2014-09-09 18:35:58 -04:00
AddGBufferVisualizationOverview ( Context , SeparateTranslucency ) ;
2014-03-14 14:13:41 -04:00
bool bStereoRenderingAndHMD = View . Family - > EngineShowFlags . StereoRendering & & View . Family - > EngineShowFlags . HMDDistortion ;
2015-04-02 16:54:49 -04:00
bool bHMDWantsUpscale = false ;
2014-03-14 14:13:41 -04:00
if ( bStereoRenderingAndHMD )
{
2014-04-23 17:31:09 -04:00
FRenderingCompositePass * Node = NULL ;
const EHMDDeviceType : : Type DeviceType = GEngine - > HMDDevice - > GetHMDDeviceType ( ) ;
if ( DeviceType = = EHMDDeviceType : : DT_OculusRift )
{
Node = Context . Graph . RegisterPass ( new FRCPassPostProcessHMD ( ) ) ;
}
else if ( DeviceType = = EHMDDeviceType : : DT_Morpheus )
{
2015-04-22 16:41:54 -04:00
# if MORPHEUS_ENGINE_DISTORTION
2015-04-08 17:24:01 -04:00
FRCPassPostProcessMorpheus * MorpheusPass = new FRCPassPostProcessMorpheus ( ) ;
MorpheusPass - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Node = Context . Graph . RegisterPass ( MorpheusPass ) ;
2015-04-08 17:58:20 -04:00
# endif
2015-04-22 16:41:54 -04:00
}
bHMDWantsUpscale = GEngine - > HMDDevice - > NeedsUpscalePostProcessPass ( ) ;
2014-04-23 17:31:09 -04:00
if ( Node )
{
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-10-20 17:40:17 -04:00
if ( bVisualizeHDR )
2014-03-14 14:13:41 -04:00
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeHDR ( ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Node - > SetInput ( ePId_Input1 , Histogram ) ;
Node - > SetInput ( ePId_Input2 , HDRColor ) ;
2014-10-20 16:39:50 -04:00
Node - > SetInput ( ePId_Input3 , HistogramOverScreen ) ;
2015-01-07 19:01:24 -05:00
Node - > AddDependency ( EyeAdaptation ) ;
2014-03-14 14:13:41 -04:00
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2014-05-08 09:05:50 -04:00
if ( View . Family - > EngineShowFlags . TestImage & & FeatureLevel > = ERHIFeatureLevel : : SM5 )
2014-03-14 14:13:41 -04:00
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessTestImage ( ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
AddHighResScreenshotMask ( Context , SeparateTranslucency ) ;
2014-11-03 16:17:18 -05:00
// 0=none..1=full
float Cylinder = 0.0f ;
if ( View . IsPerspectiveProjection ( ) & & ! GEngine - > StereoRenderingDevice . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-11-03 16:17:18 -05:00
Cylinder = FMath : : Clamp ( CVarUpscaleCylinder . GetValueOnRenderThread ( ) , 0.0f , 1.0f ) ;
}
// Do not use upscale if SeparateRenderTarget is in use!
2015-04-02 16:54:49 -04:00
if ( ( Cylinder > 0.01f | | View . UnscaledViewRect ! = View . ViewRect ) & &
( bHMDWantsUpscale | | ! View . Family - > EngineShowFlags . StereoRendering | | ( ! View . Family - > EngineShowFlags . HMDDistortion & & ! View . Family - > bUseSeparateRenderTarget ) ) )
2014-11-03 16:17:18 -05:00
{
int32 UpscaleQuality = CVarUpscaleQuality . GetValueOnRenderThread ( ) ;
UpscaleQuality = FMath : : Clamp ( UpscaleQuality , 0 , 3 ) ;
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessUpscale ( UpscaleQuality , Cylinder ) ) ;
2014-03-14 14:13:41 -04:00
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ; // Bilinear sampling.
Node - > SetInput ( ePId_Input1 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ; // Point sampling.
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2014-05-16 17:29:16 -04:00
// After the graph is built but before the graph is processed.
// If a postprocess material is using a GBuffer it adds the refcount int FRCPassPostProcessMaterial::Process()
// and when it gets processed it removes the refcount
// We only release the GBuffers after the last view was processed (SplitScreen)
if ( View . Family - > Views [ View . Family - > Views . Num ( ) - 1 ] = = & View )
{
// Generally we no longer need the GBuffers, anyone that wants to keep the GBuffers for longer should have called AdjustGBufferRefCount(1) to keep it for longer
// and call AdjustGBufferRefCount(-1) once it's consumed. This needs to happen each frame. PostProcessMaterial do that automatically
GSceneRenderTargets . AdjustGBufferRefCount ( - 1 ) ;
}
2014-03-14 14:13:41 -04:00
// The graph setup should be finished before this line ----------------------------------------
{
// currently created on the heap each frame but View.Family->RenderTarget could keep this object and all would be cleaner
TRefCountPtr < IPooledRenderTarget > Temp ;
FSceneRenderTargetItem Item ;
Item . TargetableTexture = ( FTextureRHIRef & ) View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
Item . ShaderResourceTexture = ( FTextureRHIRef & ) View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
FPooledRenderTargetDesc Desc ;
2014-07-03 21:55:37 -04:00
// Texture could be bigger than viewport
2014-10-28 22:04:42 -04:00
if ( View . Family - > RenderTarget - > GetRenderTargetTexture ( ) )
{
Desc . Extent . X = View . Family - > RenderTarget - > GetRenderTargetTexture ( ) - > GetSizeX ( ) ;
Desc . Extent . Y = View . Family - > RenderTarget - > GetRenderTargetTexture ( ) - > GetSizeY ( ) ;
}
else
{
Desc . Extent = View . Family - > RenderTarget - > GetSizeXY ( ) ;
}
2014-03-14 14:13:41 -04:00
// todo: this should come from View.Family->RenderTarget
Desc . Format = PF_B8G8R8A8 ;
Desc . NumMips = 1 ;
2014-05-19 17:59:23 -04:00
Desc . DebugName = TEXT ( " FinalPostProcessColor " ) ;
2014-03-14 14:13:41 -04:00
GRenderTargetPool . CreateUntrackedElement ( Desc , Temp , Item ) ;
OverrideRenderTarget ( Context . FinalOutput , Temp , Desc ) ;
// you can add multiple dependencies
CompositeContext . Root - > AddDependency ( Context . FinalOutput ) ;
CompositeContext . Process ( TEXT ( " PostProcessing " ) ) ;
}
}
2014-05-08 17:58:14 -04:00
GRenderTargetPool . AddPhaseEvent ( TEXT ( " AfterPostprocessing " ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-12 18:24:52 -04:00
void FPostProcessing : : ProcessES2 ( FRHICommandListImmediate & RHICmdList , FViewInfo & View , bool bUsedFramebufferFetch )
2014-03-14 14:13:41 -04:00
{
check ( IsInRenderingThread ( ) ) ;
// This page: https://udn.epicgames.com/Three/RenderingOverview#Rendering%20state%20defaults
// describes what state a pass can expect and to what state it need to be set back.
// All post processing is happening on the render thread side. All passes can access FinalPostProcessSettings and all
// view settings. Those are copies for the RT then never get access by the main thread again.
// Pointers to other structures might be unsafe to touch.
// so that the passes can register themselves to the graph
{
FMemMark Mark ( FMemStack : : Get ( ) ) ;
2014-06-27 11:07:13 -04:00
FRenderingCompositePassContext CompositeContext ( RHICmdList , View ) ;
2014-03-14 14:13:41 -04:00
FPostprocessContext Context ( CompositeContext . Graph , View ) ;
FRenderingCompositeOutputRef BloomOutput ;
FRenderingCompositeOutputRef DofOutput ;
bool bUseAa = View . FinalPostProcessSettings . AntiAliasingMethod = = AAM_TemporalAA ;
// AA with Mobile32bpp mode requires this outside of bUsePost.
if ( bUseAa )
{
// Handle pointer swap for double buffering.
FSceneViewState * ViewState = ( FSceneViewState * ) View . State ;
if ( ViewState )
{
// Note that this drops references to the render targets from two frames ago. This
// causes them to be added back to the pool where we can grab them again.
ViewState - > MobileAaBloomSunVignette1 = ViewState - > MobileAaBloomSunVignette0 ;
ViewState - > MobileAaColor1 = ViewState - > MobileAaColor0 ;
}
}
2014-11-27 10:36:38 -05:00
const FIntPoint FinalTargetSize = View . Family - > RenderTarget - > GetSizeXY ( ) ;
FIntRect FinalOutputViewRect = View . ViewRect ;
2014-09-17 09:30:48 -04:00
FIntPoint PrePostSourceViewportSize = View . ViewRect . Size ( ) ;
// ES2 preview uses a subsection of the scene RT, bUsedFramebufferFetch == true deals with this case.
bool bViewRectSource = bUsedFramebufferFetch | | GSceneRenderTargets . GetBufferSizeXY ( ) ! = PrePostSourceViewportSize ;
2014-03-14 14:13:41 -04:00
// add the passes we want to add to the graph (commenting a line means the pass is not inserted into the graph) ---------
if ( View . Family - > EngineShowFlags . PostProcessing )
{
bool bUseSun = View . bLightShaftUse ;
bool bUseDof = View . FinalPostProcessSettings . DepthOfFieldScale > 0.0f ;
bool bUseBloom = View . FinalPostProcessSettings . BloomIntensity > 0.0f ;
bool bUseVignette = View . FinalPostProcessSettings . VignetteIntensity > 0.0f ;
bool bWorkaround = CVarRenderTargetSwitchWorkaround . GetValueOnRenderThread ( ) ! = 0 ;
// This is a workaround to avoid a performance cliff when using many render targets.
bool bUseBloomSmall = bUseBloom & & ! bUseSun & & ! bUseDof & & bWorkaround ;
bool bUsePost = bUseSun | bUseDof | bUseBloom | bUseVignette ;
// Post is only supported on ES2 devices with FP16.
bUsePost & = GSupportsRenderTargetFormat_PF_FloatRGBA ;
bUsePost & = IsMobileHDR ( ) ;
if ( bUsePost )
{
// Skip this pass if the pass was done prior before resolve.
if ( ( ! bUsedFramebufferFetch ) & & ( bUseSun | | bUseDof ) )
{
// Convert depth to {circle of confusion, sun shaft intensity} before resolve.
FRenderingCompositePass * PostProcessSunMask = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunMaskES2 ( PrePostSourceViewportSize , false ) ) ;
PostProcessSunMask - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( PostProcessSunMask ) ;
2014-11-27 10:36:38 -05:00
// Context.FinalOutput now contains entire image.
// (potentially clipped to content of View.ViewRect.)
FinalOutputViewRect = FIntRect ( FIntPoint ( 0 , 0 ) , PrePostSourceViewportSize ) ;
2014-03-14 14:13:41 -04:00
}
FRenderingCompositeOutputRef PostProcessBloomSetup ;
if ( bUseSun | | bUseDof | | bUseBloom )
{
if ( bUseBloomSmall )
{
2014-09-17 09:30:48 -04:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomSetupSmallES2 ( PrePostSourceViewportSize , bViewRectSource ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
PostProcessBloomSetup = FRenderingCompositeOutputRef ( Pass ) ;
}
else
{
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomSetupES2 ( FinalOutputViewRect , bViewRectSource ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
PostProcessBloomSetup = FRenderingCompositeOutputRef ( Pass ) ;
}
}
if ( bUseDof )
{
// Near dilation circle of confusion size.
// Samples at 1/16 area, writes to 1/16 area.
FRenderingCompositeOutputRef PostProcessNear ;
{
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDofNearES2 ( FinalOutputViewRect . Size ( ) ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , PostProcessBloomSetup ) ;
PostProcessNear = FRenderingCompositeOutputRef ( Pass ) ;
}
// DOF downsample pass.
// Samples at full resolution, writes to 1/4 area.
FRenderingCompositeOutputRef PostProcessDofDown ;
{
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDofDownES2 ( FinalOutputViewRect , bViewRectSource ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessNear ) ;
PostProcessDofDown = FRenderingCompositeOutputRef ( Pass ) ;
}
// DOF blur pass.
// Samples at 1/4 area, writes to 1/4 area.
FRenderingCompositeOutputRef PostProcessDofBlur ;
{
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessDofBlurES2 ( FinalOutputViewRect . Size ( ) ) ) ;
2014-03-14 14:13:41 -04:00
Pass - > SetInput ( ePId_Input0 , PostProcessDofDown ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessNear ) ;
PostProcessDofBlur = FRenderingCompositeOutputRef ( Pass ) ;
DofOutput = PostProcessDofBlur ;
}
}
// Bloom.
FRenderingCompositeOutputRef PostProcessDownsample2 ;
FRenderingCompositeOutputRef PostProcessDownsample3 ;
FRenderingCompositeOutputRef PostProcessDownsample4 ;
FRenderingCompositeOutputRef PostProcessDownsample5 ;
FRenderingCompositeOutputRef PostProcessUpsample4 ;
FRenderingCompositeOutputRef PostProcessUpsample3 ;
FRenderingCompositeOutputRef PostProcessUpsample2 ;
if ( bUseBloomSmall )
{
float DownScale = 0.66f * 4.0f ;
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 4 , DownScale * 2.0f ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessBloomSetup ) ;
PostProcessDownsample2 = FRenderingCompositeOutputRef ( Pass ) ;
}
}
if ( bUseBloom & & ( ! bUseBloomSmall ) )
{
float DownScale = 0.66f * 4.0f ;
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 4 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessBloomSetup ) ;
PostProcessDownsample2 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 8 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample2 ) ;
PostProcessDownsample3 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 16 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample3 ) ;
PostProcessDownsample4 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Downsample by 2
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomDownES2 ( PrePostSourceViewportSize / 32 , DownScale ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample4 ) ;
PostProcessDownsample5 = FRenderingCompositeOutputRef ( Pass ) ;
}
const FFinalPostProcessSettings & Settings = Context . View . FinalPostProcessSettings ;
float UpScale = 0.66f * 2.0f ;
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom4Tint . R , Settings . Bloom4Tint . G , Settings . Bloom4Tint . B , 0.0f ) ;
FVector4 TintB = FVector4 ( Settings . Bloom5Tint . R , Settings . Bloom5Tint . G , Settings . Bloom5Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
TintB * = View . FinalPostProcessSettings . BloomIntensity ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 32 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample4 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessDownsample5 ) ;
PostProcessUpsample4 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom3Tint . R , Settings . Bloom3Tint . G , Settings . Bloom3Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
FVector4 TintB = FVector4 ( 1.0f , 1.0f , 1.0f , 0.0f ) ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 16 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample3 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessUpsample4 ) ;
PostProcessUpsample3 = FRenderingCompositeOutputRef ( Pass ) ;
}
// Upsample by 2
{
FVector4 TintA = FVector4 ( Settings . Bloom2Tint . R , Settings . Bloom2Tint . G , Settings . Bloom2Tint . B , 0.0f ) ;
TintA * = View . FinalPostProcessSettings . BloomIntensity ;
// Scaling Bloom2 by extra factor to match filter area difference between PC default and mobile.
TintA * = 0.5 ;
FVector4 TintB = FVector4 ( 1.0f , 1.0f , 1.0f , 0.0f ) ;
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessBloomUpES2 ( PrePostSourceViewportSize / 8 , FVector2D ( UpScale , UpScale ) , TintA , TintB ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessDownsample2 ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessUpsample3 ) ;
PostProcessUpsample2 = FRenderingCompositeOutputRef ( Pass ) ;
}
}
FRenderingCompositeOutputRef PostProcessSunBlur ;
if ( bUseSun )
{
// Sunshaft depth blur using downsampled alpha.
FRenderingCompositeOutputRef PostProcessSunAlpha ;
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunAlphaES2 ( PrePostSourceViewportSize ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessBloomSetup ) ;
PostProcessSunAlpha = FRenderingCompositeOutputRef ( Pass ) ;
}
// Sunshaft blur number two.
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunBlurES2 ( PrePostSourceViewportSize ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessSunAlpha ) ;
PostProcessSunBlur = FRenderingCompositeOutputRef ( Pass ) ;
}
}
if ( bUseSun | bUseVignette | bUseBloom )
{
FRenderingCompositeOutputRef PostProcessSunMerge ;
if ( bUseBloomSmall )
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunMergeSmallES2 ( PrePostSourceViewportSize ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessBloomSetup ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessDownsample2 ) ;
PostProcessSunMerge = FRenderingCompositeOutputRef ( Pass ) ;
BloomOutput = PostProcessSunMerge ;
}
else
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunMergeES2 ( PrePostSourceViewportSize ) ) ;
if ( bUseSun )
{
Pass - > SetInput ( ePId_Input0 , PostProcessSunBlur ) ;
}
if ( bUseBloom )
{
Pass - > SetInput ( ePId_Input1 , PostProcessBloomSetup ) ;
Pass - > SetInput ( ePId_Input2 , PostProcessUpsample2 ) ;
}
PostProcessSunMerge = FRenderingCompositeOutputRef ( Pass ) ;
BloomOutput = PostProcessSunMerge ;
}
// Mobile temporal AA requires a composite of two of these frames.
if ( bUseAa & & ( bUseBloom | | bUseSun ) )
{
FSceneViewState * ViewState = ( FSceneViewState * ) View . State ;
FRenderingCompositeOutputRef PostProcessSunMerge2 ;
if ( ViewState & & ViewState - > MobileAaBloomSunVignette1 )
{
FRenderingCompositePass * History ;
History = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > MobileAaBloomSunVignette1 ) ) ;
PostProcessSunMerge2 = FRenderingCompositeOutputRef ( History ) ;
}
else
{
PostProcessSunMerge2 = PostProcessSunMerge ;
}
FRenderingCompositeOutputRef PostProcessSunAvg ;
{
FRenderingCompositePass * Pass = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessSunAvgES2 ( PrePostSourceViewportSize ) ) ;
Pass - > SetInput ( ePId_Input0 , PostProcessSunMerge ) ;
Pass - > SetInput ( ePId_Input1 , PostProcessSunMerge2 ) ;
PostProcessSunAvg = FRenderingCompositeOutputRef ( Pass ) ;
}
BloomOutput = PostProcessSunAvg ;
}
}
}
}
2014-07-10 10:39:54 -04:00
2014-03-14 14:13:41 -04:00
// Must run to blit to back buffer even if post processing is off.
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * PostProcessTonemap = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessTonemapES2 ( Context . View , FinalOutputViewRect , FinalTargetSize , bViewRectSource ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessTonemap - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
PostProcessTonemap - > SetInput ( ePId_Input1 , BloomOutput ) ;
PostProcessTonemap - > SetInput ( ePId_Input2 , DofOutput ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( PostProcessTonemap ) ;
2014-11-27 10:36:38 -05:00
// if Context.FinalOutput was the clipped result of sunmask stage then this stage also restores Context.FinalOutput back original target size.
2014-12-08 09:45:54 -05:00
FinalOutputViewRect = View . UnscaledViewRect ;
2014-03-14 14:13:41 -04:00
if ( bUseAa & & View . Family - > EngineShowFlags . PostProcessing )
{
// Double buffer post output.
FSceneViewState * ViewState = ( FSceneViewState * ) View . State ;
FRenderingCompositeOutputRef PostProcessPrior = Context . FinalOutput ;
if ( ViewState & & ViewState - > MobileAaColor1 )
{
FRenderingCompositePass * History ;
History = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessInput ( ViewState - > MobileAaColor1 ) ) ;
PostProcessPrior = FRenderingCompositeOutputRef ( History ) ;
}
// Mobile temporal AA is done after tonemapping.
2014-11-27 10:36:38 -05:00
FRenderingCompositePass * PostProcessAa = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessAaES2 ( ) ) ;
2014-03-14 14:13:41 -04:00
PostProcessAa - > SetInput ( ePId_Input0 , Context . FinalOutput ) ;
PostProcessAa - > SetInput ( ePId_Input1 , PostProcessPrior ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( PostProcessAa ) ;
}
2015-01-21 11:48:05 -05:00
if ( FSceneRenderer : : ShouldCompositeEditorPrimitives ( View ) )
2014-09-17 09:30:48 -04:00
{
2015-01-21 11:48:05 -05:00
FRenderingCompositePass * EditorCompNode = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessCompositeEditorPrimitives ( false ) ) ;
EditorCompNode - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
//Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.SceneDepth));
Context . FinalOutput = FRenderingCompositeOutputRef ( EditorCompNode ) ;
2014-09-17 09:30:48 -04:00
}
2014-03-14 14:13:41 -04:00
if ( View . Family - > EngineShowFlags . ShaderComplexity )
{
FRenderingCompositePass * Node = Context . Graph . RegisterPass ( new ( FMemStack : : Get ( ) ) FRCPassPostProcessVisualizeComplexity ( GEngine - > ShaderComplexityColors ) ) ;
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
2014-08-10 03:43:19 -04:00
bool bStereoRenderingAndHMD = View . Family - > EngineShowFlags . StereoRendering & & View . Family - > EngineShowFlags . HMDDistortion ;
if ( bStereoRenderingAndHMD )
{
FRenderingCompositePass * Node = NULL ;
const EHMDDeviceType : : Type DeviceType = GEngine - > HMDDevice - > GetHMDDeviceType ( ) ;
if ( DeviceType = = EHMDDeviceType : : DT_ES2GenericStereoMesh )
{
Node = Context . Graph . RegisterPass ( new FRCPassPostProcessHMD ( ) ) ;
}
if ( Node )
{
Node - > SetInput ( ePId_Input0 , FRenderingCompositeOutputRef ( Context . FinalOutput ) ) ;
Context . FinalOutput = FRenderingCompositeOutputRef ( Node ) ;
}
}
2014-03-14 14:13:41 -04:00
// The graph setup should be finished before this line ----------------------------------------
{
// currently created on the heap each frame but View.Family->RenderTarget could keep this object and all would be cleaner
TRefCountPtr < IPooledRenderTarget > Temp ;
FSceneRenderTargetItem Item ;
Item . TargetableTexture = ( FTextureRHIRef & ) View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
Item . ShaderResourceTexture = ( FTextureRHIRef & ) View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
FPooledRenderTargetDesc Desc ;
Desc . Extent = View . Family - > RenderTarget - > GetSizeXY ( ) ;
// todo: this should come from View.Family->RenderTarget
Desc . Format = PF_B8G8R8A8 ;
Desc . NumMips = 1 ;
GRenderTargetPool . CreateUntrackedElement ( Desc , Temp , Item ) ;
OverrideRenderTarget ( Context . FinalOutput , Temp , Desc ) ;
// you can add multiple dependencies
CompositeContext . Root - > AddDependency ( Context . FinalOutput ) ;
CompositeContext . Process ( TEXT ( " PostProcessingES2 " ) ) ;
}
}
}