Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSubsurface.cpp
Gil Gribb 2cf40e541e Copying //UE4/Dev-Rendering to //UE4/Dev-Main (Source: //UE4/Dev-Rendering @ 3091903)
#lockdown Nick.Penwarden
#rb none

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

Change 3072947 on 2016/08/01 by Uriel.Doyon

	Texture GUIDs are now included in cooked builds, as they are required by the texture streamer to link build data to in game texture.
	#review-3072934 @marcus.wassmer
	#jira UE-34045

Change 3073301 on 2016/08/02 by Ben.Woodhouse

	Fix for large spotlight culling precision issues, reported on UDN by Aaron Jacobs at Double Fine. For a full description, see the UDN post
	https://udn.unrealengine.com/questions/305440/shadowed-light-flicker-caused-by-floating-point-pr.html
	#jira UE-34052

Change 3073689 on 2016/08/02 by Ben.Woodhouse

	Improved skin postprocess - support for full resolution, with diffuse/spec lighting combined into single RGBA (sharing chroma)

	Full res lighting gives less temporal AA flickering, sharper diffuse and specular lighting in the surface (since this is now at full resolution), faster postprocessing if using a 64-bit rendertarget (on NV 980Ti).

	Checkerboard rendering is controlled via the r.sss.checkerboard cvar. - 0 is off/full res, 1 is checkerboard, 2 is automatic based on scenecolor (non-checkerboard requires 64bit or more rendertarget w/separate alpha)

	Tested/profiled on PC, PS4

Change 3074666 on 2016/08/02 by Daniel.Wright

	Fixed stationary skylight brightness

Change 3074667 on 2016/08/02 by Daniel.Wright

	Fixed r.ReflectionEnvironmentLightmapMixing

Change 3074687 on 2016/08/02 by Daniel.Wright

	Disallowed DrawMaterialToRenderTarget and Begin/EndDrawCanvasToRenderTarget in construction scripts, since they don't work in game.  Blutilities can be used to do blueprint rendering in the editor.

Change 3075241 on 2016/08/03 by Rolando.Caloca

	DR - Fix linux compile issue & static analysis warning

Change 3075746 on 2016/08/03 by Daniel.Wright

	Removed bOverride_AntiAliasingMethod and outdated ini references to PP AntiAliasingMethod

Change 3075783 on 2016/08/03 by Ryan.Brucks

	#code.review Marcus.Wassmer

	Added two material nodes that return Atmospheric Light Vector and Light Direction using:

	View.AtmosphericFogSunColor
	View.AtmosphericFogSunDirection

	Nodes are called:
	AtmosphericLightVector
	AtmosphericLightColor

	Also changed SceneRendering.cpp so that values will be grabbed from directional lights without needing an Atmospheric Fog actor in the scene.

Change 3075969 on 2016/08/03 by Uriel.Doyon

	Material GUIDs are not updated anymore when parents or textures change.
	Lighting now uses a hash built from the list of parents, textures and shader functions.
	#review-3072980 @marcus.wassmer @daniel.wright

Change 3076116 on 2016/08/03 by Ryan.Brucks

	#code.review marcus.wassmer
	Fixed typo in the Caption of new Nodes "Atmospheric Light Vector" and "Atmospheric Light Color"

Change 3076456 on 2016/08/03 by Rolando.Caloca

	DR - Fix geometry shader gl_Layer for SPIR-V

Change 3076730 on 2016/08/03 by Uriel.Doyon

	Added user warning logic for the texture streaming build. Ran in MapCheck, BeginPlay and PreSave.
	#review-3072984 @marcus.wassmer

Change 3077616 on 2016/08/04 by Daniel.Wright

	Planar reflection show flags can now be edited

Change 3077621 on 2016/08/04 by Daniel.Wright

	Changed default Planar Reflection DistanceFromPlaneFadeoutEnd from 600 to 100, which reduces artifacts and is a more intuitive initial setting

Change 3077792 on 2016/08/04 by Daniel.Wright

	Fixed an unnecessary sky capture caused by the sky light component owned by the default ASkyLight

Change 3077799 on 2016/08/04 by Daniel.Wright

	Skip RF_ArchetypeObject for reflection captures

Change 3077876 on 2016/08/04 by Marc.Olano

	Noise material perf improvements

	Change random number generator for Gradient-ALU (1.7x perf boost), improve speed of Voronoi noise quality level 3.

	Removes integer BBS random number generators. Fewer instructions, but too slow to use (see 1.7x perf boost above)

Change 3077884 on 2016/08/04 by Daniel.Wright

	Lighting channels can now be edited on components with static mobility, since dynamic lights can still affect them

Change 3078994 on 2016/08/05 by Simon.Tovey

	Fix for UE-34241
	Scene proxy ptr was being cached during a downcast.
	Inside a call to CreateDynamicData, CheckMaterialUsage_Concurrent() was causing the scene proxy to be recreated an so the cached ptr was stale.
	I've fixed the immediate issue but recreating the scene proxy here doesn't seem great. Maybe CheckMaterailUsage() should be rethought a bit.

Change 3079162 on 2016/08/05 by Ben.Woodhouse

	Fix for jittering in Paper2D. Was caused by override being ignored due to a change in intiialization order for AA settings.
	#jira UE-34091

Change 3079613 on 2016/08/05 by Daniel.Wright

	New blueprint function ClearRenderTarget2D, which is the only way to set a render target alpha directly
	New blueprint function CreateRenderTarget2D

Change 3079708 on 2016/08/05 by Uriel.Doyon

	Fixed crash when building texture streaming on some levels.

Change 3079795 on 2016/08/05 by Uriel.Doyon

	Fixed issue with instanced static meshes when building texture streaming.
	Fixed typo with func "GetNumTextureStreamingPrimitives"

Change 3079806 on 2016/08/05 by Uriel.Doyon

	Enabled PerTexture MipBias. The per texture mip bias now resets to 0 when the texture gets required at low resolution.
	New scalability setting named "r.Streaming.LimitPoolSizeToVRAM" enabling the PoolSize to be limited the available VRAM
	(according to GPoolSizeVRAMPercentage)
	#review-3074662 @marcus.wassmer

Change 3082698 on 2016/08/09 by Daniel.Wright

	Copy - CreateRenderTarget2D uses a world context object as owner, allows use in a construction script

Change 3082699 on 2016/08/09 by Daniel.Wright

	Changed display name for 'Two Sided' shading model to 'Two Sided Foliage' to make it clear what it's intended to be used for

Change 3083909 on 2016/08/10 by Olaf.Piesche

	#jira UE-34106
	#jira UE-32784
	#jira UE-31198

	Reset vertex factories on mesh emitters if mesh has been reimported (if mesh package is dirty)

Change 3084645 on 2016/08/10 by Olaf.Piesche

	#jira UE-30398

	Fix offset added to particle collision locations.

Change 3084709 on 2016/08/10 by Daniel.Wright

	Copy - Scene capture alpha is now inverted to match DrawMaterialToRenderTarget, and to allow compositing with existing render target contents
	Added CompositeMode to SceneCapture2D, which can be used to addively accumulate or composite instead of the default overwrite behavior
	Added bCaptureOnMovement to SceneCapture, which can be disabled so the only source of scene capturing is a manual capture by calling CaptureScene()

Change 3084783 on 2016/08/10 by Rolando.Caloca

	DR - Use the first targeted rhi shader platform as the initial RHI to load on Windows
	#jira UE-34510

Change 3084958 on 2016/08/10 by Daniel.Wright

	Copy - Reverted cl 2938543 "Lightmass now respects owner bHidden, and bCastHiddenShadow" because it did not have backwards compatibility so breaks content using hidden light cards

Change 3086023 on 2016/08/11 by Marcus.Wassmer

	Merging //UE4/Dev-Main@3085468 to Dev-Rendering (//UE4/Dev-Rendering)
	#test none

Change 3086778 on 2016/08/11 by Ben.Woodhouse

	Workaround for fortnite character rendering issue. Enable checkerboard rendering by default until we can fix properly
	#jira UE-34561

Change 3087404 on 2016/08/12 by Rolando.Caloca

	DR - Upgrade glslang to 1.0.21.1
	- Added some more debug output

Change 3087524 on 2016/08/12 by Rolando.Caloca

	DR - vk - Fixed StencilRef, fixed size of RHIReadSurfaceFloatData (but still returns dummy data)

Change 3087663 on 2016/08/12 by Rolando.Caloca

	DR - vk - Fix for SRGB; support for mip texture views

Change 3087735 on 2016/08/12 by Daniel.Wright

	TextureRenderTarget2D's can now be up to 8192^2.  Anything over 2048 pops up an 'are you sure' dialog.

Change 3087750 on 2016/08/12 by Rolando.Caloca

	DR - vk - Minor renaming in prep for merge

Change 3087813 on 2016/08/12 by Rolando.Caloca

	DR - vk - More minor cleanup

Change 3087819 on 2016/08/12 by Chris.Bunner

	Check material function input types directly, no need to traverse connected graph.
	#jira UE-32134

Change 3087901 on 2016/08/12 by Rolando.Caloca

	DR - vk - Fix RT view to use 1 mip
	Fix depth buffer component swizzle

Change 3088193 on 2016/08/12 by Daniel.Wright

	DFAO and RTDF shadows are enabled in High and Epic scalability settings by default

Change 3088988 on 2016/08/15 by Rolando.Caloca

	DR - Add Accessors

Change 3089104 on 2016/08/15 by Olaf.Piesche

	#jira UE-34241

	Sceneproxy can be nullptr in FDynamicMeshEmitterData::Init if the proxy is being recreated

Change 3089208 on 2016/08/15 by Daniel.Wright

	Downsampled separate translucency uses a separate view uniform buffer with correct buffer sizes
	* Fixes WorldPosition in downsampled translucency
	* View uniform buffer parameters are now cached on the view, to allow recreating the uniform buffer without having to rebuild the entire struct.  Currently used by global distance field, downsampled separate translucency.
	* Fixed the downsampled translucency depth buffer being full res used together with a smaller color target, now they are both the downsampled res

Change 3089209 on 2016/08/15 by Daniel.Wright

	Fixed atmospheric fog on translucency

Change 3089457 on 2016/08/15 by Daniel.Wright

	Fixed lighting build failure from UMaterialInstanceDynamic assigned to a mesh that's being exported to Lightmass.  The Swarm cache entry is created using the parent's guid, causing multiple MID's with the same parent to acquire a file handle multiple times which fails after the first.

Change 3089549 on 2016/08/15 by Daniel.Wright

	UMaterialInterface initializes LightingGuid to something valid - causes UMaterialInstanceDynamic to have a valid LightingGuid so they can be used in lighting builds

Change 3089703 on 2016/08/15 by Daniel.Wright

	Custom expression fixup for View.RenderTargetSize

Change 3090546 on 2016/08/16 by Daniel.Wright

	Hopeful fix for recycled snapshot view crash

Change 3091202 on 2016/08/16 by Daniel.Wright

	Manually clear FViewInfo::CachedViewUniformShaderParameters on creating a snapshot, since memcpy is used to create the snapshot view

[CL 3091931 by Gil Gribb in Main branch]
2016-08-17 11:38:13 -04:00

1012 lines
33 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PostProcessSubsurface.cpp: Screenspace subsurface scattering implementation.
=============================================================================*/
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "SceneFilterRendering.h"
#include "PostProcessSubsurface.h"
#include "PostProcessing.h"
#include "SceneUtils.h"
#include "CompositionLighting/PostProcessPassThrough.h"
ENGINE_API const IPooledRenderTarget* GetSubsufaceProfileTexture_RT(FRHICommandListImmediate& RHICmdList);
static TAutoConsoleVariable<int32> CVarSSSQuality(
TEXT("r.SSS.Quality"),
0,
TEXT("Defines the quality of the recombine pass when using the SubsurfaceScatteringProfile shading model\n")
TEXT(" 0: low (faster, default)\n")
TEXT(" 1: high (sharper details but slower)\n")
TEXT("-1: auto, 1 if TemporalAA is disabled (without TemporalAA the quality is more noticable)"),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarSSSFilter(
TEXT("r.SSS.Filter"),
1,
TEXT("Defines the filter method for Screenspace Subsurface Scattering feature.\n")
TEXT(" 0: point filter (useful for testing, could be cleaner)\n")
TEXT(" 1: bilinear filter"),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarSSSSampleSet(
TEXT("r.SSS.SampleSet"),
2,
TEXT("Defines how many samples we use for Screenspace Subsurface Scattering feature.\n")
TEXT(" 0: lowest quality (6*2+1)\n")
TEXT(" 1: medium quality (9*2+1)\n")
TEXT(" 2: high quality (13*2+1) (default)"),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarCheckerboardSubsurfaceProfileRendering(
TEXT("r.SSS.Checkerboard"),
1,
TEXT("Enables or disables checkerboard rendering for subsurface profile rendering.\n")
TEXT("This is necessary if SceneColor does not include a floating point alpha channel (e.g 32-bit formats)\n")
TEXT(" 0: Disabled (high quality) \n")
TEXT(" 1: Enabled (low quality). Surface lighting will be at reduced resolution.\n")
TEXT(" 2: Automatic. Non-checkerboard lighting will be applied if we have a suitable rendertarget format\n"),
ECVF_RenderThreadSafe
);
// -------------------------------------------------------------
float GetSubsurfaceRadiusScale()
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.SSS.Scale"));
check(CVar);
float Ret = CVar->GetValueOnRenderThread();
return FMath::Max(0.0f, Ret);
}
// -------------------------------------------------------------
const bool FRCPassPostProcessSubsurface::RequiresCheckerboardSubsurfaceRendering(EPixelFormat SceneColorFormat)
{
int CVarValue = CVarCheckerboardSubsurfaceProfileRendering.GetValueOnRenderThread();
if (CVarValue == 0)
{
return false;
}
else if ( CVarValue == 1 )
{
return true;
}
else if (CVarValue == 2)
{
switch (SceneColorFormat)
{
case PF_A32B32G32R32F:
case PF_FloatRGBA:
return false;
default:
return true;
}
}
return true;
}
// -------------------------------------------------------------
/** Shared shader parameters needed for screen space subsurface scattering. */
class FSubsurfaceParameters
{
public:
void Bind(const FShaderParameterMap& ParameterMap)
{
SSSParams.Bind(ParameterMap, TEXT("SSSParams"));
SSProfilesTexture.Bind(ParameterMap, TEXT("SSProfilesTexture"));
}
void SetParameters(FRHICommandList& RHICmdList, const FPixelShaderRHIParamRef& ShaderRHI, const FRenderingCompositePassContext& Context) const
{
{
// from Separabale.usf: float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY))
// can be extracted out of projection matrix
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// Calculate the sssWidth scale (1.0 for a unit plane sitting on the projection window):
float DistanceToProjectionWindow = Context.View.ViewMatrices.ProjMatrix.M[0][0];
float SSSScaleZ = DistanceToProjectionWindow * GetSubsurfaceRadiusScale();
// * 0.5f: hacked in 0.5 - -1..1 to 0..1 but why this isn't in demo code?
float SSSScaleX = SSSScaleZ / SUBSURFACE_KERNEL_SIZE * 0.5f;
FVector4 ColorScale(SSSScaleX, SSSScaleZ, 0, 0);
SetShaderValue(Context.RHICmdList, ShaderRHI, SSSParams, ColorScale);
}
{
const IPooledRenderTarget* PooledRT = GetSubsufaceProfileTexture_RT(Context.RHICmdList);
if(!PooledRT)
{
// no subsurface profile was used yet
PooledRT = GSystemTextures.BlackDummy;
}
const FSceneRenderTargetItem& Item = PooledRT->GetRenderTargetItem();
SetTextureParameter(Context.RHICmdList, ShaderRHI, SSProfilesTexture, Item.ShaderResourceTexture);
}
}
friend FArchive& operator<<(FArchive& Ar,FSubsurfaceParameters& P)
{
Ar << P.SSSParams << P.SSProfilesTexture;
return Ar;
}
private:
FShaderParameter SSSParams;
FShaderResourceParameter SSProfilesTexture;
};
// ---------------------------------------------
/**
* Encapsulates the post processing subsurface scattering pixel shader.
*/
class FPostProcessSubsurfaceVisualizePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FPostProcessSubsurfaceVisualizePS , 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("SUBSURFACE_RADIUS_SCALE"), SUBSURFACE_RADIUS_SCALE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
}
/** Default constructor. */
FPostProcessSubsurfaceVisualizePS () {}
public:
FPostProcessPassParameters PostprocessParameter;
FDeferredPixelShaderParameters DeferredParameters;
FShaderResourceParameter MiniFontTexture;
FSubsurfaceParameters SubsurfaceParameters;
/** Initialization constructor. */
FPostProcessSubsurfaceVisualizePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
PostprocessParameter.Bind(Initializer.ParameterMap);
DeferredParameters.Bind(Initializer.ParameterMap);
MiniFontTexture.Bind(Initializer.ParameterMap, TEXT("MiniFontTexture"));
SubsurfaceParameters.Bind(Initializer.ParameterMap);
}
void SetParameters(const FRenderingCompositePassContext& Context)
{
const FFinalPostProcessSettings& Settings = Context.View.FinalPostProcessSettings;
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View);
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI());
DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View);
SetTextureParameter(Context.RHICmdList, ShaderRHI, MiniFontTexture, GEngine->MiniFontTexture ? GEngine->MiniFontTexture->Resource->TextureRHI : GSystemTextures.WhiteDummy->GetRenderTargetItem().TargetableTexture);
SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << PostprocessParameter << DeferredParameters << MiniFontTexture << SubsurfaceParameters;
return bShaderHasOutdatedParameters;
}
static const TCHAR* GetSourceFilename()
{
return TEXT("PostProcessSubsurface");
}
static const TCHAR* GetFunctionName()
{
return TEXT("VisualizePS");
}
};
IMPLEMENT_SHADER_TYPE3(FPostProcessSubsurfaceVisualizePS, SF_Pixel);
void SetSubsurfaceVisualizeShader(const FRenderingCompositePassContext& Context)
{
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
TShaderMapRef<FPostProcessSubsurfaceVisualizePS> PixelShader(Context.GetShaderMap());
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(Context);
VertexShader->SetParameters(Context);
}
FRCPassPostProcessSubsurfaceVisualize::FRCPassPostProcessSubsurfaceVisualize(FRHICommandList& RHICmdList)
{
// we need the GBuffer, we release it Process()
FSceneRenderTargets::Get_Todo_PassContext().AdjustGBufferRefCount(RHICmdList, 1);
}
void FRCPassPostProcessSubsurfaceVisualize::Process(FRenderingCompositePassContext& Context)
{
SCOPED_DRAW_EVENT(Context.RHICmdList, SubsurfaceVisualize);
const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0);
if(!InputDesc)
{
// input is not hooked up correctly
return;
}
const FSceneView& View = Context.View;
const FSceneViewFamily& ViewFamily = *(View.Family);
FIntPoint SrcSize = InputDesc->Extent;
FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent;
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList);
// e.g. 4 means the input texture is 4x smaller than the buffer size
uint32 ScaleFactor = SceneContext.GetBufferSizeXY().X / SrcSize.X;
FIntRect SrcRect = View.ViewRect / ScaleFactor;
FIntRect DestRect = SrcRect;
const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);
// Set the view family's render target/viewport.
SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef());
// is optimized away if possible (RT size=view size, )
Context.RHICmdList.Clear(true, FLinearColor::Black, false, 1.0f, false, 0, DestRect);
Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f );
// set the state
Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
SetSubsurfaceVisualizeShader(Context);
// Draw a quad mapping scene color to the view's render target
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
DrawRectangle(
Context.RHICmdList,
DestRect.Min.X, DestRect.Min.Y,
DestRect.Width(), DestRect.Height(),
SrcRect.Min.X, SrcRect.Min.Y,
SrcRect.Width(), SrcRect.Height(),
DestSize,
SrcSize,
*VertexShader,
EDRF_UseTriangleOptimization);
{
FRenderTargetTemp TempRenderTarget(View, (const FTexture2DRHIRef&)DestRenderTarget.TargetableTexture);
FCanvas Canvas(&TempRenderTarget, NULL, ViewFamily.CurrentRealTime, ViewFamily.CurrentWorldTime, ViewFamily.DeltaWorldTime, Context.GetFeatureLevel());
float X = 30;
float Y = 28;
const float YStep = 14;
FString Line;
Line = FString::Printf(TEXT("Visualize Screen Space Subsurface Scattering"));
Canvas.DrawShadowedString(X, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
Y += YStep;
uint32 Index = 0;
while (GSubsurfaceProfileTextureObject.GetEntryString(Index++, Line))
{
Canvas.DrawShadowedString(X, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
}
Canvas.Flush_RenderThread(Context.RHICmdList);
}
Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
// we no longer need the GBuffer
SceneContext.AdjustGBufferRefCount(Context.RHICmdList, -1);
}
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceVisualize::ComputeOutputDesc(EPassOutputId InPassOutputId) const
{
FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_Todo_PassContext().GetSceneColor()->GetDesc();
Ret.Reset();
Ret.DebugName = TEXT("SubsurfaceVisualize");
// alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering)
Ret.Format = PF_FloatRGBA;
return Ret;
}
// ---------------------------------------------
/**
* Encapsulates the post processing subsurface scattering pixel shader.
* @param HalfRes 0:to full res, 1:to half res
*/
template <uint32 HalfRes, uint32 Checkerboard>
class FPostProcessSubsurfaceSetupPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FPostProcessSubsurfaceSetupPS , 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("HALF_RES"), HalfRes);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_RADIUS_SCALE"), SUBSURFACE_RADIUS_SCALE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_PROFILE_CHECKERBOARD"), Checkerboard);
}
/** Default constructor. */
FPostProcessSubsurfaceSetupPS () {}
public:
FPostProcessPassParameters PostprocessParameter;
FDeferredPixelShaderParameters DeferredParameters;
FShaderResourceParameter MiniFontTexture;
FSubsurfaceParameters SubsurfaceParameters;
/** Initialization constructor. */
FPostProcessSubsurfaceSetupPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
PostprocessParameter.Bind(Initializer.ParameterMap);
DeferredParameters.Bind(Initializer.ParameterMap);
SubsurfaceParameters.Bind(Initializer.ParameterMap);
}
void SetParameters(const FRenderingCompositePassContext& Context)
{
const FFinalPostProcessSettings& Settings = Context.View.FinalPostProcessSettings;
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View);
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI());
DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View);
SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << PostprocessParameter << DeferredParameters << SubsurfaceParameters;
return bShaderHasOutdatedParameters;
}
static const TCHAR* GetSourceFilename()
{
return TEXT("PostProcessSubsurface");
}
static const TCHAR* GetFunctionName()
{
return TEXT("SetupPS");
}
};
// #define avoids a lot of code duplication
#define VARIATION1(A) VARIATION2(A,0) VARIATION2(A,1)
#define VARIATION2(A,B) typedef FPostProcessSubsurfaceSetupPS<A,B> FPostProcessSubsurfaceSetupPS##A##B; \
IMPLEMENT_SHADER_TYPE2(FPostProcessSubsurfaceSetupPS##A##B, SF_Pixel);
VARIATION1(0) VARIATION1(1)
#undef VARIATION1
#undef VARIATION2
template <uint32 HalfRes, uint32 Checkerboard>
void SetSubsurfaceSetupShader(const FRenderingCompositePassContext& Context)
{
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
TShaderMapRef<FPostProcessSubsurfaceSetupPS<HalfRes, Checkerboard> > PixelShader(Context.GetShaderMap());
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(Context);
VertexShader->SetParameters(Context);
}
// --------------------------------------
FRCPassPostProcessSubsurfaceSetup::FRCPassPostProcessSubsurfaceSetup(FViewInfo& View, bool bInHalfRes)
: ViewRect(View.ViewRect)
, bHalfRes(bInHalfRes)
{
}
void FRCPassPostProcessSubsurfaceSetup::Process(FRenderingCompositePassContext& Context)
{
SCOPED_DRAW_EVENT(Context.RHICmdList, SubsurfaceSetup);
const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0);
if(!InputDesc)
{
// input is not hooked up correctly
return;
}
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList);
const bool bCheckerboard = FRCPassPostProcessSubsurface::RequiresCheckerboardSubsurfaceRendering( SceneContext.GetSceneColorFormat() );
const FSceneView& View = Context.View;
const FSceneViewFamily& ViewFamily = *(View.Family);
FIntPoint SrcSize = InputDesc->Extent;
FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent;
FIntRect DestRect = FIntRect(0, 0, DestSize.X, DestSize.Y);
FIntRect SrcRect = View.ViewRect;
if(bHalfRes)
{
// upscale rectangle to not slightly scale (might miss a pixel)
SrcRect = DestRect * 2 + View.ViewRect.Min;
}
const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);
// Set the view family's render target/viewport.
SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef());
Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f );
// set the state
Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
if(bHalfRes)
{
if (bCheckerboard)
{
SetSubsurfaceSetupShader<1, 1>(Context);
}
else
{
SetSubsurfaceSetupShader<1,0>(Context);
}
}
else
{
if (bCheckerboard)
{
SetSubsurfaceSetupShader<0, 1>(Context);
}
else
{
SetSubsurfaceSetupShader<0, 0>(Context);
}
}
// Draw a quad mapping scene color to the view's render target
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
DrawPostProcessPass(
Context.RHICmdList,
DestRect.Min.X, DestRect.Min.Y,
DestRect.Width(), DestRect.Height(),
SrcRect.Min.X, SrcRect.Min.Y,
SrcRect.Width(), SrcRect.Height(),
DestSize,
SrcSize,
*VertexShader,
View.StereoPass,
Context.HasHmdMesh(),
EDRF_UseTriangleOptimization);
Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
}
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const
{
FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_Todo_PassContext().GetSceneColor()->GetDesc();
Ret.Reset();
Ret.DebugName = TEXT("SubsurfaceSetup");
// alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering)
Ret.Format = PF_FloatRGBA;
Ret.Extent = ViewRect.Size();
if(bHalfRes)
{
Ret.Extent = FIntPoint::DivideAndRoundUp(Ret.Extent, 2);
Ret.Extent.X = FMath::Max(1, Ret.Extent.X);
Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y);
}
return Ret;
}
/** Encapsulates the post processing subsurface pixel shader. */
// @param Direction 0: horizontal, 1:vertical
// @param SampleSet 0:low, 1:med, 2:high
template <uint32 Direction, uint32 SampleSet>
class TPostProcessSubsurfacePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TPostProcessSubsurfacePS, 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("SSS_DIRECTION"), Direction);
OutEnvironment.SetDefine(TEXT("SSS_SAMPLESET"), SampleSet);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_RADIUS_SCALE"), SUBSURFACE_RADIUS_SCALE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
}
/** Default constructor. */
TPostProcessSubsurfacePS() {}
public:
FPostProcessPassParameters PostprocessParameter;
FDeferredPixelShaderParameters DeferredParameters;
FSubsurfaceParameters SubsurfaceParameters;
/** Initialization constructor. */
TPostProcessSubsurfacePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
PostprocessParameter.Bind(Initializer.ParameterMap);
DeferredParameters.Bind(Initializer.ParameterMap);
SubsurfaceParameters.Bind(Initializer.ParameterMap);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << PostprocessParameter << DeferredParameters << SubsurfaceParameters;
return bShaderHasOutdatedParameters;
}
void SetParameters(const FRenderingCompositePassContext& Context)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View);
DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View);
if(CVarSSSFilter.GetValueOnRenderThread())
{
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Bilinear,AM_Border,AM_Border,AM_Border>::GetRHI());
}
else
{
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point,AM_Border,AM_Border,AM_Border>::GetRHI());
}
SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context);
}
static const TCHAR* GetSourceFilename()
{
return TEXT("PostProcessSubsurface");
}
static const TCHAR* GetFunctionName()
{
return TEXT("MainPS");
}
};
// #define avoids a lot of code duplication
#define VARIATION1(A) VARIATION2(A,0) VARIATION2(A,1) VARIATION2(A,2)
#define VARIATION2(A, B) typedef TPostProcessSubsurfacePS<A, B> TPostProcessSubsurfacePS##A##B; \
IMPLEMENT_SHADER_TYPE2(TPostProcessSubsurfacePS##A##B, SF_Pixel);
VARIATION1(0) VARIATION1(1) VARIATION1(2)
#undef VARIATION1
#undef VARIATION2
FRCPassPostProcessSubsurface::FRCPassPostProcessSubsurface(uint32 InDirection, bool bInHalfRes)
: Direction(InDirection)
, bHalfRes(bInHalfRes)
{
check(InDirection < 2);
}
template <uint32 Direction, uint32 SampleSet>
void SetSubsurfaceShader(const FRenderingCompositePassContext& Context, TShaderMapRef<FPostProcessVS> &VertexShader)
{
TShaderMapRef<TPostProcessSubsurfacePS<Direction, SampleSet> > PixelShader(Context.GetShaderMap());
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(Context);
VertexShader->SetParameters(Context);
}
// 0:horizontal, 1: vertical
template <uint32 Direction>
void SetSubsurfaceShaderSampleSet(const FRenderingCompositePassContext& Context, TShaderMapRef<FPostProcessVS> &VertexShader, uint32 SampleSet)
{
switch(SampleSet)
{
case 0: SetSubsurfaceShader<Direction, 0>(Context, VertexShader); break;
case 1: SetSubsurfaceShader<Direction, 1>(Context, VertexShader); break;
case 2: SetSubsurfaceShader<Direction, 2>(Context, VertexShader); break;
default:
check(0);
}
}
void FRCPassPostProcessSubsurface::Process(FRenderingCompositePassContext& Context)
{
const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0);
check(InputDesc);
{
const IPooledRenderTarget* PooledRT = GetSubsufaceProfileTexture_RT(Context.RHICmdList);
check(PooledRT);
// for debugging
GRenderTargetPool.VisualizeTexture.SetCheckPoint(Context.RHICmdList, PooledRT);
}
const FSceneView& View = Context.View;
const FSceneViewFamily& ViewFamily = *(View.Family);
FIntPoint SrcSize = InputDesc->Extent;
FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent;
check(DestSize.X);
check(DestSize.Y);
check(SrcSize.X);
check(SrcSize.Y);
FIntRect SrcRect = FIntRect(0, 0, DestSize.X, DestSize.Y);
FIntRect DestRect = SrcRect;
TRefCountPtr<IPooledRenderTarget> NewSceneColor;
const FSceneRenderTargetItem* DestRenderTarget;
{
DestRenderTarget = &PassOutputs[0].RequestSurface(Context);
check(DestRenderTarget);
}
// Set the view family's render target/viewport.
SetRenderTarget(Context.RHICmdList, DestRenderTarget->TargetableTexture, FTextureRHIRef());
Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f );
Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
SCOPED_DRAW_EVENTF(Context.RHICmdList, SubsurfacePass, TEXT("SubsurfaceDirection#%d"), Direction);
uint32 SampleSet = FMath::Clamp(CVarSSSSampleSet.GetValueOnRenderThread(), 0, 2);
if (Direction == 0)
{
SetSubsurfaceShaderSampleSet<0>(Context, VertexShader, SampleSet);
}
else
{
SetSubsurfaceShaderSampleSet<1>(Context, VertexShader, SampleSet);
}
DrawPostProcessPass(
Context.RHICmdList,
DestRect.Min.X, DestRect.Min.Y,
DestRect.Width(), DestRect.Height(),
SrcRect.Min.X, SrcRect.Min.Y,
SrcRect.Width(), SrcRect.Height(),
DestSize,
SrcSize,
*VertexShader,
View.StereoPass,
Context.HasHmdMesh(),
EDRF_UseTriangleOptimization);
Context.RHICmdList.CopyToResolveTarget(DestRenderTarget->TargetableTexture, DestRenderTarget->ShaderResourceTexture, false, FResolveParams());
}
FPooledRenderTargetDesc FRCPassPostProcessSubsurface::ComputeOutputDesc(EPassOutputId InPassOutputId) const
{
FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc;
Ret.Reset();
Ret.DebugName = (Direction == 0) ? TEXT("SubsurfaceX") : TEXT("SubsurfaceY");
return Ret;
}
/** Encapsulates the post processing subsurface recombine pixel shader. */
// @param RecombineMode 0:fullres, 1: halfres, 2:no scattering, just reconstruct the lighting (needed for scalability)
// @param RecombineQuality 0:low..1:high
template <uint32 RecombineMode, uint32 RecombineQuality, uint32 Checkerboard>
class TPostProcessSubsurfaceRecombinePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TPostProcessSubsurfaceRecombinePS, 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("RECOMBINE_QUALITY"), RecombineQuality);
OutEnvironment.SetDefine(TEXT("HALF_RES"), (uint32)(RecombineMode == 1));
OutEnvironment.SetDefine(TEXT("RECOMBINE_SUBSURFACESCATTER"), (uint32)(RecombineMode != 2));
OutEnvironment.SetDefine(TEXT("SUBSURFACE_RADIUS_SCALE"), SUBSURFACE_RADIUS_SCALE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_PROFILE_CHECKERBOARD"), Checkerboard);
}
/** Default constructor. */
TPostProcessSubsurfaceRecombinePS() {}
public:
FPostProcessPassParameters PostprocessParameter;
FDeferredPixelShaderParameters DeferredParameters;
FSubsurfaceParameters SubsurfaceParameters;
/** Initialization constructor. */
TPostProcessSubsurfaceRecombinePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
PostprocessParameter.Bind(Initializer.ParameterMap);
DeferredParameters.Bind(Initializer.ParameterMap);
SubsurfaceParameters.Bind(Initializer.ParameterMap);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << PostprocessParameter << DeferredParameters << SubsurfaceParameters;
return bShaderHasOutdatedParameters;
}
void SetParameters(const FRenderingCompositePassContext& Context)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View);
DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View);
PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Bilinear,AM_Border,AM_Border,AM_Border>::GetRHI());
SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context);
}
static const TCHAR* GetSourceFilename()
{
return TEXT("PostProcessSubsurface");
}
static const TCHAR* GetFunctionName()
{
return TEXT("SubsurfaceRecombinePS");
}
};
// #define avoids a lot of code duplication
#define VARIATION1(A) VARIATION2(A,0) VARIATION2(A,1)
#define VARIATION2(A, B) VARIATION3(A,B,0) VARIATION3(A,B,1)
#define VARIATION3(A, B, C) typedef TPostProcessSubsurfaceRecombinePS<A, B, C> TPostProcessSubsurfaceRecombinePS##A##B##C; \
IMPLEMENT_SHADER_TYPE2(TPostProcessSubsurfaceRecombinePS##A##B##C, SF_Pixel);
VARIATION1(0) VARIATION1(1) VARIATION1(2)
#undef VARIATION1
#undef VARIATION2
#undef VARIATION3
// @param RecombineMode 0:fullres, 1: halfres, 2:no scattering, just reconstruct the lighting (needed for scalability)
// @param RecombineQuality 0:low..1:high
template <uint32 RecombineMode, uint32 RecombineQuality, uint32 Checkerboard>
void SetSubsurfaceRecombineShader(const FRenderingCompositePassContext& Context, TShaderMapRef<FPostProcessVS> &VertexShader)
{
TShaderMapRef<TPostProcessSubsurfaceRecombinePS<RecombineMode, RecombineQuality, Checkerboard> > PixelShader(Context.GetShaderMap());
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
PixelShader->SetParameters(Context);
VertexShader->SetParameters(Context);
}
FRCPassPostProcessSubsurfaceRecombine::FRCPassPostProcessSubsurfaceRecombine(bool bInHalfRes, bool bInSingleViewportMode)
: bHalfRes(bInHalfRes)
, bSingleViewportMode(bInSingleViewportMode)
{
}
void FRCPassPostProcessSubsurfaceRecombine::Process(FRenderingCompositePassContext& Context)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList);
const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0);
check(InputDesc);
const FSceneView& View = Context.View;
const FSceneViewFamily& ViewFamily = *(View.Family);
FIntPoint SrcSize = InputDesc->Extent;
FIntPoint DestSize = SceneContext.GetBufferSizeXY();
check(DestSize.X);
check(DestSize.Y);
check(SrcSize.X);
check(SrcSize.Y);
FIntRect SrcRect = FIntRect(0, 0, InputDesc->Extent.X, InputDesc->Extent.Y);
FIntRect DestRect = View.ViewRect;
TRefCountPtr<IPooledRenderTarget>& SceneColor = SceneContext.GetSceneColor();
const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);
// Set the view family's render target/viewport.
SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef());
Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
CopyOverOtherViewportsIfNeeded(Context, View);
Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f );
TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap());
uint32 QualityCVar = CVarSSSQuality.GetValueOnRenderThread();
const bool bCheckerboard = FRCPassPostProcessSubsurface::RequiresCheckerboardSubsurfaceRendering( SceneContext.GetSceneColorFormat() );
// 0:low / 1:high
uint32 RecombineQuality = 0;
{
if(QualityCVar == -1)
{
RecombineQuality = (View.AntiAliasingMethod == AAM_TemporalAA) ? 0 : 1;
}
else if(QualityCVar == 1)
{
RecombineQuality = 1;
}
}
// needed for Scalability
// 0:fullres, 1: halfres, 2:no scattering, just reconstruct the lighting (needed for scalability)
uint32 RecombineMode = 2;
if(GetInput(ePId_Input1)->IsValid())
{
RecombineMode = bHalfRes ? 1 : 0;
}
SCOPED_DRAW_EVENTF(Context.RHICmdList, SubsurfacePassRecombine, TEXT("SubsurfacePassRecombine Mode:%d Quality:%d"), RecombineMode, RecombineQuality);
{
if (bCheckerboard)
{
if (RecombineQuality == 0)
{
switch (RecombineMode)
{
case 0: SetSubsurfaceRecombineShader<0, 0, 1>(Context, VertexShader); break;
case 1: SetSubsurfaceRecombineShader<1, 0, 1>(Context, VertexShader); break;
case 2: SetSubsurfaceRecombineShader<2, 0, 1>(Context, VertexShader); break;
default: check(0);
}
}
else
{
switch (RecombineMode)
{
case 0: SetSubsurfaceRecombineShader<0, 1, 1>(Context, VertexShader); break;
case 1: SetSubsurfaceRecombineShader<1, 1, 1>(Context, VertexShader); break;
case 2: SetSubsurfaceRecombineShader<2, 1, 1>(Context, VertexShader); break;
default: check(0);
}
}
}
else
{
if (RecombineQuality == 0)
{
switch (RecombineMode)
{
case 0: SetSubsurfaceRecombineShader<0, 0, 0>(Context, VertexShader); break;
case 1: SetSubsurfaceRecombineShader<1, 0, 0>(Context, VertexShader); break;
case 2: SetSubsurfaceRecombineShader<2, 0, 0>(Context, VertexShader); break;
default: check(0);
}
}
else
{
switch (RecombineMode)
{
case 0: SetSubsurfaceRecombineShader<0, 1, 0>(Context, VertexShader); break;
case 1: SetSubsurfaceRecombineShader<1, 1, 0>(Context, VertexShader); break;
case 2: SetSubsurfaceRecombineShader<2, 1, 0>(Context, VertexShader); break;
default: check(0);
}
}
}
}
DrawPostProcessPass(
Context.RHICmdList,
DestRect.Min.X, DestRect.Min.Y,
DestRect.Width(), DestRect.Height(),
SrcRect.Min.X, SrcRect.Min.Y,
SrcRect.Width(), SrcRect.Height(),
DestSize,
SrcSize,
*VertexShader,
View.StereoPass,
Context.HasHmdMesh(),
EDRF_UseTriangleOptimization);
Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
// replace the current SceneColor with this one
SceneContext.SetSceneColor(PassOutputs[0].PooledRenderTarget);
PassOutputs[0].PooledRenderTarget.SafeRelease();
}
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceRecombine::ComputeOutputDesc(EPassOutputId InPassOutputId) const
{
FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc;
Ret.Reset();
Ret.DebugName = TEXT("SceneColorSubsurface");
// we replace the HDR SceneColor with this one
return Ret;
}