Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp
Gil Gribb c7b6303e56 Copying //UE4/Dev-Rendering to Dev-Main (//UE4/Dev-Main)
#lockdown nick.penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2771498 on 2015/11/18 by Rolando.Caloca
	DevRendering - HlslParser - Do not crash if an unknown preprocessor directive is found; add proper support for #pragma
	#codereview Marcus.Wassmer

Change 2771600 on 2015/11/18 by Rolando.Caloca

	DevRendering - SCW - Added support for running the platform shader compiler for one usf file off the dumped usf
	Usage:
	ShaderCompileWorker -directcompile FILENAME.USF -entry=EntryPoint -format=PCD3D_SM5/SF_PS4/etc -vs/-ps/-gs/-hs/-ds/-cs

	-Also removed old communication enum from SCW
	#rb Daniel.Wright

Change 2771647 on 2015/11/18 by Rolando.Caloca

	DevRendering - HlslParser - Refactored removed unused outputs code in prep for reusing a lot of this code
	- Entry point string now gets modified to the optimized one
	- Fixed parser allocator when requesting pages bigger than PageSize
	#rb Chris.Bunner

Change 2772133 on 2015/11/18 by Chris.Bunner

	Removed physics shape type zeroing on Speedtree import. UE-23285
	#rb Ori.Cohen

Change 2772225 on 2015/11/18 by Rolando.Caloca

	DevRendering - Hlsl - Support for removing unused inputs on pixel shaders
	- Fix some shadow variable warnings
	#rb Chris.Bunner, Nick.Penwarden

Change 2772469 on 2015/11/18 by Daniel.Wright

	Fixed SCW always exiting after compiling a long shader, now checks idle time starting from the end of the last compile task
	Automated smoke tests aren't run in standalone programs which are frequently launched as they increase the startup time (doubles startup time of SCW as shown in sampling profile)
	#rb Rolando.Caloca

Change 2772471 on 2015/11/18 by Daniel.Wright

	Particle SubUV cutouts
	* A new asset type 'SubUV Animation' precomputes bounding geometry for every frame of a SubUV texture animation.
	* Particle emitters with a SubUV module can then use this SubUV Animation to render with much tigher bounding geometry to reduce overdraw.
	* GPU performance savings depend on how much empty space (zero alpha) existed in the texture.  Measured a reduction of 2-3x GPU time on a smoke effect.
	* This only works if the material does not modify opacity to reveal areas with zero texture alpha

Change 2772483 on 2015/11/18 by Marcus.Wassmer

	Filtering options on UnrealPak -list
	#rb Josh.Adams

Change 2772644 on 2015/11/18 by Daniel.Wright

	Integrate - Temporal AA dithering is only enabled if outputting to a low precision format
	#rb Nick.Penwarden

Change 2773336 on 2015/11/19 by Rolando.Caloca

	DevRendering - PS4 shaders - Added input/output attribute information when r.PS4StripExtraShaderBinaryData=0
	#rb Marcus.Wassmer

Change 2773476 on 2015/11/19 by Rolando.Caloca

	DevRendering - PS4 Shader attribute export stats
	Run using r.PS4DumpExportStats 1 in the console
	- Also fixed non-vertex shaders not getting optional data
	#codereview Marcus.Wassmer

Change 2773865 on 2015/11/19 by Gil.Gribb

	UE4 - Added an FName churn tracker.

Change 2773900 on 2015/11/19 by Rolando.Caloca

	DevRendering - Fix sharing shaders for material & mesh shaders
	#rb Marcus.Wassmer

Change 2774277 on 2015/11/19 by Gil.Gribb

	UE4 - Did minor optimizations to the PS4 RHI and drawlists.

Change 2774421 on 2015/11/19 by Olaf.Piesche

	Fix #2 for UE-23325 - separate translucency materials don't show in static mesh editor

	#codereview Martin.Mittring

Change 2774447 on 2015/11/19 by Rolando.Caloca

	DevRendering - Velocity and Depth shader pipelines
	#rb Marcus.Wassmer

Change 2774603 on 2015/11/19 by Marcus.Wassmer

	Windowed vsync for ps4
	#rb Rolando.Caloca

Change 2775650 on 2015/11/20 by Rolando.Caloca

	DevRendering - Added two utility overloads per UDN suggestion
	#codereview Gil.Gribb

Change 2775798 on 2015/11/20 by David.Hill

	Adding a new AutoExposure method

	#rb Martin.Mittring

Change 2776345 on 2015/11/20 by Daniel.Wright

	Capsule shadows for movable skylight
	* Gathers capsule occlusion along the unoccluded sky cone computed by Distance Field Ambient Occlusion
	* Requires DFAO to be enabled at the moment
	* Some serious artifacts remaining in indoor scenarios, as the unoccluded sky direction is not continuous

Change 2777033 on 2015/11/22 by Uriel.Doyon

	Enabled SceneTextures node validation when material domain is DeferredDecal
	#review Martin.Mittring
	#jira UE-23141

Change 2778618 on 2015/11/23 by Daniel.Wright
2015-12-10 21:55:37 -05:00

1108 lines
45 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DistanceFieldLightingPost.cpp
=============================================================================*/
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "UniformBuffer.h"
#include "ShaderParameters.h"
#include "PostProcessing.h"
#include "SceneFilterRendering.h"
#include "DistanceFieldLightingShared.h"
#include "DistanceFieldSurfaceCacheLighting.h"
#include "DistanceFieldGlobalIllumination.h"
#include "PostProcessAmbientOcclusion.h"
#include "RHICommandList.h"
#include "SceneUtils.h"
#include "OneColorShader.h"
#include "BasePassRendering.h"
#include "HeightfieldLighting.h"
int32 GAOFillGaps = 1;
FAutoConsoleVariableRef CVarAOFillGaps(
TEXT("r.AOFillGaps"),
GAOFillGaps,
TEXT("Whether to fill in pixels using a screen space filter that had no valid world space interpolation weight from surface cache samples.\n")
TEXT("This is needed whenever r.AOMinLevel is not 0."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
int32 GAOFillGapsHighQuality = 1;
FAutoConsoleVariableRef CVarAOFillGapsHighQuality(
TEXT("r.AOFillGapsHighQuality"),
GAOFillGapsHighQuality,
TEXT("Whether to use the higher quality gap filling method that does a 5x5 gather, or the cheaper method that just looks up the 4 grid samples."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
int32 GAOUseHistory = 1;
FAutoConsoleVariableRef CVarAOUseHistory(
TEXT("r.AOUseHistory"),
GAOUseHistory,
TEXT("Whether to apply a temporal filter to the distance field AO, which reduces flickering but also adds trails when occluders are moving."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
int32 GAOHistoryStabilityPass = 1;
FAutoConsoleVariableRef CVarAOHistoryStabilityPass(
TEXT("r.AOHistoryStabilityPass"),
GAOHistoryStabilityPass,
TEXT("Whether to gather stable results to fill in holes in the temporal reprojection. Adds some GPU cost but improves temporal stability with foliage."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
float GAOHistoryWeight = .85f;
FAutoConsoleVariableRef CVarAOHistoryWeight(
TEXT("r.AOHistoryWeight"),
GAOHistoryWeight,
TEXT("Amount of last frame's AO to lerp into the final result. Higher values increase stability, lower values have less streaking under occluder movement."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
float GAOHistoryDistanceThreshold = 30;
FAutoConsoleVariableRef CVarAOHistoryDistanceThreshold(
TEXT("r.AOHistoryDistanceThreshold"),
GAOHistoryDistanceThreshold,
TEXT("World space distance threshold needed to discard last frame's DFAO results. Lower values reduce ghosting from characters when near a wall but increase flickering artifacts."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
float GAOViewFadeDistanceScale = .7f;
FAutoConsoleVariableRef CVarAOViewFadeDistanceScale(
TEXT("r.AOViewFadeDistanceScale"),
GAOViewFadeDistanceScale,
TEXT("Distance over which AO will fade out as it approaches r.AOMaxViewDistance, as a fraction of r.AOMaxViewDistance."),
ECVF_Cheat | ECVF_RenderThreadSafe
);
template<bool bSupportIrradiance>
class TDistanceFieldAOCombinePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TDistanceFieldAOCombinePS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
OutEnvironment.SetDefine(TEXT("SUPPORT_IRRADIANCE"), bSupportIrradiance ? TEXT("1") : TEXT("0"));
}
/** Default constructor. */
TDistanceFieldAOCombinePS() {}
/** Initialization constructor. */
TDistanceFieldAOCombinePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
AOParameters.Bind(Initializer.ParameterMap);
AOLevelParameters.Bind(Initializer.ParameterMap);
BentNormalAOTexture.Bind(Initializer.ParameterMap,TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(Initializer.ParameterMap,TEXT("BentNormalAOSampler"));
IrradianceTexture.Bind(Initializer.ParameterMap,TEXT("IrradianceTexture"));
IrradianceSampler.Bind(Initializer.ParameterMap,TEXT("IrradianceSampler"));
DistanceFieldNormalTexture.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalTexture"));
DistanceFieldNormalSampler.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalSampler"));
DistanceFadeScale.Bind(Initializer.ParameterMap, TEXT("DistanceFadeScale"));
SelfOcclusionReplacement.Bind(Initializer.ParameterMap, TEXT("SelfOcclusionReplacement"));
}
void SetParameters(
FRHICommandList& RHICmdList,
const FSceneView& View,
FSceneRenderTargetItem& InBentNormalTexture,
IPooledRenderTarget* InIrradianceTexture,
FSceneRenderTargetItem& DistanceFieldNormal,
const FDistanceFieldAOParameters& Parameters)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
AOLevelParameters.Set(RHICmdList, ShaderRHI, View, GAODownsampleFactor);
SetTextureParameter(RHICmdList, ShaderRHI, BentNormalAOTexture, BentNormalAOSampler, TStaticSamplerState<SF_Point>::GetRHI(), InBentNormalTexture.ShaderResourceTexture);
if (IrradianceTexture.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, IrradianceTexture, IrradianceSampler, TStaticSamplerState<SF_Point>::GetRHI(), InIrradianceTexture->GetRenderTargetItem().ShaderResourceTexture);
}
SetTextureParameter(
RHICmdList,
ShaderRHI,
DistanceFieldNormalTexture,
DistanceFieldNormalSampler,
TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
DistanceFieldNormal.ShaderResourceTexture
);
const float DistanceFadeScaleValue = 1.0f / ((1.0f - GAOViewFadeDistanceScale) * GetMaxAOViewDistance());
SetShaderValue(RHICmdList, ShaderRHI, DistanceFadeScale, DistanceFadeScaleValue);
extern float GVPLSelfOcclusionReplacement;
SetShaderValue(RHICmdList, ShaderRHI, SelfOcclusionReplacement, GVPLSelfOcclusionReplacement);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
Ar << AOParameters;
Ar << AOLevelParameters;
Ar << BentNormalAOTexture;
Ar << BentNormalAOSampler;
Ar << IrradianceTexture;
Ar << IrradianceSampler;
Ar << DistanceFieldNormalTexture;
Ar << DistanceFieldNormalSampler;
Ar << DistanceFadeScale;
Ar << SelfOcclusionReplacement;
return bShaderHasOutdatedParameters;
}
private:
FDeferredPixelShaderParameters DeferredParameters;
FAOParameters AOParameters;
FAOLevelParameters AOLevelParameters;
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderResourceParameter IrradianceTexture;
FShaderResourceParameter IrradianceSampler;
FShaderResourceParameter DistanceFieldNormalTexture;
FShaderResourceParameter DistanceFieldNormalSampler;
FShaderParameter DistanceFadeScale;
FShaderParameter SelfOcclusionReplacement;
};
IMPLEMENT_SHADER_TYPE(template<>,TDistanceFieldAOCombinePS<true>,TEXT("DistanceFieldLightingPost"),TEXT("AOCombinePS"),SF_Pixel);
IMPLEMENT_SHADER_TYPE(template<>,TDistanceFieldAOCombinePS<false>,TEXT("DistanceFieldLightingPost"),TEXT("AOCombinePS"),SF_Pixel);
template<bool bSupportIrradiance, bool bHighQuality>
class TFillGapsPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TFillGapsPS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
OutEnvironment.SetDefine(TEXT("SUPPORT_IRRADIANCE"), bSupportIrradiance ? TEXT("1") : TEXT("0"));
OutEnvironment.SetDefine(TEXT("HIGH_QUALITY_FILL_GAPS"), bHighQuality ? TEXT("1") : TEXT("0"));
}
/** Default constructor. */
TFillGapsPS() {}
/** Initialization constructor. */
TFillGapsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
BentNormalAOTexture.Bind(Initializer.ParameterMap, TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(Initializer.ParameterMap, TEXT("BentNormalAOSampler"));
IrradianceTexture.Bind(Initializer.ParameterMap, TEXT("IrradianceTexture"));
IrradianceSampler.Bind(Initializer.ParameterMap, TEXT("IrradianceSampler"));
BentNormalAOTexelSize.Bind(Initializer.ParameterMap, TEXT("BentNormalAOTexelSize"));
MinDownsampleFactorToBaseLevel.Bind(Initializer.ParameterMap, TEXT("MinDownsampleFactorToBaseLevel"));
}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FSceneRenderTargetItem& DistanceFieldAOBentNormal2, IPooledRenderTarget* DistanceFieldIrradiance2)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
SetTextureParameter(
RHICmdList,
ShaderRHI,
BentNormalAOTexture,
BentNormalAOSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
DistanceFieldAOBentNormal2.ShaderResourceTexture
);
if (IrradianceTexture.IsBound())
{
SetTextureParameter(
RHICmdList,
ShaderRHI,
IrradianceTexture,
IrradianceSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
DistanceFieldIrradiance2->GetRenderTargetItem().ShaderResourceTexture
);
}
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
const FIntPoint DownsampledBufferSize(SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor));
const FVector2D BaseLevelTexelSizeValue(1.0f / DownsampledBufferSize.X, 1.0f / DownsampledBufferSize.Y);
SetShaderValue(RHICmdList, ShaderRHI, BentNormalAOTexelSize, BaseLevelTexelSizeValue);
extern int32 GAOMinLevel;
extern int32 GAOPowerOfTwoBetweenLevels;
const float MinDownsampleFactor = 1 << (GAOMinLevel * GAOPowerOfTwoBetweenLevels);
SetShaderValue(RHICmdList, ShaderRHI, MinDownsampleFactorToBaseLevel, MinDownsampleFactor);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << BentNormalAOTexture;
Ar << BentNormalAOSampler;
Ar << IrradianceTexture;
Ar << IrradianceSampler;
Ar << BentNormalAOTexelSize;
Ar << MinDownsampleFactorToBaseLevel;
return bShaderHasOutdatedParameters;
}
private:
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderResourceParameter IrradianceTexture;
FShaderResourceParameter IrradianceSampler;
FShaderParameter BentNormalAOTexelSize;
FShaderParameter MinDownsampleFactorToBaseLevel;
};
#define IMPLEMENT_FILLGAPS_PS_TYPE(bSupportIrradiance,bHighQuality) \
typedef TFillGapsPS<bSupportIrradiance, bHighQuality> TFillGapsPS##bSupportIrradiance##bHighQuality; \
IMPLEMENT_SHADER_TYPE(template<>,TFillGapsPS##bSupportIrradiance##bHighQuality,TEXT("DistanceFieldLightingPost"),TEXT("FillGapsPS"),SF_Pixel);
IMPLEMENT_FILLGAPS_PS_TYPE(true, true);
IMPLEMENT_FILLGAPS_PS_TYPE(true, false);
IMPLEMENT_FILLGAPS_PS_TYPE(false, true);
IMPLEMENT_FILLGAPS_PS_TYPE(false, false);
template<bool bSupportIrradiance>
class TUpdateHistoryPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TUpdateHistoryPS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
OutEnvironment.SetDefine(TEXT("SUPPORT_IRRADIANCE"), bSupportIrradiance ? TEXT("1") : TEXT("0"));
}
/** Default constructor. */
TUpdateHistoryPS() {}
/** Initialization constructor. */
TUpdateHistoryPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
BentNormalAOTexture.Bind(Initializer.ParameterMap, TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(Initializer.ParameterMap, TEXT("BentNormalAOSampler"));
BentNormalHistoryTexture.Bind(Initializer.ParameterMap, TEXT("BentNormalHistoryTexture"));
BentNormalHistorySampler.Bind(Initializer.ParameterMap, TEXT("BentNormalHistorySampler"));
IrradianceTexture.Bind(Initializer.ParameterMap, TEXT("IrradianceTexture"));
IrradianceSampler.Bind(Initializer.ParameterMap, TEXT("IrradianceSampler"));
IrradianceHistoryTexture.Bind(Initializer.ParameterMap, TEXT("IrradianceHistoryTexture"));
IrradianceHistorySampler.Bind(Initializer.ParameterMap, TEXT("IrradianceHistorySampler"));
HistoryWeight.Bind(Initializer.ParameterMap, TEXT("HistoryWeight"));
HistoryDistanceThreshold.Bind(Initializer.ParameterMap, TEXT("HistoryDistanceThreshold"));
UseHistoryFilter.Bind(Initializer.ParameterMap, TEXT("UseHistoryFilter"));
VelocityTexture.Bind(Initializer.ParameterMap, TEXT("VelocityTexture"));
VelocityTextureSampler.Bind(Initializer.ParameterMap, TEXT("VelocityTextureSampler"));
}
void SetParameters(
FRHICommandList& RHICmdList,
const FSceneView& View,
FSceneRenderTargetItem& BentNormalHistoryTextureValue,
TRefCountPtr<IPooledRenderTarget>* IrradianceHistoryRT,
FSceneRenderTargetItem& DistanceFieldAOBentNormal,
IPooledRenderTarget* DistanceFieldIrradiance,
IPooledRenderTarget* VelocityTextureValue)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
SetTextureParameter(
RHICmdList,
ShaderRHI,
BentNormalAOTexture,
BentNormalAOSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
DistanceFieldAOBentNormal.ShaderResourceTexture
);
SetTextureParameter(
RHICmdList,
ShaderRHI,
BentNormalHistoryTexture,
BentNormalHistorySampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
BentNormalHistoryTextureValue.ShaderResourceTexture
);
if (IrradianceTexture.IsBound())
{
SetTextureParameter(
RHICmdList,
ShaderRHI,
IrradianceTexture,
IrradianceSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
DistanceFieldIrradiance->GetRenderTargetItem().ShaderResourceTexture
);
}
if (IrradianceHistoryTexture.IsBound())
{
SetTextureParameter(
RHICmdList,
ShaderRHI,
IrradianceHistoryTexture,
IrradianceHistorySampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
(*IrradianceHistoryRT)->GetRenderTargetItem().ShaderResourceTexture
);
}
SetUniformBufferParameter(RHICmdList, ShaderRHI, GetUniformBufferParameter<FCameraMotionParameters>(), CreateCameraMotionParametersUniformBuffer(View));
SetShaderValue(RHICmdList, ShaderRHI, HistoryWeight, GAOHistoryWeight);
SetShaderValue(RHICmdList, ShaderRHI, HistoryDistanceThreshold, GAOHistoryDistanceThreshold);
SetShaderValue(RHICmdList, ShaderRHI, UseHistoryFilter, (GAOHistoryStabilityPass ? 1.0f : 0.0f));
SetTextureParameter(
RHICmdList,
ShaderRHI,
VelocityTexture,
VelocityTextureSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
VelocityTextureValue ? VelocityTextureValue->GetRenderTargetItem().ShaderResourceTexture : GBlackTexture->TextureRHI
);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar)
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
Ar << BentNormalAOTexture;
Ar << BentNormalAOSampler;
Ar << BentNormalHistoryTexture;
Ar << BentNormalHistorySampler;
Ar << IrradianceTexture;
Ar << IrradianceSampler;
Ar << IrradianceHistoryTexture;
Ar << IrradianceHistorySampler;
Ar << HistoryWeight;
Ar << HistoryDistanceThreshold;
Ar << UseHistoryFilter;
Ar << VelocityTexture;
Ar << VelocityTextureSampler;
return bShaderHasOutdatedParameters;
}
private:
FDeferredPixelShaderParameters DeferredParameters;
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderResourceParameter BentNormalHistoryTexture;
FShaderResourceParameter BentNormalHistorySampler;
FShaderResourceParameter IrradianceTexture;
FShaderResourceParameter IrradianceSampler;
FShaderResourceParameter IrradianceHistoryTexture;
FShaderResourceParameter IrradianceHistorySampler;
FShaderParameter HistoryWeight;
FShaderParameter HistoryDistanceThreshold;
FShaderParameter UseHistoryFilter;
FShaderResourceParameter VelocityTexture;
FShaderResourceParameter VelocityTextureSampler;
};
IMPLEMENT_SHADER_TYPE(template<>,TUpdateHistoryPS<true>,TEXT("DistanceFieldLightingPost"),TEXT("UpdateHistoryPS"),SF_Pixel);
IMPLEMENT_SHADER_TYPE(template<>,TUpdateHistoryPS<false>,TEXT("DistanceFieldLightingPost"),TEXT("UpdateHistoryPS"),SF_Pixel);
template<bool bSupportIrradiance>
class TFilterHistoryPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TFilterHistoryPS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
OutEnvironment.SetDefine(TEXT("SUPPORT_IRRADIANCE"), bSupportIrradiance ? TEXT("1") : TEXT("0"));
}
/** Default constructor. */
TFilterHistoryPS() {}
/** Initialization constructor. */
TFilterHistoryPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
BentNormalAOTexture.Bind(Initializer.ParameterMap, TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(Initializer.ParameterMap, TEXT("BentNormalAOSampler"));
IrradianceTexture.Bind(Initializer.ParameterMap, TEXT("IrradianceTexture"));
IrradianceSampler.Bind(Initializer.ParameterMap, TEXT("IrradianceSampler"));
HistoryWeight.Bind(Initializer.ParameterMap, TEXT("HistoryWeight"));
BentNormalAOTexelSize.Bind(Initializer.ParameterMap, TEXT("BentNormalAOTexelSize"));
}
void SetParameters(
FRHICommandList& RHICmdList,
const FSceneView& View,
FSceneRenderTargetItem& BentNormalHistoryTextureValue,
IPooledRenderTarget* IrradianceHistoryRT)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
SetTextureParameter(
RHICmdList,
ShaderRHI,
BentNormalAOTexture,
BentNormalAOSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
BentNormalHistoryTextureValue.ShaderResourceTexture
);
if (IrradianceTexture.IsBound())
{
SetTextureParameter(
RHICmdList,
ShaderRHI,
IrradianceTexture,
IrradianceSampler,
TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
IrradianceHistoryRT->GetRenderTargetItem().ShaderResourceTexture
);
}
SetShaderValue(RHICmdList, ShaderRHI, HistoryWeight, GAOHistoryWeight);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
const FIntPoint DownsampledBufferSize(SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor));
const FVector2D BaseLevelTexelSizeValue(1.0f / DownsampledBufferSize.X, 1.0f / DownsampledBufferSize.Y);
SetShaderValue(RHICmdList, ShaderRHI, BentNormalAOTexelSize, BaseLevelTexelSizeValue);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar)
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << BentNormalAOTexture;
Ar << BentNormalAOSampler;
Ar << IrradianceTexture;
Ar << IrradianceSampler;
Ar << HistoryWeight;
Ar << BentNormalAOTexelSize;
return bShaderHasOutdatedParameters;
}
private:
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderResourceParameter IrradianceTexture;
FShaderResourceParameter IrradianceSampler;
FShaderParameter HistoryWeight;
FShaderParameter BentNormalAOTexelSize;
};
IMPLEMENT_SHADER_TYPE(template<>,TFilterHistoryPS<true>,TEXT("DistanceFieldLightingPost"),TEXT("FilterHistoryPS"),SF_Pixel);
IMPLEMENT_SHADER_TYPE(template<>,TFilterHistoryPS<false>,TEXT("DistanceFieldLightingPost"),TEXT("FilterHistoryPS"),SF_Pixel);
void AllocateOrReuseAORenderTarget(FRHICommandList& RHICmdList, TRefCountPtr<IPooledRenderTarget>& Target, const TCHAR* Name, bool bWithAlphaOrFP16Precision)
{
if (!Target)
{
FIntPoint BufferSize = GetBufferSizeForAO();
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, bWithAlphaOrFP16Precision ? PF_FloatRGBA : PF_FloatRGB, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false));
Desc.AutoWritable = false;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, Target, Name);
}
}
void UpdateHistory(
FRHICommandList& RHICmdList,
const FViewInfo& View,
const TCHAR* BentNormalHistoryRTName,
const TCHAR* IrradianceHistoryRTName,
IPooledRenderTarget* VelocityTexture,
/** Contains last frame's history, if non-NULL. This will be updated with the new frame's history. */
TRefCountPtr<IPooledRenderTarget>* BentNormalHistoryState,
TRefCountPtr<IPooledRenderTarget>* IrradianceHistoryState,
/** Source */
TRefCountPtr<IPooledRenderTarget>& BentNormalSource,
TRefCountPtr<IPooledRenderTarget>& IrradianceSource,
/** Output of Temporal Reprojection for the next step in the pipeline. */
TRefCountPtr<IPooledRenderTarget>& BentNormalHistoryOutput,
TRefCountPtr<IPooledRenderTarget>& IrradianceHistoryOutput)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
if (BentNormalHistoryState)
{
const bool bUseDistanceFieldGI = IsDistanceFieldGIAllowed(View);
if (*BentNormalHistoryState
&& !View.bCameraCut
&& !View.bPrevTransformsReset
&& (!bUseDistanceFieldGI || (IrradianceHistoryState && *IrradianceHistoryState)))
{
// Reuse a render target from the pool with a consistent name, for vis purposes
TRefCountPtr<IPooledRenderTarget> NewBentNormalHistory;
AllocateOrReuseAORenderTarget(RHICmdList, NewBentNormalHistory, BentNormalHistoryRTName, true);
TRefCountPtr<IPooledRenderTarget> NewIrradianceHistory;
if (bUseDistanceFieldGI)
{
AllocateOrReuseAORenderTarget(RHICmdList, NewIrradianceHistory, IrradianceHistoryRTName, false);
}
SCOPED_DRAW_EVENT(RHICmdList, UpdateHistory);
{
FTextureRHIParamRef RenderTargets[2] =
{
NewBentNormalHistory->GetRenderTargetItem().TargetableTexture,
bUseDistanceFieldGI ? NewIrradianceHistory->GetRenderTargetItem().TargetableTexture : NULL,
};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets) - (bUseDistanceFieldGI ? 0 : 1), RenderTargets, FTextureRHIParamRef(), 0, NULL);
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
if (bUseDistanceFieldGI)
{
TShaderMapRef<TUpdateHistoryPS<true> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, (*BentNormalHistoryState)->GetRenderTargetItem(), IrradianceHistoryState, BentNormalSource->GetRenderTargetItem(), IrradianceSource, VelocityTexture);
}
else
{
TShaderMapRef<TUpdateHistoryPS<false> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, (*BentNormalHistoryState)->GetRenderTargetItem(), IrradianceHistoryState, BentNormalSource->GetRenderTargetItem(), IrradianceSource, VelocityTexture);
}
VertexShader->SetParameters(RHICmdList, View);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
View.ViewRect.Min.X / GAODownsampleFactor, View.ViewRect.Min.Y / GAODownsampleFactor,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
*VertexShader);
RHICmdList.CopyToResolveTarget(NewBentNormalHistory->GetRenderTargetItem().TargetableTexture, NewBentNormalHistory->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
if (bUseDistanceFieldGI)
{
RHICmdList.CopyToResolveTarget(NewIrradianceHistory->GetRenderTargetItem().TargetableTexture, NewIrradianceHistory->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
}
}
if (GAOHistoryStabilityPass)
{
const FPooledRenderTargetDesc& HistoryDesc = (*BentNormalHistoryState)->GetDesc();
// Reallocate history if buffer sizes have changed
if (HistoryDesc.Extent != SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor))
{
GRenderTargetPool.FreeUnusedResource(*BentNormalHistoryState);
*BentNormalHistoryState = NULL;
// Update the view state's render target reference with the new history
AllocateOrReuseAORenderTarget(RHICmdList, *BentNormalHistoryState, BentNormalHistoryRTName, true);
if (bUseDistanceFieldGI)
{
GRenderTargetPool.FreeUnusedResource(*IrradianceHistoryState);
*IrradianceHistoryState = NULL;
AllocateOrReuseAORenderTarget(RHICmdList, *IrradianceHistoryState, IrradianceHistoryRTName, false);
}
}
{
FTextureRHIParamRef RenderTargets[2] =
{
(*BentNormalHistoryState)->GetRenderTargetItem().TargetableTexture,
bUseDistanceFieldGI ? (*IrradianceHistoryState)->GetRenderTargetItem().TargetableTexture : NULL,
};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets) - (bUseDistanceFieldGI ? 0 : 1), RenderTargets, FTextureRHIParamRef(), 0, NULL, true);
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
if (bUseDistanceFieldGI)
{
TShaderMapRef<TFilterHistoryPS<true> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, NewBentNormalHistory->GetRenderTargetItem(), NewIrradianceHistory);
}
else
{
TShaderMapRef<TFilterHistoryPS<false> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, NewBentNormalHistory->GetRenderTargetItem(), NewIrradianceHistory);
}
VertexShader->SetParameters(RHICmdList, View);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
*VertexShader);
RHICmdList.CopyToResolveTarget((*BentNormalHistoryState)->GetRenderTargetItem().TargetableTexture, (*BentNormalHistoryState)->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
if (bUseDistanceFieldGI)
{
RHICmdList.CopyToResolveTarget((*IrradianceHistoryState)->GetRenderTargetItem().TargetableTexture, (*IrradianceHistoryState)->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
}
}
BentNormalHistoryOutput = *BentNormalHistoryState;
IrradianceHistoryOutput = *IrradianceHistoryState;
}
else
{
// Update the view state's render target reference with the new history
*BentNormalHistoryState = NewBentNormalHistory;
BentNormalHistoryOutput = NewBentNormalHistory;
*IrradianceHistoryState = NewIrradianceHistory;
IrradianceHistoryOutput = NewIrradianceHistory;
}
}
else
{
// Use the current frame's mask for next frame's history
*BentNormalHistoryState = BentNormalSource;
BentNormalHistoryOutput = BentNormalSource;
BentNormalSource = NULL;
*IrradianceHistoryState = IrradianceSource;
IrradianceHistoryOutput = IrradianceSource;
IrradianceSource = NULL;
}
}
else
{
// Temporal reprojection is disabled or there is no view state - pass through
BentNormalHistoryOutput = BentNormalSource;
IrradianceHistoryOutput = IrradianceSource;
}
}
void PostProcessBentNormalAOSurfaceCache(
FRHICommandList& RHICmdList,
const FDistanceFieldAOParameters& Parameters,
const FViewInfo& View,
IPooledRenderTarget* VelocityTexture,
FSceneRenderTargetItem& BentNormalInterpolation,
IPooledRenderTarget* IrradianceInterpolation,
FSceneRenderTargetItem& DistanceFieldNormal,
TRefCountPtr<IPooledRenderTarget>& BentNormalOutput,
TRefCountPtr<IPooledRenderTarget>& IrradianceOutput)
{
const bool bUseDistanceFieldGI = IsDistanceFieldGIAllowed(View);
TRefCountPtr<IPooledRenderTarget> DistanceFieldAOBentNormal;
TRefCountPtr<IPooledRenderTarget> DistanceFieldIrradiance;
AllocateOrReuseAORenderTarget(RHICmdList, DistanceFieldAOBentNormal, TEXT("DistanceFieldBentNormalAO"), true);
if (bUseDistanceFieldGI)
{
AllocateOrReuseAORenderTarget(RHICmdList, DistanceFieldIrradiance, TEXT("DistanceFieldIrradiance"), false);
}
TRefCountPtr<IPooledRenderTarget> DistanceFieldAOBentNormal2;
TRefCountPtr<IPooledRenderTarget> DistanceFieldIrradiance2;
if (GAOFillGaps)
{
AllocateOrReuseAORenderTarget(RHICmdList, DistanceFieldAOBentNormal2, TEXT("DistanceFieldBentNormalAO2"), true);
if (bUseDistanceFieldGI)
{
AllocateOrReuseAORenderTarget(RHICmdList, DistanceFieldIrradiance2, TEXT("DistanceFieldIrradiance2"), false);
}
}
{
SCOPED_DRAW_EVENT(RHICmdList, AOCombine);
TRefCountPtr<IPooledRenderTarget> EffectiveDiffuseIrradianceTarget;
if (bUseDistanceFieldGI)
{
EffectiveDiffuseIrradianceTarget = GAOFillGaps ? DistanceFieldIrradiance2 : DistanceFieldIrradiance;
}
FSceneRenderTargetItem& EffectiveBentNormalTarget = GAOFillGaps ? DistanceFieldAOBentNormal2->GetRenderTargetItem() : DistanceFieldAOBentNormal->GetRenderTargetItem();
FTextureRHIParamRef RenderTargets[2] =
{
EffectiveBentNormalTarget.TargetableTexture,
EffectiveDiffuseIrradianceTarget ? EffectiveDiffuseIrradianceTarget->GetRenderTargetItem().TargetableTexture : NULL,
};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets) - (bUseDistanceFieldGI ? 0 : 1), RenderTargets, FTextureRHIParamRef(), 0, NULL);
{
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
if (bUseDistanceFieldGI)
{
TShaderMapRef<TDistanceFieldAOCombinePS<true> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, BentNormalInterpolation, IrradianceInterpolation, DistanceFieldNormal, Parameters);
}
else
{
TShaderMapRef<TDistanceFieldAOCombinePS<false> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, BentNormalInterpolation, IrradianceInterpolation, DistanceFieldNormal, Parameters);
}
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
GetBufferSizeForAO(),
*VertexShader);
}
RHICmdList.CopyToResolveTarget(EffectiveBentNormalTarget.TargetableTexture, EffectiveBentNormalTarget.ShaderResourceTexture, false, FResolveParams());
if (bUseDistanceFieldGI)
{
RHICmdList.CopyToResolveTarget(EffectiveDiffuseIrradianceTarget->GetRenderTargetItem().TargetableTexture, EffectiveDiffuseIrradianceTarget->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
}
}
if (GAOFillGaps)
{
SCOPED_DRAW_EVENT(RHICmdList, FillGaps);
FTextureRHIParamRef RenderTargets[2] =
{
DistanceFieldAOBentNormal->GetRenderTargetItem().TargetableTexture,
bUseDistanceFieldGI ? DistanceFieldIrradiance->GetRenderTargetItem().TargetableTexture : NULL,
};
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets) - (bUseDistanceFieldGI ? 0 : 1), RenderTargets, FTextureRHIParamRef(), 0, NULL);
{
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
if (GAOFillGapsHighQuality)
{
if (bUseDistanceFieldGI)
{
TShaderMapRef<TFillGapsPS<true, true> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal2->GetRenderTargetItem(), DistanceFieldIrradiance2);
}
else
{
TShaderMapRef<TFillGapsPS<false, true> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal2->GetRenderTargetItem(), DistanceFieldIrradiance2);
}
}
else
{
if (bUseDistanceFieldGI)
{
TShaderMapRef<TFillGapsPS<true, false> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal2->GetRenderTargetItem(), DistanceFieldIrradiance2);
}
else
{
TShaderMapRef<TFillGapsPS<false, false> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal2->GetRenderTargetItem(), DistanceFieldIrradiance2);
}
}
VertexShader->SetParameters(RHICmdList, View);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
SceneContext.GetBufferSizeXY() / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
*VertexShader);
}
RHICmdList.CopyToResolveTarget(DistanceFieldAOBentNormal->GetRenderTargetItem().TargetableTexture, DistanceFieldAOBentNormal->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
if (bUseDistanceFieldGI)
{
RHICmdList.CopyToResolveTarget(DistanceFieldIrradiance->GetRenderTargetItem().TargetableTexture, DistanceFieldIrradiance->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
}
}
FSceneViewState* ViewState = View.ViewState;
TRefCountPtr<IPooledRenderTarget>* BentNormalHistoryState = ViewState ? &ViewState->DistanceFieldAOHistoryRT : NULL;
TRefCountPtr<IPooledRenderTarget>* IrradianceHistoryState = ViewState ? &ViewState->DistanceFieldIrradianceHistoryRT : NULL;
BentNormalOutput = DistanceFieldAOBentNormal;
IrradianceOutput = DistanceFieldIrradiance;
if (GAOUseHistory)
{
UpdateHistory(
RHICmdList,
View,
TEXT("DistanceFieldAOHistory"),
TEXT("DistanceFieldIrradianceHistory"),
VelocityTexture,
BentNormalHistoryState,
IrradianceHistoryState,
DistanceFieldAOBentNormal,
DistanceFieldIrradiance,
BentNormalOutput,
IrradianceOutput);
}
}
enum EAOUpsampleType
{
AOUpsample_OutputBentNormal,
AOUpsample_OutputAO,
AOUpsample_OutputBentNormalAndIrradiance,
AOUpsample_OutputIrradiance
};
template<EAOUpsampleType UpsampleType>
class TDistanceFieldAOUpsamplePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TDistanceFieldAOUpsamplePS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
OutEnvironment.SetDefine(TEXT("OUTPUT_BENT_NORMAL"), (UpsampleType == AOUpsample_OutputBentNormal || UpsampleType == AOUpsample_OutputBentNormalAndIrradiance) ? TEXT("1") : TEXT("0"));
OutEnvironment.SetDefine(TEXT("SUPPORT_IRRADIANCE"), (UpsampleType == AOUpsample_OutputIrradiance || UpsampleType == AOUpsample_OutputBentNormalAndIrradiance) ? TEXT("1") : TEXT("0"));
OutEnvironment.SetDefine(TEXT("OUTPUT_AO"), (UpsampleType == AOUpsample_OutputAO) ? TEXT("1") : TEXT("0"));
}
/** Default constructor. */
TDistanceFieldAOUpsamplePS() {}
/** Initialization constructor. */
TDistanceFieldAOUpsamplePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
BentNormalAOTexture.Bind(Initializer.ParameterMap,TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(Initializer.ParameterMap,TEXT("BentNormalAOSampler"));
IrradianceTexture.Bind(Initializer.ParameterMap,TEXT("IrradianceTexture"));
IrradianceSampler.Bind(Initializer.ParameterMap,TEXT("IrradianceSampler"));
}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, TRefCountPtr<IPooledRenderTarget>& DistanceFieldAOBentNormal, IPooledRenderTarget* DistanceFieldIrradiance)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
SetTextureParameter(RHICmdList, ShaderRHI, BentNormalAOTexture, BentNormalAOSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), DistanceFieldAOBentNormal->GetRenderTargetItem().ShaderResourceTexture);
if (IrradianceTexture.IsBound())
{
SetTextureParameter(RHICmdList, ShaderRHI, IrradianceTexture, IrradianceSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), DistanceFieldIrradiance->GetRenderTargetItem().ShaderResourceTexture);
}
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
Ar << BentNormalAOTexture;
Ar << BentNormalAOSampler;
Ar << IrradianceTexture;
Ar << IrradianceSampler;
return bShaderHasOutdatedParameters;
}
private:
FDeferredPixelShaderParameters DeferredParameters;
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderResourceParameter IrradianceTexture;
FShaderResourceParameter IrradianceSampler;
};
#define IMPLEMENT_UPSAMPLE_PS_TYPE(UpsampleType) \
typedef TDistanceFieldAOUpsamplePS<UpsampleType> TDistanceFieldAOUpsamplePS##UpsampleType; \
IMPLEMENT_SHADER_TYPE(template<>,TDistanceFieldAOUpsamplePS##UpsampleType,TEXT("DistanceFieldLightingPost"),TEXT("AOUpsamplePS"),SF_Pixel);
IMPLEMENT_UPSAMPLE_PS_TYPE(AOUpsample_OutputBentNormal)
IMPLEMENT_UPSAMPLE_PS_TYPE(AOUpsample_OutputAO)
IMPLEMENT_UPSAMPLE_PS_TYPE(AOUpsample_OutputBentNormalAndIrradiance)
IMPLEMENT_UPSAMPLE_PS_TYPE(AOUpsample_OutputIrradiance)
void UpsampleBentNormalAO(
FRHICommandList& RHICmdList,
const TArray<FViewInfo>& Views,
TRefCountPtr<IPooledRenderTarget>& DistanceFieldAOBentNormal,
TRefCountPtr<IPooledRenderTarget>& DistanceFieldIrradiance,
bool bVisualizeAmbientOcclusion,
bool bVisualizeGlobalIllumination)
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
const bool bUseDistanceFieldGI = IsDistanceFieldGIAllowed(View);
SCOPED_DRAW_EVENT(RHICmdList, UpsampleAO);
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
if (bVisualizeAmbientOcclusion)
{
TShaderMapRef<TDistanceFieldAOUpsamplePS<AOUpsample_OutputAO> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal, DistanceFieldIrradiance);
}
else if (bVisualizeGlobalIllumination && bUseDistanceFieldGI)
{
TShaderMapRef<TDistanceFieldAOUpsamplePS<AOUpsample_OutputIrradiance> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal, DistanceFieldIrradiance);
}
else
{
if (bUseDistanceFieldGI)
{
TShaderMapRef<TDistanceFieldAOUpsamplePS<AOUpsample_OutputBentNormalAndIrradiance> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal, DistanceFieldIrradiance);
}
else
{
TShaderMapRef<TDistanceFieldAOUpsamplePS<AOUpsample_OutputBentNormal> > PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(RHICmdList, View, DistanceFieldAOBentNormal, DistanceFieldIrradiance);
}
}
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
View.ViewRect.Min.X / GAODownsampleFactor, View.ViewRect.Min.Y / GAODownsampleFactor,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
GetBufferSizeForAO(),
*VertexShader);
}
}