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
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
|
ScreenSpaceReflections.cpp: Post processing Screen Space Reflections implementation.
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
|
|
#include "RendererPrivate.h"
|
|
|
|
|
#include "ScenePrivate.h"
|
|
|
|
|
#include "SceneFilterRendering.h"
|
|
|
|
|
#include "PostProcessing.h"
|
|
|
|
|
#include "ScreenSpaceReflections.h"
|
2014-04-02 18:09:23 -04:00
|
|
|
#include "PostProcessTemporalAA.h"
|
|
|
|
|
#include "PostProcessAmbientOcclusion.h"
|
2014-08-21 06:03:00 -04:00
|
|
|
#include "SceneUtils.h"
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
static TAutoConsoleVariable<int32> CVarSSRQuality(
|
|
|
|
|
TEXT("r.SSR.Quality"),
|
|
|
|
|
3,
|
|
|
|
|
TEXT("Whether to use screen space reflections and at what quality setting.\n")
|
|
|
|
|
TEXT("(limits the setting in the post process settings which has a different scale)\n")
|
|
|
|
|
TEXT("(costs performance, adds more visual realism but the technique has limits)\n")
|
|
|
|
|
TEXT(" 0: off (default)\n")
|
|
|
|
|
TEXT(" 1: low (no glossy)\n")
|
|
|
|
|
TEXT(" 2: medium (no glossy)\n")
|
|
|
|
|
TEXT(" 3: high (glossy/using roughness, few samples)\n")
|
2014-06-26 20:02:41 -04:00
|
|
|
TEXT(" 4: very high (likely too slow for real-time)"),
|
2014-03-14 14:13:41 -04:00
|
|
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
|
|
|
|
|
|
|
|
|
static TAutoConsoleVariable<int32> CVarSSRTemporal(
|
|
|
|
|
TEXT("r.SSR.Temporal"),
|
|
|
|
|
0,
|
|
|
|
|
TEXT("Defines if we use the temporal smoothing for the screen space reflection\n")
|
|
|
|
|
TEXT(" 0 is off (for debugging), 1 is on (default)"),
|
|
|
|
|
ECVF_RenderThreadSafe);
|
|
|
|
|
|
|
|
|
|
bool DoScreenSpaceReflections(const FViewInfo& View)
|
|
|
|
|
{
|
|
|
|
|
if(!View.Family->EngineShowFlags.ScreenSpaceReflections)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!View.State)
|
|
|
|
|
{
|
|
|
|
|
// not view state (e.g. thumbnail rendering?), no HZB (no screen space reflections or occlusion culling)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SSRQuality = CVarSSRQuality.GetValueOnRenderThread();
|
|
|
|
|
|
|
|
|
|
if(SSRQuality <= 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(View.FinalPostProcessSettings.ScreenSpaceReflectionIntensity < 1.0f)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-26 20:02:41 -04:00
|
|
|
/**
|
|
|
|
|
* Encapsulates the post processing screen space reflections pixel shader.
|
|
|
|
|
* @param SSRQuality 0:Visualize Mask
|
|
|
|
|
*/
|
2014-03-14 14:13:41 -04:00
|
|
|
template<uint32 PrevFrame, uint32 SSRQuality >
|
|
|
|
|
class FPostProcessScreenSpaceReflectionsPS : public FGlobalShader
|
|
|
|
|
{
|
|
|
|
|
DECLARE_SHADER_TYPE(FPostProcessScreenSpaceReflectionsPS, Global);
|
|
|
|
|
|
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
|
|
|
{
|
|
|
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
|
|
|
{
|
|
|
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
|
|
|
|
|
OutEnvironment.SetDefine( TEXT("PREV_FRAME_COLOR"), PrevFrame );
|
|
|
|
|
OutEnvironment.SetDefine( TEXT("SSR_QUALITY"), SSRQuality );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Default constructor. */
|
|
|
|
|
FPostProcessScreenSpaceReflectionsPS() {}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FPostProcessPassParameters PostprocessParameter;
|
|
|
|
|
FDeferredPixelShaderParameters DeferredParameters;
|
|
|
|
|
FShaderParameter SSRParams;
|
|
|
|
|
|
|
|
|
|
/** Initialization constructor. */
|
|
|
|
|
FPostProcessScreenSpaceReflectionsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
|
|
|
: FGlobalShader(Initializer)
|
|
|
|
|
{
|
|
|
|
|
PostprocessParameter.Bind(Initializer.ParameterMap);
|
|
|
|
|
DeferredParameters.Bind(Initializer.ParameterMap);
|
|
|
|
|
SSRParams.Bind(Initializer.ParameterMap, TEXT("SSRParams"));
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 07:13:34 -04:00
|
|
|
void SetParameters(const FRenderingCompositePassContext& Context)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
const FFinalPostProcessSettings& Settings = Context.View.FinalPostProcessSettings;
|
|
|
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
|
|
2014-06-12 07:13:34 -04:00
|
|
|
FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2014-06-12 07:13:34 -04:00
|
|
|
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI());
|
|
|
|
|
DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
float MaxRoughness = FMath::Clamp(Context.View.FinalPostProcessSettings.ScreenSpaceReflectionMaxRoughness, 0.01f, 1.0f);
|
|
|
|
|
|
|
|
|
|
// f(x) = x * Scale + Bias
|
|
|
|
|
// f(MaxRoughness) = 0
|
|
|
|
|
// f(MaxRoughness/2) = 1
|
|
|
|
|
|
|
|
|
|
float RoughnessMaskScale = -2.0f / MaxRoughness;
|
2014-06-27 16:23:33 -04:00
|
|
|
RoughnessMaskScale *= SSRQuality < 3 ? 2.0f : 1.0f;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
FLinearColor Value(
|
|
|
|
|
FMath::Clamp(Context.View.FinalPostProcessSettings.ScreenSpaceReflectionIntensity * 0.01f, 0.0f, 1.0f),
|
|
|
|
|
RoughnessMaskScale,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
2014-06-12 07:13:34 -04:00
|
|
|
SetShaderValue(Context.RHICmdList, ShaderRHI, SSRParams, Value);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FShader interface.
|
2015-04-01 07:20:55 -04:00
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
|
|
|
Ar << PostprocessParameter << DeferredParameters << SSRParams;
|
|
|
|
|
return bShaderHasOutdatedParameters;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
|
|
|
|
|
#define IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(A, B) \
|
|
|
|
|
typedef FPostProcessScreenSpaceReflectionsPS<A,B> FPostProcessScreenSpaceReflectionsPS##A##B; \
|
|
|
|
|
IMPLEMENT_SHADER_TYPE(template<>,FPostProcessScreenSpaceReflectionsPS##A##B,TEXT("ScreenSpaceReflections"),TEXT("ScreenSpaceReflectionsPS"),SF_Pixel)
|
|
|
|
|
|
2014-06-26 20:02:41 -04:00
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(0,0);
|
2014-03-14 14:13:41 -04:00
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(0,1);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(1,1);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(0,2);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(1,2);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(0,3);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(1,3);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(0,4);
|
|
|
|
|
IMPLEMENT_REFLECTION_PIXELSHADER_TYPE(1,4);
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// @param Quality usually in 0..100 range, default is 50
|
|
|
|
|
// @return see CVarSSRQuality, never 0
|
|
|
|
|
static int32 ComputeSSRQuality(float Quality)
|
|
|
|
|
{
|
|
|
|
|
int32 Ret;
|
|
|
|
|
|
2014-05-29 17:53:21 -04:00
|
|
|
if(Quality >= 60.0f)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-05-29 17:53:21 -04:00
|
|
|
Ret = (Quality >= 80.0f) ? 4 : 3;
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-05-29 17:53:21 -04:00
|
|
|
Ret = (Quality >= 40.0f) ? 2 : 1;
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SSRQualityCVar = FMath::Max(0, CVarSSRQuality.GetValueOnRenderThread());
|
|
|
|
|
|
|
|
|
|
return FMath::Min(Ret, SSRQualityCVar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRCPassPostProcessScreenSpaceReflections::Process(FRenderingCompositePassContext& Context)
|
|
|
|
|
{
|
2014-10-20 10:43:43 -04:00
|
|
|
SCOPED_DRAW_EVENT(Context.RHICmdList, ScreenSpaceReflections);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
const FSceneView& View = Context.View;
|
2014-08-19 10:41:34 -04:00
|
|
|
const auto FeatureLevel = Context.GetFeatureLevel();
|
2014-03-14 14:13:41 -04:00
|
|
|
const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);
|
|
|
|
|
|
|
|
|
|
// Set the view family's render target/viewport.
|
2014-06-12 07:13:34 -04:00
|
|
|
SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef());
|
|
|
|
|
Context.RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, FIntRect());
|
2014-03-14 14:13:41 -04:00
|
|
|
Context.SetViewportAndCallRHI(View.ViewRect);
|
|
|
|
|
|
|
|
|
|
// set the state
|
2014-06-12 07:13:34 -04:00
|
|
|
Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
|
Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
|
|
|
|
|
Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
int SSRQuality = ComputeSSRQuality(View.FinalPostProcessSettings.ScreenSpaceReflectionQuality);
|
|
|
|
|
|
|
|
|
|
SSRQuality = FMath::Clamp(SSRQuality, 1, 4);
|
2014-06-27 11:07:13 -04:00
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2014-06-26 20:02:41 -04:00
|
|
|
uint32 iPreFrame = bPrevFrame ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
if (View.Family->EngineShowFlags.VisualizeSSR)
|
|
|
|
|
{
|
|
|
|
|
iPreFrame = 0;
|
|
|
|
|
SSRQuality = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-28 06:22:54 -04:00
|
|
|
TShaderMapRef< FPostProcessVS > VertexShader(Context.GetShaderMap());
|
2014-06-26 20:02:41 -04:00
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
#define CASE(A, B) \
|
|
|
|
|
case (A + 2 * (B + 3 * 0 )): \
|
|
|
|
|
{ \
|
2014-08-28 06:22:54 -04:00
|
|
|
TShaderMapRef< FPostProcessScreenSpaceReflectionsPS<A, B> > PixelShader(Context.GetShaderMap()); \
|
2014-03-14 14:13:41 -04:00
|
|
|
static FGlobalBoundShaderState BoundShaderState; \
|
2014-08-19 10:41:34 -04:00
|
|
|
SetGlobalBoundShaderState(Context.RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \
|
2014-06-12 07:13:34 -04:00
|
|
|
VertexShader->SetParameters(Context); \
|
|
|
|
|
PixelShader->SetParameters(Context); \
|
2014-03-14 14:13:41 -04:00
|
|
|
}; \
|
|
|
|
|
break
|
|
|
|
|
|
2014-06-26 20:02:41 -04:00
|
|
|
switch (iPreFrame + 2 * (SSRQuality + 3 * 0))
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-26 20:02:41 -04:00
|
|
|
CASE(0,0);
|
2014-03-14 14:13:41 -04:00
|
|
|
CASE(0,1); CASE(1,1);
|
|
|
|
|
CASE(0,2); CASE(1,2);
|
|
|
|
|
CASE(0,3); CASE(1,3);
|
|
|
|
|
CASE(0,4); CASE(1,4);
|
2014-06-26 20:02:41 -04:00
|
|
|
default:
|
|
|
|
|
check(!"Missing case in FRCPassPostProcessScreenSpaceReflections");
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
#undef CASE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw a quad mapping scene color to the view's render target
|
|
|
|
|
DrawRectangle(
|
2014-06-12 07:13:34 -04:00
|
|
|
Context.RHICmdList,
|
2014-03-14 14:13:41 -04:00
|
|
|
0, 0,
|
|
|
|
|
View.ViewRect.Width(), View.ViewRect.Height(),
|
|
|
|
|
View.ViewRect.Min.X, View.ViewRect.Min.Y,
|
|
|
|
|
View.ViewRect.Width(), View.ViewRect.Height(),
|
|
|
|
|
View.ViewRect.Size(),
|
|
|
|
|
GSceneRenderTargets.GetBufferSizeXY(),
|
2014-04-23 17:26:59 -04:00
|
|
|
*VertexShader,
|
2014-03-14 14:13:41 -04:00
|
|
|
EDRF_UseTriangleOptimization);
|
|
|
|
|
|
2014-06-12 07:13:34 -04:00
|
|
|
Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FPooledRenderTargetDesc FRCPassPostProcessScreenSpaceReflections::ComputeOutputDesc(EPassOutputId InPassOutputId) const
|
|
|
|
|
{
|
|
|
|
|
FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(GSceneRenderTargets.GetBufferSizeXY(), PF_FloatRGBA, TexCreate_None, TexCreate_RenderTargetable, false));
|
|
|
|
|
|
|
|
|
|
Ret.DebugName = TEXT("ScreenSpaceReflections");
|
|
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-12 18:24:52 -04:00
|
|
|
void ScreenSpaceReflections(FRHICommandListImmediate& RHICmdList, FViewInfo& View, TRefCountPtr<IPooledRenderTarget>& SSROutput)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
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 );
|
|
|
|
|
|
|
|
|
|
FSceneViewState* ViewState = (FSceneViewState*)Context.View.State;
|
|
|
|
|
|
2014-05-06 11:27:50 -04:00
|
|
|
FRenderingCompositePass* SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( GSceneRenderTargets.GetSceneColor() ) );
|
2015-01-09 20:56:36 -05:00
|
|
|
FRenderingCompositePass* HZBInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( View.HZB ) );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
bool bPrevFrame = 0;
|
|
|
|
|
if( ViewState && ViewState->TemporalAAHistoryRT && !Context.View.bCameraCut )
|
|
|
|
|
{
|
|
|
|
|
SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->TemporalAAHistoryRT ) );
|
|
|
|
|
bPrevFrame = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FRenderingCompositePass* TracePass = Context.Graph.RegisterPass( new FRCPassPostProcessScreenSpaceReflections( bPrevFrame ) );
|
|
|
|
|
TracePass->SetInput( ePId_Input0, SceneColorInput );
|
|
|
|
|
TracePass->SetInput( ePId_Input1, HZBInput );
|
|
|
|
|
|
|
|
|
|
Context.FinalOutput = FRenderingCompositeOutputRef( TracePass );
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-20 17:39:20 -04:00
|
|
|
const bool bTemporalFilter = View.FinalPostProcessSettings.AntiAliasingMethod != AAM_TemporalAA || CVarSSRTemporal.GetValueOnRenderThread() != 0;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
if( ViewState && bTemporalFilter )
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
FRenderingCompositeOutputRef HistoryInput;
|
|
|
|
|
if( ViewState && ViewState->SSRHistoryRT && !Context.View.bCameraCut )
|
|
|
|
|
{
|
|
|
|
|
HistoryInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->SSRHistoryRT ) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// No history, use black
|
2014-05-08 09:05:50 -04:00
|
|
|
HistoryInput = Context.Graph.RegisterPass(new FRCPassPostProcessInput(GSystemTextures.BlackDummy));
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRenderingCompositePass* TemporalAAPass = Context.Graph.RegisterPass( new FRCPassPostProcessSSRTemporalAA );
|
|
|
|
|
TemporalAAPass->SetInput( ePId_Input0, Context.FinalOutput );
|
|
|
|
|
TemporalAAPass->SetInput( ePId_Input1, HistoryInput );
|
|
|
|
|
//TemporalAAPass->SetInput( ePId_Input2, VelocityInput );
|
|
|
|
|
|
|
|
|
|
Context.FinalOutput = FRenderingCompositeOutputRef( TemporalAAPass );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( ViewState )
|
|
|
|
|
{
|
|
|
|
|
FRenderingCompositePass* HistoryOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &ViewState->SSRHistoryRT ) );
|
|
|
|
|
HistoryOutput->SetInput( ePId_Input0, Context.FinalOutput );
|
|
|
|
|
|
|
|
|
|
Context.FinalOutput = FRenderingCompositeOutputRef( HistoryOutput );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FRenderingCompositePass* ReflectionOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &SSROutput ) );
|
|
|
|
|
ReflectionOutput->SetInput( ePId_Input0, Context.FinalOutput );
|
|
|
|
|
|
|
|
|
|
Context.FinalOutput = FRenderingCompositeOutputRef( ReflectionOutput );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompositeContext.Root->AddDependency( Context.FinalOutput );
|
|
|
|
|
CompositeContext.Process(TEXT("ReflectionEnvironments"));
|
2015-04-01 07:20:55 -04:00
|
|
|
}
|