2249 lines
85 KiB
C++
2249 lines
85 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "PathTracingSpatialTemporalDenoising.h"
|
|
#include "PathTracing.h"
|
|
#include "RHI.h"
|
|
|
|
class FDenoiserManager
|
|
{
|
|
public:
|
|
static FDenoiserManager& Get()
|
|
{
|
|
static FDenoiserManager DenoiserManager;
|
|
return DenoiserManager;
|
|
}
|
|
|
|
void RegisterSpatialDenoiser(TUniquePtr<UE::Renderer::Private::IPathTracingDenoiser> InDenoiser, FString Name)
|
|
{
|
|
check(!SpatialDenoiser.Contains(Name));
|
|
|
|
bNeedTextureCreateExtraFlags |= InDenoiser->NeedTextureCreateExtraFlags();
|
|
SpatialDenoiser.Add(Name, MoveTemp(InDenoiser));
|
|
}
|
|
void RegisterSpatialTemporalDenoiser(TUniquePtr<UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser> InDenoiser, FString Name)
|
|
{
|
|
check(!PathTracingSpatialTemporalDenoisers.Contains(Name));
|
|
bNeedTextureCreateExtraFlags |= InDenoiser->NeedTextureCreateExtraFlags();
|
|
PathTracingSpatialTemporalDenoisers.Add(Name, MoveTemp(InDenoiser));
|
|
}
|
|
|
|
bool HasSpatialDenoiser()const { return SpatialDenoiser.Num() > 0; }
|
|
bool HasSpatialTemporalDenoiser()const { return PathTracingSpatialTemporalDenoisers.Num() > 0; }
|
|
bool HasDenoiser()const { return HasSpatialDenoiser() || HasSpatialTemporalDenoiser();}
|
|
|
|
UE::Renderer::Private::IPathTracingDenoiser* GetSpatialDenoiser(FString Name, bool bMatch)
|
|
{
|
|
if (SpatialDenoiser.Contains(Name))
|
|
{
|
|
return SpatialDenoiser[Name].Get();
|
|
}
|
|
else if (SpatialDenoiser.Num() > 0 && !bMatch)
|
|
{
|
|
return SpatialDenoiser.CreateConstIterator()->Value.Get();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser* GetSpatialTemporalDenoiser(FString Name, bool bMatch)
|
|
{
|
|
if (PathTracingSpatialTemporalDenoisers.Contains(Name))
|
|
{
|
|
return PathTracingSpatialTemporalDenoisers[Name].Get();
|
|
}
|
|
else if (PathTracingSpatialTemporalDenoisers.Num() > 0 && !bMatch)
|
|
{
|
|
return PathTracingSpatialTemporalDenoisers.CreateConstIterator()->Value.Get();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void UnregisterDenoiser(FString Name)
|
|
{
|
|
SpatialDenoiser.Remove(Name);
|
|
PathTracingSpatialTemporalDenoisers.Remove(Name);
|
|
}
|
|
|
|
/** If any plugin needs extra creation flag*/
|
|
bool NeedTextureCreateExtraFlags()
|
|
{
|
|
return bNeedTextureCreateExtraFlags;
|
|
}
|
|
|
|
private:
|
|
FDenoiserManager() = default;
|
|
FDenoiserManager(const FDenoiserManager&) = delete;
|
|
FDenoiserManager& operator=(const FDenoiserManager&) = delete;
|
|
|
|
TMap<FString, TUniquePtr<UE::Renderer::Private::IPathTracingDenoiser> > SpatialDenoiser;
|
|
|
|
/**Spatial-temporal denoiser can work as both spatial and temporal denoiser*/
|
|
TMap<FString, TUniquePtr<UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser> > PathTracingSpatialTemporalDenoisers;
|
|
|
|
/** Since all plugins can be dynamically switched, need to increase the compatibility*/
|
|
bool bNeedTextureCreateExtraFlags = false;
|
|
};
|
|
|
|
void RegisterSpatialDenoiser(TUniquePtr<UE::Renderer::Private::IPathTracingDenoiser> PathTracingDenoiser, FString Name)
|
|
{
|
|
FDenoiserManager::Get().RegisterSpatialDenoiser(MoveTemp(PathTracingDenoiser), Name);
|
|
}
|
|
void RegisterSpatialTemporalDenoiser(TUniquePtr<UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser> PathTracingDenoiser, FString Name)
|
|
{
|
|
FDenoiserManager::Get().RegisterSpatialTemporalDenoiser(MoveTemp(PathTracingDenoiser), Name);
|
|
}
|
|
|
|
void UnregisterDenoiser(FString Name)
|
|
{
|
|
FDenoiserManager::Get().UnregisterDenoiser(Name);
|
|
}
|
|
|
|
bool HasTemporalDenoiser()
|
|
{
|
|
return FDenoiserManager::Get().HasSpatialTemporalDenoiser();
|
|
}
|
|
|
|
#if RHI_RAYTRACING
|
|
|
|
#include "DeferredShadingRenderer.h"
|
|
#include "GenerateMips.h"
|
|
#include "GlobalShader.h"
|
|
#include "HAL/PlatformApplicationMisc.h"
|
|
#include "PathTracingDefinitions.h"
|
|
#include "RayTracing/RayTracingMaterialHitShaders.h"
|
|
#include "RayTracingDefinitions.h"
|
|
#include "RayTracingTypes.h"
|
|
#include "RenderGraphDefinitions.h"
|
|
#include "RendererPrivate.h"
|
|
#include "PostProcess/PostProcessMaterial.h"
|
|
#include <limits>
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogPathTracingDenoising, Log, All);
|
|
|
|
namespace {
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingDenoiser(
|
|
TEXT("r.PathTracing.Denoiser"),
|
|
-1,
|
|
TEXT("Enable denoising of the path traced output (if a denoiser plugin is active) (default = -1 (driven by postprocesing volume))\n")
|
|
TEXT("-1: inherit from PostProcessVolume\n")
|
|
TEXT("0: disable denoiser\n")
|
|
TEXT("1: enable denoiser (if a denoiser plugin is active)\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingDenoiserNormalSpace(
|
|
TEXT("r.PathTracing.Denoiser.NormalSpace"),
|
|
0,
|
|
TEXT("The space normal is in\n")
|
|
TEXT("0: World space (default)\n")
|
|
TEXT("1: Camera space. Some denoisers require camera space normal\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingDenoiserPrepassVarianceType(
|
|
TEXT("r.PathTracing.Denoiser.Prepass.VarianceType"),
|
|
1,
|
|
TEXT("Select the per-pixel variance type:\n")
|
|
TEXT("0: Multiple channel (RGB) variance for radiance\n")
|
|
TEXT("1: Combined single channel variance for radiance, albedo and normal\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingDenoiserPrepassOutputVarianceTexture(
|
|
TEXT("r.PathTracing.Denoiser.Prepass.OutputVarianceTexture"),
|
|
0,
|
|
TEXT("0: Output variance texture on demand\n")
|
|
TEXT("1: Always output variance texture to denoisers, or the postprocess material usually used by MRQ\n")
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingDenoiserPrepassRankedLuminanceVariance(
|
|
TEXT("r.PathTracing.Denoiser.Prepass.RankedLuminanceVariance"),
|
|
1,
|
|
TEXT("Select the luminance type when calculating the variance:\n")
|
|
TEXT("0: use default luminance to estimate variance.\n")
|
|
TEXT("1: Use channel ranked luminance when calculating variance.\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingSpatialDenoiser(
|
|
TEXT("r.PathTracing.SpatialDenoiser"),
|
|
1,
|
|
TEXT("Enable spatial denoising of the path traced output\n")
|
|
TEXT("-1: inherit from PostProcessVolume\n")
|
|
TEXT("0: disable denoiser\n")
|
|
TEXT("1: enable denoiser (if a denoiser plugin is active)\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<FString> CVarPathTracingDenoiserName(
|
|
TEXT("r.PathTracing.Denoiser.Name"),
|
|
"NNEDenoiser",
|
|
TEXT("Set the spatial denoiser name. It is the corresponding name registered by a denoiser plugin\n")
|
|
TEXT("Any registered denoiser should be able to denoise a single frame spatially.\n")
|
|
);
|
|
|
|
TAutoConsoleVariable<FString> CVarPathTracingTemporalDenoiserName(
|
|
TEXT("r.PathTracing.TemporalDenoiser.Name"),
|
|
"NFOR",
|
|
TEXT("Set the temporal denoiser name. It is the corresponding name registered by a denoiser plugin\n")
|
|
TEXT("The temporal denoiser usually has better temporal stability when rendering offline.\n")
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingSpatialDenoiserType(
|
|
TEXT("r.PathTracing.SpatialDenoiser.Type"),
|
|
0,
|
|
TEXT("The type of spatial denoiser\n")
|
|
TEXT("0: Use spatial denoiser only plugin\n")
|
|
TEXT("1: Use spatial denoiser plugin that also provides temporal denoising\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiser(
|
|
TEXT("r.PathTracing.TemporalDenoiser"),
|
|
0,
|
|
TEXT("Enable temporal denoising of the path traced output\n")
|
|
TEXT("-1: inherit from PostProcessVolume (TODO when out of experimental phase)\n")
|
|
TEXT("0: disable denoiser\n")
|
|
TEXT("1: enable denoiser (if a denoiser plugin is active)\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserType(
|
|
TEXT("r.PathTracing.TemporalDenoiser.Type"),
|
|
0,
|
|
TEXT("The type of temporal denoiser\n")
|
|
TEXT("0: Use the built-in temporal denoiser\n")
|
|
TEXT("1: Use the temporal denoiser from plugin\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserMotionVectorType(
|
|
TEXT("r.PathTracing.TemporalDenoiser.MotionVector.Type"),
|
|
0,
|
|
TEXT("The type of motion vecotr estimation algorithm\n")
|
|
TEXT("0: Built-in motion vector estimator\n")
|
|
TEXT("1: Motion vector estimator from the plugin\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserVisualizeMotionVector(
|
|
TEXT("r.PathTracing.TemporalDenoiser.VisualizeMotionVector"),
|
|
0,
|
|
TEXT("1: visualize the motion vector compared to the raster motion vector\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserEnableSubPixelOffset(
|
|
TEXT("r.PathTracing.TemporalDenoiser.EnableSubPixelOffset"),
|
|
1,
|
|
TEXT("Enable subpixel offset when merging\n")
|
|
TEXT("-1: inherit from PostProcessVolume\n")
|
|
TEXT("0: disable denoiser\n")
|
|
TEXT("1: enable denoiser (if a denoiser plugin is active)\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<float> CVarPathTracingTemporalDenoiserKappa(
|
|
TEXT("r.PathTracing.TemporalDenoiser.kappa"),
|
|
-1.0f,
|
|
TEXT("Scaling parameter to determine how fast the history weight falls and the cutting point to zero. Use DeltaE to derive kappa if -1\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<float> CVarPathTracingTemporalDenoiserEta(
|
|
TEXT("r.PathTracing.TemporalDenoiser.eta"),
|
|
1.0f,
|
|
TEXT("Eta param. Error distance below this will have max history weight. Use DeltaE to derive Eta if -1\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<float> CVarPathTracingTemporalDenoiserDeltaE(
|
|
TEXT("r.PathTracing.TemporalDenoiser.DeltaE"),
|
|
5.0f,
|
|
TEXT("Cut off the history weight to zero at CIE DeltaE for low frequency.\n")
|
|
TEXT("1.0 :the just noticeable difference (JND),\n")
|
|
TEXT("2.0 :perceptible for close look\n")
|
|
TEXT("10.0:Perceptible at a glance ")
|
|
TEXT("This works as an alternative control instead of kappa. 2 as default."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<float> CVarPathTracingTemporalDenoiserDeltaEHighFrequency(
|
|
TEXT("r.PathTracing.TemporalDenoiser.DeltaE.HighFrequency"),
|
|
2.1f,
|
|
TEXT("Cut off the history weight to zero when using high frequency per pixel difference.\n")
|
|
TEXT("It should only be enabled when the source image is smooth or denoised."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<float> CVarPathTracingTemporalDenoiserAlpha(
|
|
TEXT("r.PathTracing.TemporalDenoiser.alpha"),
|
|
1.0f,
|
|
TEXT("The weight of history in the exponential mean average\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserMode(
|
|
TEXT("r.PathTracing.TemporalDenoiser.mode"),
|
|
1,
|
|
TEXT("0: disabled \n")
|
|
TEXT("1: offline rendering only\n")
|
|
TEXT("2: online rendering (for debug)\n"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserSource(
|
|
TEXT("r.PathTracing.TemporalDenoiser.source"),
|
|
0,
|
|
TEXT("0: Denoised Radance when possible (Default) \n")
|
|
TEXT("1: Normal\n")
|
|
TEXT("2: Albedo\n")
|
|
TEXT("3: Raw Radiance")
|
|
TEXT("Otherwise: Feature Fusion (TODO)"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserDenoiseSourceImageFirst(
|
|
TEXT("r.PathTracing.TemporalDenoiser.DenoiseSourceImageFirst"),
|
|
0,
|
|
TEXT("Denoise the source image with IntelImageDenoisier"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserSubPixelOffsetStartMip(
|
|
TEXT("r.PathTracing.TemporalDenoiser.SubPixelOffset.StartMip"),
|
|
8,
|
|
TEXT("From 0 to this mip, we will perform subpixel offset"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserMotionOperation(
|
|
TEXT("r.PathTracing.TemporalDenoiser.MotionOperation"),
|
|
1,
|
|
TEXT("0: use the motion vector directly estimated")
|
|
TEXT("1: subtract between the motion"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserVisWarp(
|
|
TEXT("r.PathTracing.TemporalDenoiser.VisWarp"),
|
|
0,
|
|
TEXT("0: disable")
|
|
TEXT("1: visualize warped source by the motion vector")
|
|
TEXT("2: weights, warped source, and combined"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserDistanceMetrics(
|
|
TEXT("r.PathTracing.TemporalDenoiser.DistanceMetrics"),
|
|
2,
|
|
TEXT("0: Luminance based metrics for distance estimation. Color with same luminance will create error in motion and history weights estimation.")
|
|
TEXT("1: Direct color difference")
|
|
TEXT("2: Visual color difference based on CIELAB2000 color difference."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserTotalVariation(
|
|
TEXT("r.PathTracing.TemporalDenoiser.TotalVariation"),
|
|
1,
|
|
TEXT("!=0: Use less history if the total variation is large in a local patch"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarPathTracingTemporalDenoiserPatchCount(
|
|
TEXT("r.PathTracing.TemporalDenoiser.PatchCount"),
|
|
1,
|
|
TEXT("The number of similar patches found by Non-Local Mean to use for temporal denoising\n")
|
|
TEXT("1: default. Accumulae the one with the minimal distance exponentially.")
|
|
TEXT(">1 && < 16: Use bilaterial filtering to accumulate multiple patches."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
DECLARE_GPU_STAT(PathTracingSpatialTemporalDenoising);
|
|
}
|
|
|
|
int GetPathTracingDenoiserMode(const FViewInfo& View)
|
|
{
|
|
int DenoiserMode = CVarPathTracingDenoiser.GetValueOnRenderThread();
|
|
if (DenoiserMode < 0)
|
|
{
|
|
DenoiserMode = View.FinalPostProcessSettings.PathTracingEnableDenoiser;
|
|
}
|
|
return DenoiserMode;
|
|
}
|
|
|
|
bool IsPathTracingDenoiserEnabled(const FViewInfo& View)
|
|
{
|
|
return GetPathTracingDenoiserMode(View) != 0 && FDenoiserManager::Get().HasDenoiser();
|
|
}
|
|
|
|
static bool ShouldDenoiseWithNormalInCameraSpace()
|
|
{
|
|
int NormalSpace = CVarPathTracingDenoiserNormalSpace.GetValueOnRenderThread();
|
|
return NormalSpace != 0;
|
|
}
|
|
|
|
enum class ESpatialDenoiserType : int32
|
|
{
|
|
NONE = -1,
|
|
SPATIAL_DENOISER_PLUGIN,
|
|
SPATIAL_TEMPORAL_DENOISER_PLUGIN,
|
|
MAX
|
|
};
|
|
|
|
enum class ETemporalDenoisingMode : uint32
|
|
{
|
|
ETDM_DISABLED,
|
|
ETDM_OFFLINE,
|
|
ETDM_ONLINE,
|
|
ETDM_MAX
|
|
};
|
|
|
|
enum class ETemporalDenoiserType : int32
|
|
{
|
|
NONE = -1,
|
|
BUILTIN_TEMPORAL_DENOISER,
|
|
SPATIAL_TEMPORAL_DENOISER_PLUGIN,
|
|
MAX
|
|
};
|
|
|
|
enum class ETemporalDenoiserMotionVectorType : int32
|
|
{
|
|
NONE = -1,
|
|
BUILTIN,
|
|
PLUGIN,
|
|
MAX
|
|
};
|
|
|
|
bool ShouldEnablePathTracingDenoiserRealtimeDebug()
|
|
{
|
|
int TemporalDenoiserMode = CVarPathTracingTemporalDenoiserMode.GetValueOnRenderThread();
|
|
TemporalDenoiserMode = FMath::Clamp(TemporalDenoiserMode, 0, static_cast<int32>(ETemporalDenoisingMode::ETDM_MAX));
|
|
ETemporalDenoisingMode Mode = static_cast<ETemporalDenoisingMode>(TemporalDenoiserMode);
|
|
|
|
return Mode == ETemporalDenoisingMode::ETDM_ONLINE;
|
|
}
|
|
|
|
static bool ShouldApplySpatialDenoiser()
|
|
{
|
|
return CVarPathTracingSpatialDenoiser.GetValueOnRenderThread() != 0;
|
|
}
|
|
|
|
|
|
TArray<ESpatialDenoiserType> GetAvailableSpatialDenoiserTypes()
|
|
{
|
|
TArray<ESpatialDenoiserType> Types;
|
|
if (FDenoiserManager::Get().HasSpatialTemporalDenoiser())
|
|
{
|
|
Types.Add(ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN);
|
|
}
|
|
|
|
if (FDenoiserManager::Get().HasSpatialDenoiser())
|
|
{
|
|
Types.Add(ESpatialDenoiserType::SPATIAL_DENOISER_PLUGIN);
|
|
}
|
|
|
|
if (Types.Num() == 0)
|
|
{
|
|
Types.Add(ESpatialDenoiserType::NONE);
|
|
}
|
|
return Types;
|
|
}
|
|
|
|
ESpatialDenoiserType GetSpatialDenoiserType()
|
|
{
|
|
int32 Type = CVarPathTracingSpatialDenoiserType.GetValueOnRenderThread();
|
|
|
|
Type = FMath::Clamp(Type,
|
|
static_cast<int32>(ESpatialDenoiserType::NONE) + 1,
|
|
static_cast<int32>(ESpatialDenoiserType::MAX) - 1);
|
|
|
|
ESpatialDenoiserType DenoiserType = static_cast<ESpatialDenoiserType>(Type);
|
|
|
|
if (DenoiserType == ESpatialDenoiserType::SPATIAL_DENOISER_PLUGIN && FDenoiserManager::Get().HasSpatialDenoiser())
|
|
{
|
|
return DenoiserType;
|
|
}
|
|
else if (DenoiserType == ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN && FDenoiserManager::Get().HasSpatialTemporalDenoiser())
|
|
{
|
|
return DenoiserType;
|
|
}
|
|
else
|
|
{
|
|
// Fallback to the one that is available instead of the requested one
|
|
DenoiserType = GetAvailableSpatialDenoiserTypes()[0];
|
|
}
|
|
|
|
return DenoiserType;
|
|
}
|
|
|
|
static bool ShouldApplyTemporalDenoiser(const FPathTracingSpatialTemporalDenoisingContext& DenoisingContext, const FViewInfo& View)
|
|
{
|
|
const bool bApplyTemporalDenoiser =
|
|
(CVarPathTracingTemporalDenoiser.GetValueOnAnyThread() == 1) &&
|
|
DenoisingContext.LastDenoisedRadianceTexture &&
|
|
DenoisingContext.LastDenoisedRadianceTexture != DenoisingContext.RadianceTexture;
|
|
|
|
return bApplyTemporalDenoiser;
|
|
}
|
|
|
|
ETemporalDenoiserType GetTemporalDenoiserType()
|
|
{
|
|
|
|
ESpatialDenoiserType SpatialDenoiserType = GetSpatialDenoiserType();
|
|
|
|
if ( SpatialDenoiserType == ESpatialDenoiserType::SPATIAL_DENOISER_PLUGIN)
|
|
{
|
|
return ETemporalDenoiserType::BUILTIN_TEMPORAL_DENOISER;
|
|
}
|
|
else if (SpatialDenoiserType == ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN)
|
|
{
|
|
return ETemporalDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN;
|
|
}
|
|
|
|
return ETemporalDenoiserType::NONE;
|
|
|
|
}
|
|
|
|
ETemporalDenoiserMotionVectorType GetTemporalDenoiserMotionVectorType()
|
|
{
|
|
int32 Type = CVarPathTracingTemporalDenoiserMotionVectorType.GetValueOnRenderThread();
|
|
|
|
Type = FMath::Clamp(Type,
|
|
static_cast<int32>(ETemporalDenoiserMotionVectorType::NONE) + 1,
|
|
static_cast<int32>(ETemporalDenoiserMotionVectorType::MAX) - 1);
|
|
|
|
return static_cast<ETemporalDenoiserMotionVectorType>(Type);
|
|
}
|
|
|
|
UE::Renderer::Private::IPathTracingDenoiser* GetActiveSpatialDenoiser(bool bMatch = false)
|
|
{
|
|
FString DenoiserName = CVarPathTracingDenoiserName.GetValueOnRenderThread();
|
|
return FDenoiserManager::Get().GetSpatialDenoiser(DenoiserName, bMatch);
|
|
}
|
|
|
|
UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser* GetActiveSpatialTemporalDenoiser(bool bMatch = false)
|
|
{
|
|
FString DenoiserName = CVarPathTracingTemporalDenoiserName.GetValueOnRenderThread();
|
|
return FDenoiserManager::Get().GetSpatialTemporalDenoiser(DenoiserName, bMatch);
|
|
}
|
|
|
|
ETextureCreateFlags GetExtraTextureCreateFlagsForDenoiser()
|
|
{
|
|
ESpatialDenoiserType SpatialDenoiserType = GetSpatialDenoiserType();
|
|
ETemporalDenoiserType TemporalDenoiserType = GetTemporalDenoiserType();
|
|
ETextureCreateFlags TextureCreateFlags = ETextureCreateFlags::None;
|
|
|
|
bool bThirdPartyDenoiserNeedsTextureCreateExtraFlags = FDenoiserManager::Get().NeedTextureCreateExtraFlags();
|
|
|
|
if (SpatialDenoiserType == ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN ||
|
|
TemporalDenoiserType == ETemporalDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN ||
|
|
bThirdPartyDenoiserNeedsTextureCreateExtraFlags)
|
|
{
|
|
TextureCreateFlags |= TexCreate_Shared | TexCreate_RenderTargetable;
|
|
}
|
|
|
|
return TextureCreateFlags;
|
|
}
|
|
|
|
static float GetHighFrequencyCutoffDeltaE()
|
|
{
|
|
return FMath::Max(1.0f, CVarPathTracingTemporalDenoiserDeltaEHighFrequency.GetValueOnRenderThread());
|
|
}
|
|
|
|
static bool ShouldRemoveSelfSubpixelOffset(int MipLevel)
|
|
{
|
|
bool bRemoveSelfSubpixelOffset = CVarPathTracingTemporalDenoiserMotionOperation.GetValueOnRenderThread() == 1
|
|
&& MipLevel <= CVarPathTracingTemporalDenoiserSubPixelOffsetStartMip.GetValueOnRenderThread()
|
|
&& CVarPathTracingTemporalDenoiserEnableSubPixelOffset.GetValueOnAnyThread() != 0;
|
|
|
|
return bRemoveSelfSubpixelOffset;
|
|
}
|
|
|
|
static float GetErrorDistanceBasedOnDeltaE(float DeltaE)
|
|
{
|
|
const float NormalizeDeltaEAndEuclideanDistanceToSameMean = 0.0141f;
|
|
float ErrorDistanceFromDeltaE = log2f(2 + DeltaE * NormalizeDeltaEAndEuclideanDistanceToSameMean);
|
|
return ErrorDistanceFromDeltaE;
|
|
}
|
|
|
|
static void GetBlendingFactor(float& Kappa, float& Eta, float& Alpha)
|
|
{
|
|
Kappa = CVarPathTracingTemporalDenoiserKappa.GetValueOnRenderThread();
|
|
Eta = CVarPathTracingTemporalDenoiserEta.GetValueOnRenderThread();
|
|
Alpha = CVarPathTracingTemporalDenoiserAlpha.GetValueOnRenderThread();
|
|
|
|
if (Eta == -1)
|
|
{
|
|
// Eta is set to 1 JND (just noticeable difference).
|
|
Eta = GetErrorDistanceBasedOnDeltaE(1.0f);
|
|
}
|
|
|
|
if (Kappa == -1)
|
|
{
|
|
// Use DeltaE to determine Kappa in our modified weight formula such that
|
|
// the history weight falls off to zero when we reaches DeltaE.
|
|
|
|
float DeltaE =CVarPathTracingTemporalDenoiserDeltaE.GetValueOnRenderThread();
|
|
DeltaE = FMath::Max(DeltaE, 1.0f + 1e-6f);
|
|
float FallOffToZeroErrorDistance = GetErrorDistanceBasedOnDeltaE(DeltaE);
|
|
Kappa = 1 / (FallOffToZeroErrorDistance - Eta);
|
|
}
|
|
}
|
|
|
|
static bool ShouldCompilePathTracingDenoiserShadersForProject(EShaderPlatform ShaderPlatform)
|
|
{
|
|
static const auto CVarLocalVariablePathTracing = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.PathTracing"));
|
|
const int PathTracing = CVarLocalVariablePathTracing ? CVarLocalVariablePathTracing->GetValueOnAnyThread() : 0;
|
|
|
|
return ShouldCompileRayTracingShadersForProject(ShaderPlatform) &&
|
|
FDataDrivenShaderPlatformInfo::GetSupportsPathTracing(ShaderPlatform) &&
|
|
PathTracing != 0;
|
|
}
|
|
|
|
static bool ShouldGenerateVarianceMap()
|
|
{
|
|
int32 PathTracingTemporalDenoiserSource = CVarPathTracingTemporalDenoiserSource.GetValueOnRenderThread();
|
|
return PathTracingTemporalDenoiserSource < 0 || PathTracingTemporalDenoiserSource > 3;
|
|
}
|
|
|
|
static bool ShouldVisualizePathTracingVelocityState(const FPathTracingSpatialTemporalDenoisingContext& DenoisingContext)
|
|
{
|
|
bool bVisualizeMotionVector = CVarPathTracingTemporalDenoiserVisualizeMotionVector.GetValueOnRenderThread() != 0;
|
|
|
|
return bVisualizeMotionVector && DenoisingContext.MotionVector;
|
|
}
|
|
|
|
static bool ShouldVisualizeWarping(const FPathTracingSpatialTemporalDenoisingContext& DenoisingContext)
|
|
{
|
|
return CVarPathTracingTemporalDenoiserVisWarp.GetValueOnRenderThread() != 0 &&
|
|
DenoisingContext.MotionVector && DenoisingContext.LastDenoisedRadianceTexture;
|
|
}
|
|
|
|
static int32 GetTemporalAccumulationPatchCount()
|
|
{
|
|
return FMath::Clamp(CVarPathTracingTemporalDenoiserPatchCount.GetValueOnRenderThread(), 1, 16);
|
|
}
|
|
|
|
static bool ShouldUseTotalVariation(uint32 MipLevel)
|
|
{
|
|
return CVarPathTracingTemporalDenoiserTotalVariation.GetValueOnRenderThread() != 0.0f &&
|
|
(MipLevel == 0) &&
|
|
CVarPathTracingTemporalDenoiserEnableSubPixelOffset.GetValueOnAnyThread() != 0.0f;
|
|
}
|
|
|
|
static bool ShouldEnableSubpixelOffset(uint32 MipLevel)
|
|
{
|
|
uint32 PixelOffsetStartMip = CVarPathTracingTemporalDenoiserSubPixelOffsetStartMip.GetValueOnRenderThread();
|
|
bool bShouldEnableSubpixelOffset = (MipLevel <= PixelOffsetStartMip) &&
|
|
CVarPathTracingTemporalDenoiserEnableSubPixelOffset.GetValueOnAnyThread() != 0;
|
|
|
|
return bShouldEnableSubpixelOffset;
|
|
}
|
|
|
|
static bool IsVarianceTextureRequiredForCurrentDenoiser()
|
|
{
|
|
bool NeedVarianceTexture = false;
|
|
using UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser;
|
|
IPathTracingSpatialTemporalDenoiser* ActiveSpatialTemporalDenoiser = nullptr;
|
|
|
|
if (GetSpatialDenoiserType() == ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN)
|
|
{
|
|
ActiveSpatialTemporalDenoiser = GetActiveSpatialTemporalDenoiser();
|
|
}
|
|
else
|
|
{
|
|
FString DenoiserName = CVarPathTracingDenoiserName.GetValueOnRenderThread();
|
|
ActiveSpatialTemporalDenoiser = FDenoiserManager::Get().GetSpatialTemporalDenoiser(DenoiserName, /*bMatch*/true);
|
|
}
|
|
|
|
if (ActiveSpatialTemporalDenoiser)
|
|
{
|
|
NeedVarianceTexture = ActiveSpatialTemporalDenoiser->NeedVarianceTexture();
|
|
}
|
|
|
|
return NeedVarianceTexture;
|
|
}
|
|
|
|
static bool ShouldPrepassOutputVarianceTexture(const FViewInfo& View)
|
|
{
|
|
static const auto CVarOutputPostProcessResources =
|
|
IConsoleManager::Get().FindTConsoleVariableDataBool(TEXT("r.PathTracing.OutputPostProcessResources"));
|
|
const bool bOutputPostProcessResources = CVarOutputPostProcessResources ?
|
|
CVarOutputPostProcessResources->GetValueOnRenderThread() : false;
|
|
|
|
// Variance texture will be available if
|
|
// 1. when we always output so it can be accessed for debug
|
|
// 2. post process requires and we allow output post process resource in path tracing
|
|
// 3. the denoiser requires a variance texture.
|
|
return CVarPathTracingDenoiserPrepassOutputVarianceTexture.GetValueOnRenderThread() != 0 ||
|
|
(bOutputPostProcessResources && IsPathTracingVarianceTextureRequiredInPostProcessMaterial(View)) ||
|
|
IsVarianceTextureRequiredForCurrentDenoiser();
|
|
}
|
|
|
|
static constexpr uint32 kMipDiffDelta = 2;
|
|
|
|
static constexpr uint32 kNumberOfPixelShifts = 25;
|
|
static constexpr uint32 kNumberOfShiftsPerTexture = 4;
|
|
static constexpr uint32 kNumberOfPasses = 1;
|
|
static constexpr uint32 kNumberOfShiftsPerPass = kNumberOfShiftsPerTexture * kNumberOfPasses;
|
|
static constexpr uint32 kNumberOfTexturesPerPass = (kNumberOfPixelShifts + kNumberOfShiftsPerPass - 1) / kNumberOfShiftsPerPass;
|
|
|
|
static constexpr uint32 kThreadSize = 8;
|
|
|
|
static_assert(kNumberOfTexturesPerPass <= 7, "The number of buffers for Pixel correspondence estimation can not exceed seven per pass");
|
|
|
|
static const TCHAR* DistanceTextureNames[7] =
|
|
{
|
|
TEXT("PathTracing.EstimateMotion.Disntace.0"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.1"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.2"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.3"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.4"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.5"),
|
|
TEXT("PathTracing.EstimateMotion.Disntace.6"),
|
|
};
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FDenoisingCommonParameters, )
|
|
// Constant variable in each pass
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, SharedTextureSampler)
|
|
SHADER_PARAMETER(uint32, PatchCount)
|
|
SHADER_PARAMETER(uint32, NumOfMips)
|
|
|
|
// Dynamic variable in each subpass.
|
|
SHADER_PARAMETER(uint32, PatchId)
|
|
SHADER_PARAMETER(uint32, MipLevel)
|
|
END_SHADER_PARAMETER_STRUCT();
|
|
|
|
|
|
class FTemporalReprojectionAlignCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalReprojectionAlignCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalReprojectionAlignCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, PixelOffsetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, SourceTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, TargetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV_ARRAY(RWTexture2D<float4>, RWDistanceTextures, [kNumberOfTexturesPerPass])
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
enum class EDistanceMetrics : uint32 {
|
|
METRICS_LUMINANCE,
|
|
METRICS_EUCLIDEAN,
|
|
METRICS_PERCEPTION,
|
|
MAX
|
|
};
|
|
|
|
class FDistanceMetrics : SHADER_PERMUTATION_ENUM_CLASS("DISTANCE_METRICS", EDistanceMetrics);
|
|
using FPermutationDomain = TShaderPermutationDomain<FDistanceMetrics>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_REPROJECTION_ALIGN"), 1);
|
|
OutEnvironment.SetDefine(TEXT("K_NUM_OF_TEXTURES_PER_PASS"), kNumberOfTexturesPerPass);
|
|
}
|
|
|
|
static EDistanceMetrics GetDistanceMetrics()
|
|
{
|
|
uint32 DistanceMetrics = CVarPathTracingTemporalDenoiserDistanceMetrics.GetValueOnRenderThread();
|
|
DistanceMetrics = FMath::Clamp(DistanceMetrics,
|
|
static_cast<uint32>(EDistanceMetrics::METRICS_LUMINANCE),
|
|
static_cast<uint32>(EDistanceMetrics::MAX) - 1);
|
|
|
|
return static_cast<EDistanceMetrics>(DistanceMetrics);
|
|
}
|
|
|
|
static const TCHAR* GetEventName(EDistanceMetrics DistanceMetrics)
|
|
{
|
|
static const TCHAR* const kEventNames[] = {
|
|
TEXT("Luminance"),
|
|
TEXT("Euclidean"),
|
|
TEXT("Perception")
|
|
};
|
|
static_assert(UE_ARRAY_COUNT(kEventNames) == int32(EDistanceMetrics::MAX), "Fix me");
|
|
return kEventNames[static_cast<uint32>(DistanceMetrics)];
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalReprojectionAlignCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "ReprojectionAlignCS", SF_Compute);
|
|
|
|
class FTemporalReprojectionBlurCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalReprojectionBlurCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalReprojectionBlurCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, InputTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, OutputTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FDimensionDirectCopy : SHADER_PERMUTATION_BOOL("DIRECT_COPY");
|
|
using FPermutationDomain = TShaderPermutationDomain<FDimensionDirectCopy>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_REPROJECTION_BLUR"), 1);
|
|
OutEnvironment.SetDefine(TEXT("K_NUM_OF_TEXTURES_PER_PASS"), kNumberOfTexturesPerPass);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalReprojectionBlurCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "ReprojectionBlurCS", SF_Compute);
|
|
|
|
class FTemporalReprojectionMergeCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalReprojectionMergeCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalReprojectionMergeCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV_ARRAY(Texture2D<float4>, DistanceTextures, [kNumberOfTexturesPerPass])
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, PixelOffsetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWPixelOffsetTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FSubpixelOffset : SHADER_PERMUTATION_BOOL("SUBPIXEL_OFFSET");
|
|
class FTotalVariation : SHADER_PERMUTATION_BOOL("TOTAL_VARIATION");
|
|
using FPermutationDomain = TShaderPermutationDomain<FSubpixelOffset,FTotalVariation>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_REPROJECTION_MERGE"), 1);
|
|
OutEnvironment.SetDefine(TEXT("K_NUM_OF_TEXTURES_PER_PASS"), kNumberOfTexturesPerPass);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);
|
|
}
|
|
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalReprojectionMergeCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "ReprojectionMergeCS", SF_Compute);
|
|
|
|
class FMotionVectorSubtractCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FMotionVectorSubtractCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FMotionVectorSubtractCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, Minuend)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, Subtrahend)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("MOTION_VECTOR_SUBTRACT"), 1);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FMotionVectorSubtractCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "MotionVectorSubtractCS", SF_Compute);
|
|
|
|
// Warp the history texture, and use local high frequency to adjust the final blending factor.
|
|
class FTemporalHighFrequencyRejectMapCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalHighFrequencyRejectMapCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalHighFrequencyRejectMapCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER(float, HighFrequencyCutoffDeltaE)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, SourceTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, TargetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, PixelOffsetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, OutputTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_HIGHFREQ_REJECT"), 1);
|
|
OutEnvironment.SetDefine(TEXT("K_NUM_OF_TEXTURES_PER_PASS"), kNumberOfTexturesPerPass);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalHighFrequencyRejectMapCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "TemporalHighFrequencyRejectCS", SF_Compute);
|
|
|
|
enum class EFeatureFusionCategory : uint32
|
|
{
|
|
SOURCE,
|
|
TARGET,
|
|
MAX
|
|
};
|
|
|
|
static constexpr uint32 kNumOfFeatureFusionCategory = static_cast<uint32>(EFeatureFusionCategory::MAX);
|
|
|
|
class FTemporalFeatureFusionCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalFeatureFusionCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalFeatureFusionCS, FGlobalShader)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV_ARRAY(Texture2D, AlbedoTexture, [kNumOfFeatureFusionCategory])
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV_ARRAY(Texture2D, NormalTexture, [kNumOfFeatureFusionCategory])
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV_ARRAY(Texture2D, RadianceTexture, [kNumOfFeatureFusionCategory])
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV_ARRAY(StructuredBuffer<FPixelMaterialLightingFingerprint>, VarianceMap,[kNumOfFeatureFusionCategory])
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, LastDenoisedRadiance)
|
|
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, SharedTextureSampler)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV_ARRAY(RWTexture2D<float4>, OutputTexture, [kNumOfFeatureFusionCategory])
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_FEATURE_FUSION"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalFeatureFusionCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "TemporalFeatureFusionCS", SF_Compute);
|
|
|
|
|
|
class FTemporalResolveCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalResolveCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalResolveCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER(float, Kappa)
|
|
SHADER_PARAMETER(float, Eta)
|
|
SHADER_PARAMETER(float, Alpha)
|
|
SHADER_PARAMETER(float, HighFrequencyCutoffDeltaE)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDenoisingCommonParameters, DenoisingCommonParameters)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, SourceTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, TargetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, PixelOffsetTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, HighFrequencyRejectMap)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, OutputTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_REPROJECTION_RESOLVE"), 1);
|
|
OutEnvironment.SetDefine(TEXT("K_NUM_OF_TEXTURES_PER_PASS"), kNumberOfTexturesPerPass);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalResolveCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "TemporalResolveCS", SF_Compute);
|
|
|
|
// Add Spatial denoiser
|
|
class FSpatialDenoiserCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FSpatialDenoiserCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FSpatialDenoiserCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputNormal)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputAlbedo)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, OutputTexture)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("SPATIAL_DENOISING"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FSpatialDenoiserCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "SpatialDenoiserCS", SF_Compute);
|
|
|
|
class FConvertWorldSpaceNormalToCameraSpaceCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FConvertWorldSpaceNormalToCameraSpaceCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FConvertWorldSpaceNormalToCameraSpaceCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, NormalTexture)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER(float, Width)
|
|
SHADER_PARAMETER(float, Height)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("PREPROCESS_BUFFER"), 1);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FConvertWorldSpaceNormalToCameraSpaceCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "ConvertWorldSpaceNormalToCameraSpaceCS", SF_Compute);
|
|
|
|
static void ConvertNormalSpace(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FRDGTextureRef NormalTexture)
|
|
{
|
|
typedef FConvertWorldSpaceNormalToCameraSpaceCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->NormalTexture = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(NormalTexture));
|
|
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
|
|
PassParameters->Width = NormalTexture->Desc.GetSize().X;
|
|
PassParameters->Height = NormalTexture->Desc.GetSize().Y;
|
|
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ConvertWorldSpaceNormalToCameraSpace %dx%d",
|
|
View.ViewRect.Width(),
|
|
View.ViewRect.Height()),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(View.ViewRect.Size(), 8));
|
|
}
|
|
|
|
static void PathTracingDenoiserPlugin(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
int DenoiserMode,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef AlbedoTexture,
|
|
FRDGTextureRef NormalTexture,
|
|
FRDGTextureRef DepthTexture,
|
|
FRDGTextureRef VarianceTexture,
|
|
FRDGTextureRef OutputTexture)
|
|
{
|
|
FRDGTextureRef ProcessedNormalTexture = NormalTexture;
|
|
|
|
if (ShouldDenoiseWithNormalInCameraSpace())
|
|
{
|
|
const FRDGTextureDesc& Desc = NormalTexture->Desc;
|
|
ProcessedNormalTexture = GraphBuilder.CreateTexture(Desc, TEXT("PathTracing.CameraSpaceNormal"));
|
|
{
|
|
FRHICopyTextureInfo CopyInfo;
|
|
CopyInfo.Size.X = Desc.Extent.X;
|
|
CopyInfo.Size.Y = Desc.Extent.Y;
|
|
CopyInfo.Size.Z = 1;
|
|
CopyInfo.NumMips = Desc.NumMips;
|
|
|
|
AddCopyTexturePass(GraphBuilder, NormalTexture, ProcessedNormalTexture, CopyInfo);
|
|
}
|
|
ConvertNormalSpace(GraphBuilder, View, ProcessedNormalTexture);
|
|
}
|
|
|
|
/**
|
|
* First try to use the matched denoiser to denoise.
|
|
* If the requested denoiser is not available, fallback to the spatial denoiser.
|
|
*/
|
|
bool bMatch = true;
|
|
if (UE::Renderer::Private::IPathTracingDenoiser* ActiveSpatialDenoiser = GetActiveSpatialDenoiser(bMatch); ActiveSpatialDenoiser)
|
|
{
|
|
ActiveSpatialDenoiser->AddPasses(GraphBuilder, View, { InputTexture, AlbedoTexture, NormalTexture, OutputTexture });
|
|
}
|
|
else
|
|
{
|
|
using UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser;
|
|
|
|
FString DenoiserName = CVarPathTracingDenoiserName.GetValueOnRenderThread();
|
|
IPathTracingSpatialTemporalDenoiser* ActiveSpatialTemporalDenoiser = FDenoiserManager::Get().GetSpatialTemporalDenoiser(DenoiserName,bMatch);
|
|
|
|
if (ActiveSpatialTemporalDenoiser)
|
|
{
|
|
/**
|
|
* Force the temporal denoiser to denoise a single frame.
|
|
*/
|
|
IPathTracingSpatialTemporalDenoiser::FInputs Inputs;
|
|
Inputs.ColorTex = InputTexture;
|
|
Inputs.AlbedoTex = AlbedoTexture;
|
|
Inputs.NormalTex = NormalTexture;
|
|
Inputs.DepthTex = DepthTexture;
|
|
Inputs.VarianceTex = VarianceTexture;
|
|
|
|
// Set flow texture to black
|
|
Inputs.FlowTex = GraphBuilder.CreateTexture(InputTexture->Desc, TEXT("PathTracing.OpticalFlow"));
|
|
AddClearRenderTargetPass(GraphBuilder, Inputs.FlowTex, FLinearColor::Black);
|
|
|
|
Inputs.PreviousOutputTex = InputTexture;
|
|
Inputs.OutputTex = OutputTexture;
|
|
Inputs.DenoisingFrameId = 0;
|
|
Inputs.bForceSpatialDenoiserOnly = true; // Force to use spatial denoiser.
|
|
|
|
ActiveSpatialTemporalDenoiser->AddPasses(GraphBuilder, View, Inputs);
|
|
}
|
|
else
|
|
{
|
|
//fallback to the default spatial denoiser
|
|
bMatch = false;
|
|
GetActiveSpatialDenoiser(bMatch)->AddPasses(GraphBuilder, View, { InputTexture, AlbedoTexture, NormalTexture, OutputTexture });
|
|
}
|
|
}
|
|
}
|
|
|
|
static void PathTracingSpatialTemporalDenoiserPlugin(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
int DenoiserMode,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef AlbedoTexture,
|
|
FRDGTextureRef NormalTexture,
|
|
FRDGTextureRef DepthTexture,
|
|
FRDGTextureRef FlowTexture,
|
|
FRDGTextureRef PreviousOutputFrameTexture,
|
|
FRDGTextureRef OutputTexture,
|
|
int DenoisingFrameId,
|
|
bool bForceSpatialDenoiserOnly,
|
|
FPathTracingSpatialTemporalDenoisingContext& Context)
|
|
{
|
|
check(GetActiveSpatialTemporalDenoiser());
|
|
|
|
FRDGTextureRef ProcessedNormalTexture = NormalTexture;
|
|
|
|
if (ShouldDenoiseWithNormalInCameraSpace())
|
|
{
|
|
const FRDGTextureDesc& Desc = NormalTexture->Desc;
|
|
ProcessedNormalTexture = GraphBuilder.CreateTexture(Desc, TEXT("PathTracing.CameraSpaceNormal"));
|
|
{
|
|
FRHICopyTextureInfo CopyInfo;
|
|
CopyInfo.Size.X = Desc.Extent.X;
|
|
CopyInfo.Size.Y = Desc.Extent.Y;
|
|
CopyInfo.Size.Z = 1;
|
|
CopyInfo.NumMips = Desc.NumMips;
|
|
|
|
AddCopyTexturePass(GraphBuilder, NormalTexture, ProcessedNormalTexture, CopyInfo);
|
|
}
|
|
ConvertNormalSpace(GraphBuilder, View, ProcessedNormalTexture);
|
|
}
|
|
|
|
using UE::Renderer::Private::IPathTracingSpatialTemporalDenoiser;
|
|
|
|
IPathTracingSpatialTemporalDenoiser::FInputs Inputs;
|
|
Inputs.ColorTex = InputTexture;
|
|
Inputs.AlbedoTex = AlbedoTexture;
|
|
Inputs.NormalTex = NormalTexture;
|
|
Inputs.DepthTex = DepthTexture;
|
|
Inputs.VarianceTex = Context.VarianceTexture;
|
|
Inputs.OutputTex = OutputTexture;
|
|
Inputs.FlowTex = FlowTexture;
|
|
Inputs.PreviousOutputTex = PreviousOutputFrameTexture;
|
|
Inputs.DenoisingFrameId = DenoisingFrameId;
|
|
Inputs.bForceSpatialDenoiserOnly = bForceSpatialDenoiserOnly;
|
|
|
|
if (Context.SpatialTemporalDenoiserHistory &&
|
|
Context.SpatialTemporalDenoiserHistory->GetDebugName() == GetActiveSpatialTemporalDenoiser()->GetDebugName())
|
|
{
|
|
Inputs.PrevHistory = Context.SpatialTemporalDenoiserHistory;
|
|
}
|
|
|
|
IPathTracingSpatialTemporalDenoiser::FOutputs Outputs = GetActiveSpatialTemporalDenoiser()->AddPasses(GraphBuilder, View, Inputs);
|
|
if (Outputs.NewHistory)
|
|
{
|
|
Context.SpatialTemporalDenoiserHistory = Outputs.NewHistory;
|
|
}
|
|
}
|
|
|
|
static bool ShouldApplyPreExposureToMotionVectorEstimation()
|
|
{
|
|
int32 DenoiserSource = CVarPathTracingTemporalDenoiserSource.GetValueOnRenderThread();
|
|
if (DenoiserSource == 0 || DenoiserSource == 3)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void PathTracingMotionVectorPlugin(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FRDGTextureRef InputFrameTexture,
|
|
FRDGTextureRef ReferenceFrameTexture,
|
|
FRDGTextureRef OutputTexture)
|
|
{
|
|
check(GetActiveSpatialTemporalDenoiser());
|
|
|
|
bool bShouldApplyPreExposure = ShouldApplyPreExposureToMotionVectorEstimation();
|
|
float PreExposure = bShouldApplyPreExposure ? View.PreExposure : 1.0f;
|
|
|
|
GetActiveSpatialTemporalDenoiser()->AddMotionVectorPass(GraphBuilder, View, {InputFrameTexture, ReferenceFrameTexture, OutputTexture, PreExposure});
|
|
}
|
|
|
|
class FMotionVectorEstimationContext
|
|
{
|
|
public:
|
|
|
|
const TCHAR* PixelOffsetTextureNames[2] = {
|
|
TEXT("PathTracing.EstimateMotion.PixelOffset.Ping"),
|
|
TEXT("PathTracing.EstimateMotion.PixelOffset.Pong"),
|
|
};
|
|
|
|
FRDGTextureRef PixelOffsetTextures[2];
|
|
FScreenPassTextureViewport TargetViewport;
|
|
|
|
FRDGTextureDesc TextureWithNMipsDescriptor;
|
|
FRDGTextureDesc TextureDescriptor;
|
|
FRDGTextureDesc TextureDescriptorFinalOutput;
|
|
|
|
FRDGTextureRef SourceTexture;
|
|
FRDGTextureRef TargetTexture;
|
|
|
|
FRDGTextureRef SourceMipTexture;
|
|
FRDGTextureRef TargetMipTexture;
|
|
FRHISamplerState* BilinearClampSampler;
|
|
|
|
FRDGTextureRef DistanceTextures[kNumberOfTexturesPerPass];
|
|
FDenoisingCommonParameters DenoisingCommonParameters;
|
|
|
|
public:
|
|
|
|
FMotionVectorEstimationContext(FRDGTextureRef InSourceTexture,
|
|
FRDGTextureRef InTargetTexture):
|
|
SourceTexture(InSourceTexture),
|
|
TargetTexture(InTargetTexture){}
|
|
|
|
bool InitContext(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View)
|
|
{
|
|
TargetViewport = FScreenPassTextureViewport(View.ViewRect);
|
|
uint32 NumOfMips = FMath::Min(7u, 1 + FMath::FloorLog2((uint32)TargetViewport.Extent.GetMin()));
|
|
|
|
if (!ensureMsgf(NumOfMips == 7u, TEXT("The image is too small to estimate temporal reprojection NumOfMips(%d)< 7"), NumOfMips))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Set up common denoising parameters for shader
|
|
{
|
|
DenoisingCommonParameters.ViewUniformBuffer = View.ViewUniformBuffer;
|
|
DenoisingCommonParameters.TargetViewport = GetScreenPassTextureViewportParameters(TargetViewport);
|
|
DenoisingCommonParameters.SharedTextureSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
DenoisingCommonParameters.PatchCount = GetTemporalAccumulationPatchCount();
|
|
DenoisingCommonParameters.NumOfMips = NumOfMips;
|
|
}
|
|
|
|
TextureWithNMipsDescriptor = FRDGTextureDesc::Create2D(
|
|
TargetViewport.Extent,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding(),
|
|
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV,
|
|
NumOfMips);
|
|
|
|
TextureDescriptor = FRDGTextureDesc::Create2D(
|
|
TargetViewport.Extent,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding(),
|
|
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV);
|
|
|
|
TextureDescriptorFinalOutput = FRDGTextureDesc::Create2D(
|
|
TargetViewport.Extent,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding(),
|
|
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV | GetExtraTextureCreateFlagsForDenoiser());
|
|
|
|
PixelOffsetTextures[0] = GraphBuilder.CreateTexture(TextureWithNMipsDescriptor, PixelOffsetTextureNames[0]);
|
|
PixelOffsetTextures[1] = GraphBuilder.CreateTexture(TextureWithNMipsDescriptor, PixelOffsetTextureNames[1]);
|
|
|
|
FRDGTextureDesc SourceDesc = SourceTexture->Desc;
|
|
FRDGTextureDesc TargetDesc = TargetTexture->Desc;
|
|
|
|
// Copy and create the mipmap for both source and target texture
|
|
SourceMipTexture = GraphBuilder.CreateTexture(TextureWithNMipsDescriptor, TEXT("PathTracing.EstimateMotion.Source"));
|
|
TargetMipTexture = GraphBuilder.CreateTexture(TextureWithNMipsDescriptor, TEXT("PathTracing.EstimateMotion.Target"));
|
|
BilinearClampSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
|
|
{
|
|
FRHICopyTextureInfo CopyInfo;
|
|
CopyInfo.Size.X = FMath::Min(SourceDesc.Extent.X, TargetDesc.Extent.X);
|
|
CopyInfo.Size.Y = FMath::Min(SourceDesc.Extent.Y, TargetDesc.Extent.Y);
|
|
CopyInfo.Size.Z = 1;
|
|
CopyInfo.NumMips = FMath::Min(SourceDesc.NumMips, TargetDesc.NumMips);
|
|
|
|
AddCopyTexturePass(GraphBuilder, SourceTexture, SourceMipTexture, CopyInfo);
|
|
FGenerateMips::Execute(GraphBuilder, View.FeatureLevel, SourceMipTexture, BilinearClampSampler);
|
|
|
|
AddCopyTexturePass(GraphBuilder, TargetTexture, TargetMipTexture, CopyInfo);
|
|
FGenerateMips::Execute(GraphBuilder, View.FeatureLevel, TargetMipTexture, BilinearClampSampler);
|
|
}
|
|
|
|
for (int TextureId = 0; TextureId < kNumberOfTexturesPerPass; ++TextureId)
|
|
{
|
|
DistanceTextures[TextureId] = GraphBuilder.CreateTexture(TextureWithNMipsDescriptor, DistanceTextureNames[TextureId]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32 GetPatchCount() const
|
|
{
|
|
return DenoisingCommonParameters.PatchCount;
|
|
}
|
|
|
|
uint32 GetNumOfMips() const
|
|
{
|
|
return DenoisingCommonParameters.NumOfMips;
|
|
}
|
|
|
|
void UpdatePatchId(uint32 PatchId)
|
|
{
|
|
DenoisingCommonParameters.PatchId = PatchId;
|
|
}
|
|
|
|
void UpdateMipLevel(uint32 MipLevel)
|
|
{
|
|
DenoisingCommonParameters.MipLevel = MipLevel;
|
|
}
|
|
|
|
uint32 GetMipLevel() const
|
|
{
|
|
return DenoisingCommonParameters.MipLevel;
|
|
}
|
|
|
|
FIntVector GetAlignGroupCount() const
|
|
{
|
|
return FComputeShaderUtils::GetGroupCount(
|
|
FIntVector(TargetViewport.Extent.X, TargetViewport.Extent.Y, kNumberOfTexturesPerPass),
|
|
FIntVector(kThreadSize, kThreadSize, 1));
|
|
}
|
|
|
|
};
|
|
|
|
static void AlignTexture(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
const FMotionVectorEstimationContext& Context,
|
|
FRDGTextureSRVDesc PixelOffsetSRVDesc,
|
|
FRDGTextureRef SourceMipTexture,
|
|
FRDGTextureRef TargetMipTexture)
|
|
{
|
|
|
|
uint32 MipLevel = Context.GetMipLevel();
|
|
|
|
typedef FTemporalReprojectionAlignCS SHADER;
|
|
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->PixelOffsetTexture = GraphBuilder.CreateSRV(PixelOffsetSRVDesc);
|
|
PassParameters->SourceTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(SourceMipTexture, MipLevel));
|
|
PassParameters->TargetTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(TargetMipTexture, MipLevel));
|
|
PassParameters->DenoisingCommonParameters = Context.DenoisingCommonParameters;
|
|
|
|
for (int TextureId = 0; TextureId < kNumberOfTexturesPerPass; ++TextureId)
|
|
{
|
|
PassParameters->RWDistanceTextures[TextureId] = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(Context.DistanceTextures[TextureId], MipLevel));
|
|
}
|
|
|
|
SHADER::EDistanceMetrics DistanceMetrics = SHADER::GetDistanceMetrics();
|
|
SHADER::FPermutationDomain ComputeShaderPermutationVector;
|
|
ComputeShaderPermutationVector.Set<SHADER::FDistanceMetrics>(DistanceMetrics);
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap,ComputeShaderPermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::Align %dx%d (%s)",
|
|
Context.TargetViewport.Extent.X,
|
|
Context.TargetViewport.Extent.Y,
|
|
SHADER::GetEventName(DistanceMetrics)),
|
|
ComputeShader,
|
|
PassParameters,
|
|
Context.GetAlignGroupCount());
|
|
}
|
|
|
|
// Determine the image blur size based on the current mip level and image size.
|
|
// TODO: scale blur size based on viewport size
|
|
static int32 GetBlurSize(int32 MipLevel, FIntPoint ViewportExtent)
|
|
{
|
|
int BlurSize = 1;
|
|
|
|
switch (MipLevel)
|
|
{
|
|
case 0:
|
|
BlurSize = 3; break;
|
|
case 2:
|
|
BlurSize = 2; break;
|
|
default:
|
|
BlurSize = 1; break;
|
|
};
|
|
|
|
return BlurSize;
|
|
}
|
|
|
|
static void BlurDistanceMetrics(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
const FMotionVectorEstimationContext& Context)
|
|
{
|
|
struct FReprojectionBulrPassInfo
|
|
{
|
|
FReprojectionBulrPassInfo(const TCHAR* InName, FRDGTextureRef InInput, FRDGTextureRef InOutput)
|
|
:Name(InName), Input(InInput), Output(InOutput)
|
|
{}
|
|
|
|
const TCHAR* Name;
|
|
FRDGTextureRef Input;
|
|
FRDGTextureRef Output;
|
|
};
|
|
|
|
FRDGTextureRef TempBuffer = GraphBuilder.CreateTexture(Context.TextureWithNMipsDescriptor, TEXT("PathTracing.EstimateMotion.TempBuffer"));
|
|
uint32 MipLevel = Context.GetMipLevel();
|
|
int BlurSize = GetBlurSize(MipLevel, Context.TargetViewport.Extent);
|
|
|
|
for (int TextureId = 0; TextureId < kNumberOfTexturesPerPass; ++TextureId)
|
|
{
|
|
const int NumOfBlurPass = 2;
|
|
const FReprojectionBulrPassInfo BlurPassInfos[NumOfBlurPass] =
|
|
{
|
|
{TEXT("PathTracing::Denoising::Blur0"), Context.DistanceTextures[TextureId], TempBuffer},
|
|
{TEXT("PathTracing::Denoising::Blur1"), TempBuffer, Context.DistanceTextures[TextureId]}
|
|
};
|
|
|
|
for (int i = 0; i < BlurSize; ++i)
|
|
{
|
|
for (int PassIndex = 0; PassIndex < NumOfBlurPass; ++PassIndex)
|
|
{
|
|
|
|
FReprojectionBulrPassInfo PassInfo = BlurPassInfos[PassIndex];
|
|
FRDGTextureSRVDesc InputSRVDesc = FRDGTextureSRVDesc::CreateForMipLevel(PassInfo.Input, MipLevel);
|
|
FRDGTextureUAVDesc OutputUAVDesc(PassInfo.Output, MipLevel);
|
|
|
|
typedef FTemporalReprojectionBlurCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->InputTexture = GraphBuilder.CreateSRV(InputSRVDesc);
|
|
PassParameters->OutputTexture = GraphBuilder.CreateUAV(OutputUAVDesc);
|
|
PassParameters->DenoisingCommonParameters = Context.DenoisingCommonParameters;
|
|
|
|
SHADER::FPermutationDomain ComputeShaderPermutationVector;
|
|
ComputeShaderPermutationVector.Set<SHADER::FDimensionDirectCopy>(false);
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap, ComputeShaderPermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("%s %dx%d Mip=%d (DistPatch %d/%d)",
|
|
BlurPassInfos[PassIndex].Name,
|
|
Context.TargetViewport.Extent.X,
|
|
Context.TargetViewport.Extent.Y,
|
|
MipLevel,
|
|
TextureId + 1,
|
|
kNumberOfTexturesPerPass),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(Context.TargetViewport.Extent, 8));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MergeDistanceMetrics(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
const FMotionVectorEstimationContext& Context,
|
|
const FRDGTextureSRVDesc& LastPixelOffsetSRVDesc,
|
|
FRDGTextureRef TargetPixelOffsetTexture)
|
|
{
|
|
uint32 MipLevel = Context.GetMipLevel();
|
|
|
|
typedef FTemporalReprojectionMergeCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
for (int TextureId = 0; TextureId < kNumberOfTexturesPerPass; ++TextureId)
|
|
{
|
|
PassParameters->DistanceTextures[TextureId] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(Context.DistanceTextures[TextureId], MipLevel));
|
|
}
|
|
PassParameters->PixelOffsetTexture = GraphBuilder.CreateSRV(LastPixelOffsetSRVDesc);
|
|
PassParameters->RWPixelOffsetTexture = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(TargetPixelOffsetTexture, MipLevel));
|
|
PassParameters->DenoisingCommonParameters = Context.DenoisingCommonParameters;
|
|
|
|
bool bShouldUseTotalVariation = ShouldUseTotalVariation(MipLevel);
|
|
bool bShouldEnableSubpixelOffset = ShouldEnableSubpixelOffset(MipLevel);
|
|
|
|
SHADER::FPermutationDomain ComputeShaderPermutationVector;
|
|
ComputeShaderPermutationVector.Set<SHADER::FSubpixelOffset>(bShouldEnableSubpixelOffset);
|
|
ComputeShaderPermutationVector.Set<SHADER::FTotalVariation>(bShouldUseTotalVariation);
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap, ComputeShaderPermutationVector);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::Merge %dx%d",
|
|
Context.TargetViewport.Extent.X,
|
|
Context.TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(Context.TargetViewport.Extent, 8));
|
|
}
|
|
|
|
// Estimate the motion vector (pixel correspondence offset)
|
|
static FRDGTextureRef EstimateMotionVector(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FMotionVectorEstimationContext& Context)
|
|
{
|
|
int PixelOffsetIndex = 0;
|
|
int NumOfMips = Context.GetNumOfMips();
|
|
|
|
for (int MipLevel = NumOfMips - 1; MipLevel >= 0; MipLevel -= kMipDiffDelta)
|
|
{
|
|
Context.UpdateMipLevel(MipLevel);
|
|
|
|
for (int Pass = 0; Pass < kNumberOfPasses; ++Pass)
|
|
{
|
|
const bool UseBlackDummpy = ((MipLevel == (NumOfMips - 1)) && Pass == 0);
|
|
|
|
// Write the calibration subpixel offset to the source so that we can remove it.
|
|
FRDGTextureSRVDesc SelfLastPixelOffsetSRVDesk = FRDGTextureSRVDesc::CreateForMipLevel(
|
|
GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy, Context.PixelOffsetTextureNames[1]),
|
|
0);
|
|
|
|
FRDGTextureRef SelfTargetPixelOffsetTexture = Context.PixelOffsetTextures[PixelOffsetIndex % 2];
|
|
|
|
FRDGTextureSRVDesc PixelOffsetSRVDesc = FRDGTextureSRVDesc::CreateForMipLevel(
|
|
UseBlackDummpy ?
|
|
GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy, Context.PixelOffsetTextureNames[0]) :
|
|
Context.PixelOffsetTextures[PixelOffsetIndex % 2], UseBlackDummpy ? 0 : (MipLevel + kMipDiffDelta));
|
|
|
|
FRDGTextureRef TargetPixelOffsetTexture = Context.PixelOffsetTextures[(++PixelOffsetIndex) % 2];
|
|
|
|
// Calculate the subpixel offset for the source image, and write to the unused texture in the source mipmap
|
|
if(ShouldRemoveSelfSubpixelOffset(MipLevel))
|
|
{
|
|
AlignTexture(GraphBuilder, View, Context,
|
|
SelfLastPixelOffsetSRVDesk,
|
|
Context.SourceMipTexture,
|
|
Context.SourceMipTexture);
|
|
|
|
BlurDistanceMetrics(GraphBuilder, View,
|
|
Context);
|
|
|
|
// Merge: Find the smallest distance within [-2,2]^2
|
|
MergeDistanceMetrics(GraphBuilder, View,
|
|
Context,
|
|
SelfLastPixelOffsetSRVDesk,
|
|
SelfTargetPixelOffsetTexture);
|
|
}
|
|
|
|
// Calculate the subpixel offset between the source and the target
|
|
{
|
|
AlignTexture(GraphBuilder, View, Context,
|
|
PixelOffsetSRVDesc,
|
|
Context.SourceMipTexture,
|
|
Context.TargetMipTexture);
|
|
|
|
BlurDistanceMetrics(GraphBuilder, View,
|
|
Context);
|
|
|
|
// Merge: Find the smallest distance within [-2,2]^2
|
|
MergeDistanceMetrics(GraphBuilder, View,
|
|
Context,
|
|
PixelOffsetSRVDesc,
|
|
TargetPixelOffsetTexture);
|
|
}
|
|
|
|
// Subtract the distance from source to target
|
|
if (ShouldRemoveSelfSubpixelOffset(MipLevel))
|
|
{
|
|
typedef FMotionVectorSubtractCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->Minuend = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(TargetPixelOffsetTexture, MipLevel));
|
|
PassParameters->Subtrahend = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(SelfTargetPixelOffsetTexture, MipLevel));
|
|
PassParameters->DenoisingCommonParameters = Context.DenoisingCommonParameters;
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::MotionVectorDiff %dx%d (Mip=%d)",
|
|
Context.TargetViewport.Extent.X,
|
|
Context.TargetViewport.Extent.Y,
|
|
MipLevel),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(Context.TargetViewport.Extent, 8));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return Context.PixelOffsetTextures[PixelOffsetIndex % 2];
|
|
}
|
|
|
|
// combine albedo, normal, and radiance into a single feature texture
|
|
static void FuseTemporalFeature(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FPathTracingSpatialTemporalDenoisingContext& DenoisingContext,
|
|
FRDGTextureRef& OutSourceTexture,
|
|
FRDGTextureRef& OutTargetTexture)
|
|
{
|
|
const FScreenPassTextureViewport TargetViewport(View.ViewRect);
|
|
const FScreenPassTextureViewportParameters TargetViewportParameters = GetScreenPassTextureViewportParameters(TargetViewport);
|
|
|
|
const FRDGTextureDesc TextureDescriptor = FRDGTextureDesc::Create2D(
|
|
TargetViewport.Extent,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding(),
|
|
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV | GetExtraTextureCreateFlagsForDenoiser());
|
|
|
|
OutSourceTexture = GraphBuilder.CreateTexture(TextureDescriptor, TEXT("PathTracing.Denoising.Feature.Source"));
|
|
OutTargetTexture = GraphBuilder.CreateTexture(TextureDescriptor, TEXT("PathTracing.Denoising.Feature.Target"));
|
|
|
|
typedef FTemporalFeatureFusionCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
{
|
|
PassParameters->AlbedoTexture[0] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.LastAlbedoTexture));
|
|
PassParameters->AlbedoTexture[1] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.AlbedoTexture));
|
|
PassParameters->NormalTexture[0] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.LastNormalTexture));
|
|
PassParameters->NormalTexture[1] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.NormalTexture));
|
|
PassParameters->RadianceTexture[0] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.LastRadianceTexture));
|
|
PassParameters->RadianceTexture[1] = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.RadianceTexture));
|
|
PassParameters->VarianceMap[0] = GraphBuilder.CreateSRV(DenoisingContext.LastVarianceBuffer ?
|
|
DenoisingContext.LastVarianceBuffer : DenoisingContext.VarianceBuffer,EPixelFormat::PF_R32_FLOAT);
|
|
PassParameters->VarianceMap[1] = GraphBuilder.CreateSRV(DenoisingContext.VarianceBuffer, EPixelFormat::PF_R32_FLOAT);
|
|
PassParameters->OutputTexture[0] = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(OutSourceTexture));
|
|
PassParameters->OutputTexture[1] = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(OutTargetTexture));
|
|
|
|
PassParameters->LastDenoisedRadiance = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(DenoisingContext.LastDenoisedRadianceTexture));
|
|
|
|
PassParameters->SharedTextureSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
PassParameters->TargetViewport = TargetViewportParameters;
|
|
}
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::FeatureFusion %dx%d",
|
|
TargetViewport.Extent.X,
|
|
TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(TargetViewport.Extent, 8));
|
|
|
|
}
|
|
|
|
static bool SelectMotionSourceAndTargetTextures(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FRDGTextureRef InSourceTexture,
|
|
FRDGTextureRef InTargetTexture,
|
|
FPathTracingSpatialTemporalDenoisingContext& DenoisingContext,
|
|
FRDGTextureRef& MotionEstimationSourceTexture,
|
|
FRDGTextureRef& MotionEstimationTargetTexture)
|
|
{
|
|
int32 MotionSource = CVarPathTracingTemporalDenoiserSource.GetValueOnAnyThread();
|
|
|
|
switch (MotionSource)
|
|
{
|
|
case 3:
|
|
MotionEstimationSourceTexture = DenoisingContext.LastRadianceTexture;
|
|
MotionEstimationTargetTexture = DenoisingContext.RadianceTexture;
|
|
break;
|
|
case 2:
|
|
MotionEstimationSourceTexture = DenoisingContext.LastAlbedoTexture;
|
|
MotionEstimationTargetTexture = DenoisingContext.AlbedoTexture;
|
|
break;
|
|
case 1:
|
|
MotionEstimationSourceTexture = DenoisingContext.LastNormalTexture;
|
|
MotionEstimationTargetTexture = DenoisingContext.NormalTexture;
|
|
break;
|
|
case 0:
|
|
MotionEstimationSourceTexture = InSourceTexture;
|
|
MotionEstimationTargetTexture = InTargetTexture;
|
|
break;
|
|
default:
|
|
FuseTemporalFeature(GraphBuilder, View, DenoisingContext, MotionEstimationSourceTexture, MotionEstimationTargetTexture);
|
|
break;
|
|
}
|
|
|
|
return MotionEstimationSourceTexture->Desc.Extent == MotionEstimationTargetTexture->Desc.Extent;
|
|
}
|
|
|
|
// Estimate the motion vector from source to target
|
|
static FRDGTextureRef TemporalReprojectionWithoutMotionVector(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
FRDGTextureRef InSourceTexture,
|
|
FRDGTextureRef InTargetTexture,
|
|
FRDGTextureRef MotionEstimationSourceTexture,
|
|
FRDGTextureRef MotionEstimationTargetTexture,
|
|
FPathTracingSpatialTemporalDenoisingContext& DenoisingContext)
|
|
{
|
|
|
|
FMotionVectorEstimationContext EstimationContext(MotionEstimationSourceTexture, MotionEstimationTargetTexture);
|
|
|
|
if (!EstimationContext.InitContext(GraphBuilder, View))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FRDGTextureRef HighFrequencyRejectMap = GraphBuilder.CreateTexture(EstimationContext.TextureDescriptor, TEXT("PathTracing.EstimateMotion.HighFrequencyRejectMap"));
|
|
FRDGTextureRef FinalAccumulation = GraphBuilder.CreateTexture(EstimationContext.TextureDescriptorFinalOutput, TEXT("PathTracing.EstimateMotion.FinalAccumulation"));
|
|
int PatchCount = EstimationContext.GetPatchCount();
|
|
float HighFrequencyCutoffDeltaE = GetHighFrequencyCutoffDeltaE();
|
|
|
|
FRDGTextureRef TempAccumulation = nullptr;
|
|
if (PatchCount > 1)
|
|
{
|
|
TempAccumulation = GraphBuilder.CreateTexture(EstimationContext.TextureDescriptor, TEXT("PathTracing.EstimateMotion.TempAccumulation"));
|
|
}
|
|
|
|
// Perform accumulation on Miplevel 0
|
|
const uint32 AccumulationMipLevel = 0;
|
|
float Kappa, Eta, Alpha;
|
|
GetBlendingFactor(Kappa, Eta, Alpha);
|
|
|
|
for (int PatchId = 0; PatchId < PatchCount; ++PatchId)
|
|
{
|
|
EstimationContext.UpdatePatchId(PatchId);
|
|
|
|
FRDGTextureRef PixelOffsetTexture = EstimateMotionVector(
|
|
GraphBuilder,
|
|
View,
|
|
EstimationContext);
|
|
|
|
DenoisingContext.MotionVector = PixelOffsetTexture; // Used for debugging
|
|
|
|
// Final resolve, accumulate the temporal information based on the pixel offset texture
|
|
FRDGTextureRef BlendSourceTexture = InSourceTexture;
|
|
FRDGTextureRef BlendTargetTexture = (PatchId == 0) ? InTargetTexture : TempAccumulation;
|
|
FRDGTextureRef BlendFinalTexture = (PatchId + 1 == PatchCount)? FinalAccumulation: TempAccumulation;
|
|
|
|
EstimationContext.UpdateMipLevel(AccumulationMipLevel);
|
|
|
|
// Warp the source image so that we can adjust the blending weight based on high frequency information.
|
|
// E.g., if the source and target is the albedo. We can use visual perception difference of 1dE, 2dE or 10dE
|
|
{
|
|
typedef FTemporalHighFrequencyRejectMapCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->PixelOffsetTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(PixelOffsetTexture, AccumulationMipLevel));
|
|
PassParameters->SourceTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(BlendSourceTexture, AccumulationMipLevel));
|
|
PassParameters->TargetTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(InTargetTexture, AccumulationMipLevel));
|
|
PassParameters->OutputTexture = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(HighFrequencyRejectMap)); // the difference of the optimal shift.
|
|
PassParameters->DenoisingCommonParameters = EstimationContext.DenoisingCommonParameters;
|
|
PassParameters->HighFrequencyCutoffDeltaE = HighFrequencyCutoffDeltaE;
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::RejectionMap %dx%d",
|
|
EstimationContext.TargetViewport.Extent.X,
|
|
EstimationContext.TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(EstimationContext.TargetViewport.Extent, 8));
|
|
}
|
|
|
|
{
|
|
typedef FTemporalResolveCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
PassParameters->PixelOffsetTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(PixelOffsetTexture, AccumulationMipLevel));
|
|
PassParameters->SourceTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(BlendSourceTexture, AccumulationMipLevel));
|
|
PassParameters->TargetTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(BlendTargetTexture, AccumulationMipLevel));
|
|
PassParameters->HighFrequencyRejectMap = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMipLevel(HighFrequencyRejectMap, AccumulationMipLevel));
|
|
PassParameters->OutputTexture = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(BlendFinalTexture)); // the difference of the optimal shift.
|
|
PassParameters->DenoisingCommonParameters = EstimationContext.DenoisingCommonParameters;
|
|
|
|
PassParameters->HighFrequencyCutoffDeltaE = HighFrequencyCutoffDeltaE;
|
|
PassParameters->Alpha = Alpha;
|
|
PassParameters->Kappa = Kappa;
|
|
PassParameters->Eta = Eta;
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::TemporalResolve %dx%d",
|
|
EstimationContext.TargetViewport.Extent.X,
|
|
EstimationContext.TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(EstimationContext.TargetViewport.Extent, 8));
|
|
}
|
|
}
|
|
|
|
return FinalAccumulation;
|
|
}
|
|
|
|
struct FPixelMaterialLightingFingerprint
|
|
{
|
|
FVector4 Mean;
|
|
FVector4 Var;
|
|
};
|
|
|
|
class FTemporalPrepassCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FTemporalPrepassCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FTemporalPrepassCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, AlbedoTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, NormalTexture)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<FPixelMaterialLightingFingerprint>, RWVarianceMap)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
SHADER_PARAMETER(int, Iteration)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
enum class EVarianceType : uint32
|
|
{
|
|
RadianceMultiChannel = 0,
|
|
RadianceAlbedoNormalSingleChannel,
|
|
MAX
|
|
};
|
|
|
|
class FPrepassPhase : SHADER_PERMUTATION_BOOL("PREPASS_PHASE"); // 0: initialize, 1: update
|
|
class FVarianceType : SHADER_PERMUTATION_ENUM_CLASS("VARIANCE_TYPE", EVarianceType);
|
|
class FRankedLuminanceVariance : SHADER_PERMUTATION_BOOL("RANKED_LUMINANCE_VARIANCE");
|
|
using FPermutationDomain = TShaderPermutationDomain<FPrepassPhase,FVarianceType, FRankedLuminanceVariance>;
|
|
|
|
static bool UseRankedLuminanceVariance()
|
|
{
|
|
return CVarPathTracingDenoiserPrepassRankedLuminanceVariance.GetValueOnRenderThread() != 0;
|
|
}
|
|
|
|
static EVarianceType GetVarianceType()
|
|
{
|
|
return static_cast<FTemporalPrepassCS::EVarianceType>(
|
|
FMath::Clamp(CVarPathTracingDenoiserPrepassVarianceType.GetValueOnRenderThread(),
|
|
0,
|
|
static_cast<int32>(EVarianceType::MAX) - 1));
|
|
}
|
|
|
|
static const TCHAR* GetEventName(EVarianceType VarianceType)
|
|
{
|
|
static const TCHAR* const kEventName[] = {
|
|
TEXT("Radiance"),
|
|
TEXT("Rad,Albedo,Norm")
|
|
};
|
|
static_assert(UE_ARRAY_COUNT(kEventName) == int32(EVarianceType::MAX), "Fix me");
|
|
return kEventName[int32(VarianceType)];
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("TEMPORAL_PREPASS"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FTemporalPrepassCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "TemporalPrepassCS", SF_Compute);
|
|
|
|
class FPrepassGenerateTextureCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FPrepassGenerateTextureCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FPrepassGenerateTextureCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FPixelMaterialLightingFingerprint>, VarianceMap)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, OutputTexture)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
SHADER_PARAMETER(int32, Iteration)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FVarianceType : SHADER_PERMUTATION_ENUM_CLASS("VARIANCE_TYPE", FTemporalPrepassCS::EVarianceType);
|
|
using FPermutationDomain = TShaderPermutationDomain<FVarianceType>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("PREPASS_GENERATE_TEXTURE"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FPrepassGenerateTextureCS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "PrepassGenerateTextureCS", SF_Compute);
|
|
|
|
void PathTracingSpatialTemporalDenoisingPrePass(FRDGBuilder& GraphBuilder, const FViewInfo& View,
|
|
int IterationNumber,
|
|
int MaxSPP,
|
|
FPathTracingSpatialTemporalDenoisingContext& SpatialTemporalDenoisingContext)
|
|
{
|
|
bool bShouldPrepassOutputVarianceTexture = ShouldPrepassOutputVarianceTexture(View);
|
|
bool bShouldGenerateVarianceMap = ShouldGenerateVarianceMap() || bShouldPrepassOutputVarianceTexture;
|
|
if (bShouldGenerateVarianceMap)
|
|
{
|
|
bool bNeedToUpdateVariance = (IterationNumber < MaxSPP);
|
|
const FScreenPassTextureViewport TargetViewport(View.ViewRect);
|
|
const FScreenPassTextureViewportParameters TargetViewportParameters = GetScreenPassTextureViewportParameters(TargetViewport);
|
|
|
|
|
|
if (bNeedToUpdateVariance)
|
|
{
|
|
if (!SpatialTemporalDenoisingContext.VarianceBuffer)
|
|
{
|
|
SpatialTemporalDenoisingContext.VarianceBuffer = GraphBuilder.CreateBuffer(
|
|
FRDGBufferDesc::CreateStructuredDesc(sizeof(float) * 8, View.ViewRect.Area()), TEXT("PathTracing.VarianceBuffer"));
|
|
}
|
|
|
|
typedef FTemporalPrepassCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
{
|
|
PassParameters->InputTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(SpatialTemporalDenoisingContext.RadianceTexture));
|
|
PassParameters->AlbedoTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(SpatialTemporalDenoisingContext.AlbedoTexture));
|
|
PassParameters->NormalTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(SpatialTemporalDenoisingContext.NormalTexture));
|
|
PassParameters->RWVarianceMap = GraphBuilder.CreateUAV(SpatialTemporalDenoisingContext.VarianceBuffer, EPixelFormat::PF_R32_FLOAT);
|
|
PassParameters->TargetViewport = TargetViewportParameters;
|
|
PassParameters->Iteration = IterationNumber;
|
|
}
|
|
|
|
bool bUpdateVarianceMapPhase = (IterationNumber > 0);
|
|
|
|
SHADER::FPermutationDomain ComputeShaderPermutationVector;
|
|
ComputeShaderPermutationVector.Set<SHADER::FPrepassPhase>(bUpdateVarianceMapPhase);
|
|
ComputeShaderPermutationVector.Set<SHADER::FVarianceType>(SHADER::GetVarianceType());
|
|
ComputeShaderPermutationVector.Set<SHADER::FRankedLuminanceVariance>(SHADER::UseRankedLuminanceVariance());
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap, ComputeShaderPermutationVector);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::Prepass(%s %dx%d)",
|
|
SHADER::GetEventName(SHADER::GetVarianceType()),
|
|
TargetViewport.Extent.X,
|
|
TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(TargetViewport.Extent, 8));
|
|
}
|
|
else
|
|
{
|
|
SpatialTemporalDenoisingContext.VarianceBuffer = SpatialTemporalDenoisingContext.LastVarianceBuffer;
|
|
}
|
|
|
|
FRDGBufferRef VarianceBuffer = SpatialTemporalDenoisingContext.VarianceBuffer;
|
|
|
|
if (bShouldPrepassOutputVarianceTexture && VarianceBuffer)
|
|
{
|
|
const FRDGTextureDesc TextureDescriptor = FRDGTextureDesc::Create2D(
|
|
TargetViewport.Extent,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding(),
|
|
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV | GetExtraTextureCreateFlagsForDenoiser());
|
|
|
|
if (!SpatialTemporalDenoisingContext.VarianceTexture)
|
|
{
|
|
SpatialTemporalDenoisingContext.VarianceTexture = GraphBuilder.CreateTexture(TextureDescriptor, TEXT("PathTracing.VarianceTexture"));
|
|
}
|
|
|
|
typedef FPrepassGenerateTextureCS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
{
|
|
PassParameters->OutputTexture = GraphBuilder.CreateUAV(SpatialTemporalDenoisingContext.VarianceTexture);
|
|
PassParameters->VarianceMap = GraphBuilder.CreateSRV(VarianceBuffer, EPixelFormat::PF_R32_FLOAT);
|
|
PassParameters->TargetViewport = TargetViewportParameters;
|
|
PassParameters->Iteration = FMath::Min(IterationNumber, MaxSPP - 1);
|
|
}
|
|
|
|
SHADER::FPermutationDomain ComputeShaderPermutationVector;
|
|
ComputeShaderPermutationVector.Set<SHADER::FVarianceType>(FTemporalPrepassCS::GetVarianceType());
|
|
|
|
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap, ComputeShaderPermutationVector);
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("PathTracing::Denoising::Prepass::Texture(Var[%s] %dx%d)",
|
|
FTemporalPrepassCS::GetEventName(FTemporalPrepassCS::GetVarianceType()),
|
|
TargetViewport.Extent.X,
|
|
TargetViewport.Extent.Y),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(TargetViewport.Extent, 8));
|
|
}
|
|
}
|
|
}
|
|
|
|
void PathTracingSpatialTemporalDenoising(FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
int DenoiserMode,
|
|
FRDGTexture*& SpatialTemporalDenoisedTexture,
|
|
FPathTracingSpatialTemporalDenoisingContext& SpatialTemporalDenoisingContext)
|
|
{
|
|
RDG_EVENT_SCOPE_STAT(GraphBuilder, PathTracingSpatialTemporalDenoising, "PathTracingSpatialTemporalDenoising");
|
|
RDG_GPU_STAT_SCOPE(GraphBuilder, PathTracingSpatialTemporalDenoising);
|
|
|
|
FRDGTextureDesc RadianceTextureDesc = SpatialTemporalDenoisingContext.RadianceTexture->Desc;
|
|
|
|
const ESpatialDenoiserType SpatialDenoiserType = GetSpatialDenoiserType();
|
|
const ETemporalDenoiserType TemporalDenoiserType = GetTemporalDenoiserType();
|
|
const bool bApplySpatialDenoiser = ShouldApplySpatialDenoiser();
|
|
const bool bApplyTemporalDenoiser = ShouldApplyTemporalDenoiser(SpatialTemporalDenoisingContext, View);
|
|
|
|
FRDGTextureRef TargetTexture = SpatialTemporalDenoisingContext.RadianceTexture;
|
|
FRDGTextureRef SourceTexture = SpatialTemporalDenoisingContext.LastDenoisedRadianceTexture;
|
|
FRDGTextureRef TemporalDenoisedTexture = nullptr;
|
|
|
|
if (SpatialDenoiserType == ESpatialDenoiserType::SPATIAL_DENOISER_PLUGIN)
|
|
{
|
|
if (bApplySpatialDenoiser)
|
|
{
|
|
TargetTexture = GraphBuilder.CreateTexture(RadianceTextureDesc, TEXT("PathTracer.SpatialDenoiser.Output"));
|
|
PathTracingDenoiserPlugin(
|
|
GraphBuilder,
|
|
View,
|
|
DenoiserMode,
|
|
SpatialTemporalDenoisingContext.RadianceTexture,
|
|
SpatialTemporalDenoisingContext.AlbedoTexture,
|
|
SpatialTemporalDenoisingContext.NormalTexture,
|
|
SpatialTemporalDenoisingContext.DepthTexture,
|
|
SpatialTemporalDenoisingContext.VarianceTexture,
|
|
TargetTexture);
|
|
}
|
|
|
|
if (bApplyTemporalDenoiser)
|
|
{
|
|
// Image space temporal and spatial denoising.
|
|
//
|
|
// Select motion source and target for temporal denoising
|
|
FRDGTextureRef MotionEstimationSourceTexture = nullptr;
|
|
FRDGTextureRef MotionEstimationTargetTexture = nullptr;
|
|
bool IsSourceTargetDimensionMatch = SelectMotionSourceAndTargetTextures(
|
|
GraphBuilder,
|
|
View,
|
|
SourceTexture,
|
|
TargetTexture, SpatialTemporalDenoisingContext, MotionEstimationSourceTexture, MotionEstimationTargetTexture);
|
|
|
|
|
|
if (IsSourceTargetDimensionMatch)
|
|
{
|
|
UE_LOG(LogPathTracingDenoising, Log, TEXT("Using temporal denoising for frame %i"), SpatialTemporalDenoisingContext.FrameIndex);
|
|
|
|
if (TemporalDenoiserType == ETemporalDenoiserType::BUILTIN_TEMPORAL_DENOISER)
|
|
{
|
|
TemporalDenoisedTexture = TemporalReprojectionWithoutMotionVector(GraphBuilder,
|
|
View,
|
|
SourceTexture,
|
|
TargetTexture,
|
|
MotionEstimationSourceTexture,
|
|
MotionEstimationTargetTexture,
|
|
SpatialTemporalDenoisingContext);
|
|
}
|
|
else
|
|
{
|
|
// not supported
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (SpatialDenoiserType == ESpatialDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN)
|
|
{
|
|
FRDGTextureRef MotionTexture = nullptr;
|
|
bool bIsInitialFrame = true;
|
|
|
|
MotionTexture = GraphBuilder.CreateTexture(RadianceTextureDesc, TEXT("PathTracing.EstimateMotion.OpticalFlow"));
|
|
|
|
if (bApplyTemporalDenoiser)
|
|
{
|
|
// Select motion source and target for temporal denoising
|
|
FRDGTextureRef MotionEstimationSourceTexture = nullptr;
|
|
FRDGTextureRef MotionEstimationTargetTexture = nullptr;
|
|
bool IsSourceTargetDimensionMatch = SelectMotionSourceAndTargetTextures(
|
|
GraphBuilder,
|
|
View,
|
|
SourceTexture,
|
|
TargetTexture, SpatialTemporalDenoisingContext, MotionEstimationSourceTexture, MotionEstimationTargetTexture);
|
|
|
|
if (IsSourceTargetDimensionMatch)
|
|
{
|
|
if (TemporalDenoiserType == ETemporalDenoiserType::SPATIAL_TEMPORAL_DENOISER_PLUGIN)
|
|
{
|
|
FScreenPassTextureViewport TargetViewport = FScreenPassTextureViewport(View.ViewRect);
|
|
|
|
|
|
PathTracingMotionVectorPlugin(
|
|
GraphBuilder,
|
|
View,
|
|
MotionEstimationSourceTexture,
|
|
MotionEstimationTargetTexture,
|
|
MotionTexture);
|
|
bIsInitialFrame = false;
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLinearColor ClearColor = FLinearColor::Black;
|
|
AddClearRenderTargetPass(GraphBuilder, MotionTexture, ClearColor);
|
|
}
|
|
|
|
SpatialTemporalDenoisingContext.MotionVector = MotionTexture;
|
|
|
|
TemporalDenoisedTexture = GraphBuilder.CreateTexture(RadianceTextureDesc, TEXT("PathTracing.EstimateMotion.FinalAccumulation"));
|
|
|
|
PathTracingSpatialTemporalDenoiserPlugin(
|
|
GraphBuilder, View, DenoiserMode, TargetTexture,
|
|
SpatialTemporalDenoisingContext.AlbedoTexture, SpatialTemporalDenoisingContext.NormalTexture,
|
|
SpatialTemporalDenoisingContext.DepthTexture,
|
|
MotionTexture, SourceTexture, TemporalDenoisedTexture,
|
|
SpatialTemporalDenoisingContext.FrameIndex,
|
|
bIsInitialFrame,
|
|
SpatialTemporalDenoisingContext); // zero frame will denoise without temporal
|
|
|
|
}
|
|
|
|
SpatialTemporalDenoisedTexture = TemporalDenoisedTexture ? TemporalDenoisedTexture : TargetTexture;
|
|
}
|
|
|
|
class FVisualizePathTracingMotionVectorPS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FVisualizePathTracingMotionVectorPS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVisualizePathTracingMotionVectorPS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, TemporalDenoisingMotionVector)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, RasterMotionVector)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, DenoisedTexture)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("VISUALIZE_MOTIONVECTOR"), 1);
|
|
}
|
|
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FVisualizePathTracingMotionVectorPS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "VisualizePathTracingMotionVector", SF_Pixel);
|
|
|
|
class FVisualizeWarpingPS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FVisualizeWarpingPS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVisualizeWarpingPS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, TemporalDenoisingMotionVector)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, SourceTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, DenoisedTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float4>, TargetTexture)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, TargetViewport)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, SharedTextureSampler)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldCompilePathTracingDenoiserShadersForProject(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("VISUALIZE_WARPING"), 1);
|
|
}
|
|
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FVisualizeWarpingPS, "/Engine/Private/PathTracing/PathTracingSpatialTemporalDenoising.usf", "FVisualizeWarpingPS", SF_Pixel);
|
|
|
|
FScreenPassTexture AddVisualizePathTracingDenoisingPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FVisualizePathTracingDenoisingInputs& Inputs)
|
|
{
|
|
|
|
if (ShouldVisualizePathTracingVelocityState(Inputs.DenoisingContext))
|
|
{
|
|
typedef FVisualizePathTracingMotionVectorPS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
{
|
|
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
|
|
PassParameters->TemporalDenoisingMotionVector = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Inputs.DenoisingContext.MotionVector));
|
|
PassParameters->SceneTextures = Inputs.SceneTexturesUniformBuffer;
|
|
PassParameters->DenoisedTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Inputs.DenoisedTexture));
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(Inputs.SceneColor, ERenderTargetLoadAction::ELoad);
|
|
}
|
|
|
|
TShaderMapRef<SHADER> PixelShader(View.ShaderMap);
|
|
AddDrawScreenPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Visualize Motion Vector (%d x %d)", View.ViewRect.Size().X, View.ViewRect.Size().Y),
|
|
View,
|
|
Inputs.Viewport,
|
|
Inputs.Viewport,
|
|
PixelShader,
|
|
PassParameters
|
|
);
|
|
}
|
|
|
|
if (ShouldVisualizeWarping(Inputs.DenoisingContext))
|
|
{
|
|
const FScreenPassTextureViewport TargetViewport(Inputs.DenoisedTexture, View.ViewRect);
|
|
typedef FVisualizeWarpingPS SHADER;
|
|
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
|
|
{
|
|
const FScreenPassTextureViewportParameters TargetViewportParameters = GetScreenPassTextureViewportParameters(TargetViewport);
|
|
|
|
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
|
|
PassParameters->TemporalDenoisingMotionVector = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Inputs.DenoisingContext.MotionVector));
|
|
PassParameters->SceneTextures = Inputs.SceneTexturesUniformBuffer;
|
|
PassParameters->DenoisedTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Inputs.DenoisedTexture));
|
|
PassParameters->SourceTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Inputs.DenoisingContext.LastDenoisedRadianceTexture));
|
|
PassParameters->SharedTextureSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
PassParameters->TargetViewport = TargetViewportParameters;
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(Inputs.SceneColor, ERenderTargetLoadAction::ELoad);
|
|
}
|
|
|
|
TShaderMapRef<SHADER> PixelShader(View.ShaderMap);
|
|
AddDrawScreenPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Visualize Source Warping (%d x %d)", View.ViewRect.Size().X, View.ViewRect.Size().Y),
|
|
View,
|
|
Inputs.Viewport,
|
|
Inputs.Viewport,
|
|
PixelShader,
|
|
PassParameters
|
|
);
|
|
}
|
|
|
|
return FScreenPassTexture();
|
|
}
|
|
|
|
#endif
|