You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#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. Change3075241on 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. Change3079795on 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 cl2938543"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 Change3087524on 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]
1012 lines
33 KiB
C++
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;
|
|
}
|
|
|