You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#jira UE-114681 #rb kevin.ortegren #rnx #preflight 62839fb6ba3597a0308e238f [CL 20241877 by tim doerries in ue5-main branch]
907 lines
45 KiB
C++
907 lines
45 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
VolumetricRenderTarget.cpp
|
|
=============================================================================*/
|
|
|
|
#include "VolumetricRenderTarget.h"
|
|
#include "DeferredShadingRenderer.h"
|
|
#include "RenderCore/Public/RenderGraphUtils.h"
|
|
#include "RenderCore/Public/PixelShaderUtils.h"
|
|
#include "ScenePrivate.h"
|
|
#include "SceneTextureParameters.h"
|
|
#include "SingleLayerWaterRendering.h"
|
|
#include "VolumetricCloudRendering.h"
|
|
#include "RendererUtils.h"
|
|
|
|
//PRAGMA_DISABLE_OPTIMIZATION
|
|
|
|
static TAutoConsoleVariable<int32> CVarVolumetricRenderTarget(
|
|
TEXT("r.VolumetricRenderTarget"), 1,
|
|
TEXT(""),
|
|
ECVF_SetByScalability | ECVF_RenderThreadSafe);
|
|
|
|
static TAutoConsoleVariable<float> CVarVolumetricRenderTargetUvNoiseScale(
|
|
TEXT("r.VolumetricRenderTarget.UvNoiseScale"), 0.5f,
|
|
TEXT("Used when r.VolumetricRenderTarget.UpsamplingMode is in a mode using jitter - this value scales the amount of jitter."),
|
|
ECVF_SetByScalability);
|
|
|
|
static TAutoConsoleVariable<float> CVarVolumetricRenderTargetUvNoiseSampleAcceptanceWeight(
|
|
TEXT("r.VolumetricRenderTarget.UvNoiseSampleAcceptanceWeight"), 20.0f,
|
|
TEXT("Used when r.VolumetricRenderTarget.UpsamplingMode is in a mode using jitter - this value control the acceptance of noisy cloud samples according to their similarities. A higher value means large differences will be less accepted for blending."),
|
|
ECVF_SetByScalability);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVolumetricRenderTargetMode(
|
|
TEXT("r.VolumetricRenderTarget.Mode"), 0,
|
|
TEXT("[0] trace quarter resolution + reconstruct at half resolution + upsample [1] trace half res + reconstruct full res + upsample [2] trace at quarter resolution + reconstruct full resolution (cannot intersect with opaque meshes and forces UpsamplingMode=2 [3] trace 1/8 resolution + reconstruct at half resolution + upsample)"),
|
|
ECVF_SetByScalability);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVolumetricRenderTargetUpsamplingMode(
|
|
TEXT("r.VolumetricRenderTarget.UpsamplingMode"), 4,
|
|
TEXT("Used in compositing volumetric RT over the scene. [0] bilinear [1] bilinear + jitter [2] nearest + depth test [3] bilinear + jitter + keep closest [4] bilaterial upsampling"),
|
|
ECVF_SetByScalability);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVolumetricRenderTargetPreferAsyncCompute(
|
|
TEXT("r.VolumetricRenderTarget.PreferAsyncCompute"), 0,
|
|
TEXT("Whether to prefer using async compute to generate volumetric cloud render targets."),
|
|
ECVF_SetByScalability | ECVF_RenderThreadSafe);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVolumetricRenderTargetReprojectionBoxConstraint(
|
|
TEXT("r.VolumetricRenderTarget.ReprojectionBoxConstraint"), 0,
|
|
TEXT("Whether reprojected data should be constrained to the new incoming cloud data neighborhod value."),
|
|
ECVF_SetByScalability | ECVF_RenderThreadSafe);
|
|
|
|
|
|
static float GetUvNoiseSampleAcceptanceWeight()
|
|
{
|
|
return FMath::Max(0.0f, CVarVolumetricRenderTargetUvNoiseSampleAcceptanceWeight.GetValueOnRenderThread());
|
|
}
|
|
|
|
static bool ShouldPipelineCompileVolumetricRenderTargetShaders(EShaderPlatform ShaderPlatform)
|
|
{
|
|
return GetMaxSupportedFeatureLevel(ShaderPlatform) >= ERHIFeatureLevel::SM5;
|
|
}
|
|
|
|
bool ShouldViewRenderVolumetricCloudRenderTarget(const FViewInfo& ViewInfo)
|
|
{
|
|
return CVarVolumetricRenderTarget.GetValueOnRenderThread() && ShouldPipelineCompileVolumetricRenderTargetShaders(ViewInfo.GetShaderPlatform())
|
|
&& (ViewInfo.ViewState != nullptr) && !ViewInfo.bIsReflectionCapture;
|
|
}
|
|
|
|
bool IsVolumetricRenderTargetEnabled()
|
|
{
|
|
return CVarVolumetricRenderTarget.GetValueOnRenderThread() > 0;
|
|
}
|
|
|
|
bool IsVolumetricRenderTargetAsyncCompute()
|
|
{
|
|
// TODO remove that when we remove the pixel shading path in 5.0
|
|
static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VolumetricCloud.DisableCompute"));
|
|
const bool bCloudComputePathDisabled = CVar && CVar->GetInt() > 1;
|
|
|
|
return GSupportsEfficientAsyncCompute && CVarVolumetricRenderTargetPreferAsyncCompute.GetValueOnRenderThread() > 0 && !bCloudComputePathDisabled;
|
|
}
|
|
|
|
static bool ShouldViewComposeVolumetricRenderTarget(const FViewInfo& ViewInfo)
|
|
{
|
|
return ShouldViewRenderVolumetricCloudRenderTarget(ViewInfo);
|
|
}
|
|
|
|
static uint32 GetMainDownsampleFactor(int32 Mode)
|
|
{
|
|
switch (Mode)
|
|
{
|
|
case 0:
|
|
case 3:
|
|
return 2; // Reconstruct at half resolution of view
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
return 1; // Reconstruct at full resolution of view
|
|
break;
|
|
}
|
|
check(false); // unhandled mode
|
|
return 2;
|
|
}
|
|
|
|
static uint32 GetTraceDownsampleFactor(int32 Mode)
|
|
{
|
|
switch (Mode)
|
|
{
|
|
case 0:
|
|
return 2; // Trace at half resolution of the reconstructed buffer (with it being at the half the resolution of the main view)
|
|
break;
|
|
case 1:
|
|
return 2; // Trace at half resolution of the reconstructed buffer (with it being at the same resolution as main view)
|
|
break;
|
|
case 2:
|
|
return 4; // Trace at quarter resolution of the reconstructed buffer (with it being at the same resolution as main view)
|
|
break;
|
|
case 3:
|
|
return 4; // Trace at quarter resolution of the reconstructed buffer (with it being at the half the resolution of the main view)
|
|
break;
|
|
}
|
|
check(false); // unhandled mode
|
|
return 2;
|
|
}
|
|
|
|
static void GetTextureSafeUvCoordBound(FRDGTextureRef Texture, FUintVector4& TextureValidCoordRect, FVector4f& TextureValidUvRect)
|
|
{
|
|
FIntVector TexSize = Texture->Desc.GetSize();
|
|
TextureValidCoordRect.X = 0;
|
|
TextureValidCoordRect.Y = 0;
|
|
TextureValidCoordRect.Z = TexSize.X - 1;
|
|
TextureValidCoordRect.W = TexSize.Y - 1;
|
|
TextureValidUvRect.X = 0.51f / float(TexSize.X);
|
|
TextureValidUvRect.Y = 0.51f / float(TexSize.Y);
|
|
TextureValidUvRect.Z = (float(TexSize.X) - 0.51f) / float(TexSize.X);
|
|
TextureValidUvRect.W = (float(TexSize.Y) - 0.51f) / float(TexSize.Y);
|
|
};
|
|
|
|
static bool AnyViewRequiresProcessing(TArrayView<FViewInfo> Views)
|
|
{
|
|
bool bAnyViewRequiresProcessing = false;
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
bAnyViewRequiresProcessing |= ShouldViewComposeVolumetricRenderTarget(ViewInfo);
|
|
}
|
|
return bAnyViewRequiresProcessing;
|
|
}
|
|
|
|
|
|
/*=============================================================================
|
|
UVolumetricCloudComponent implementation.
|
|
=============================================================================*/
|
|
|
|
FVolumetricRenderTargetViewStateData::FVolumetricRenderTargetViewStateData()
|
|
: CurrentRT(1)
|
|
, bFirstTimeUsed(true)
|
|
, bHistoryValid(false)
|
|
, FullResolution(FIntPoint::ZeroValue)
|
|
, VolumetricReconstructRTResolution(FIntPoint::ZeroValue)
|
|
, VolumetricTracingRTResolution(FIntPoint::ZeroValue)
|
|
{
|
|
VolumetricReconstructRTDownsampleFactor = 0;
|
|
VolumetricTracingRTDownsampleFactor = 0;
|
|
}
|
|
|
|
FVolumetricRenderTargetViewStateData::~FVolumetricRenderTargetViewStateData()
|
|
{
|
|
}
|
|
|
|
void FVolumetricRenderTargetViewStateData::Initialise(
|
|
FIntPoint& ViewRectResolutionIn,
|
|
float InUvNoiseScale,
|
|
int32 InMode,
|
|
int32 InUpsamplingMode)
|
|
{
|
|
// Update internal settings
|
|
UvNoiseScale = InUvNoiseScale;
|
|
Mode = FMath::Clamp(InMode, 0, 3);
|
|
UpsamplingMode = Mode == 2 ? 2 : FMath::Clamp(InUpsamplingMode, 0, 4); // if we are using mode 2 then we cannot intersect with depth and upsampling should be 2 (simple on/off intersection)
|
|
|
|
if (bFirstTimeUsed)
|
|
{
|
|
bFirstTimeUsed = false;
|
|
bHistoryValid = false;
|
|
FrameId = 0;
|
|
NoiseFrameIndex = 0;
|
|
NoiseFrameIndexModPattern = 0;
|
|
CurrentPixelOffset = FIntPoint::ZeroValue;
|
|
}
|
|
|
|
{
|
|
CurrentRT = 1 - CurrentRT;
|
|
const uint32 PreviousRT = 1 - CurrentRT;
|
|
|
|
// We always reallocate on a resolution change to adapt to dynamic resolution scaling.
|
|
// TODO allocate once at max resolution and change source and destination coord/uvs/rect.
|
|
if (FullResolution != ViewRectResolutionIn || GetMainDownsampleFactor(Mode) != VolumetricReconstructRTDownsampleFactor || GetTraceDownsampleFactor(Mode) != VolumetricTracingRTDownsampleFactor)
|
|
{
|
|
VolumetricReconstructRTDownsampleFactor = GetMainDownsampleFactor(Mode);
|
|
VolumetricTracingRTDownsampleFactor = GetTraceDownsampleFactor(Mode);
|
|
|
|
FullResolution = ViewRectResolutionIn;
|
|
VolumetricReconstructRTResolution = FIntPoint::DivideAndRoundUp(FullResolution, VolumetricReconstructRTDownsampleFactor); // Half resolution
|
|
VolumetricTracingRTResolution = FIntPoint::DivideAndRoundUp(VolumetricReconstructRTResolution, VolumetricTracingRTDownsampleFactor); // Half resolution of the volumetric buffer
|
|
|
|
// Need a new size so release the low resolution trace buffer
|
|
VolumetricTracingRT.SafeRelease();
|
|
VolumetricTracingRTDepth.SafeRelease();
|
|
}
|
|
|
|
FIntVector CurrentTargetResVec = VolumetricReconstructRT[CurrentRT].IsValid() ? VolumetricReconstructRT[CurrentRT]->GetDesc().GetSize() : FIntVector::ZeroValue;
|
|
FIntPoint CurrentTargetRes = FIntPoint::DivideAndRoundUp(FullResolution, VolumetricReconstructRTDownsampleFactor);
|
|
if (VolumetricReconstructRT[CurrentRT].IsValid() && FIntPoint(CurrentTargetResVec.X, CurrentTargetResVec.Y) != CurrentTargetRes)
|
|
{
|
|
// Resolution does not match so release target we are going to render in
|
|
VolumetricReconstructRT[CurrentRT].SafeRelease();
|
|
VolumetricReconstructRTDepth[CurrentRT].SafeRelease();
|
|
}
|
|
|
|
// Regular every frame update
|
|
{
|
|
// Do not mark history as valid if the half resolution buffer is not valid. That means nothing has been rendered last frame.
|
|
// That can happen when cloud is used to render into that buffer
|
|
bHistoryValid = VolumetricReconstructRT[PreviousRT].IsValid();
|
|
|
|
NoiseFrameIndex += FrameId == 0 ? 1 : 0;
|
|
NoiseFrameIndexModPattern = NoiseFrameIndex % (VolumetricTracingRTDownsampleFactor * VolumetricTracingRTDownsampleFactor);
|
|
|
|
FrameId++;
|
|
FrameId = FrameId % (VolumetricTracingRTDownsampleFactor * VolumetricTracingRTDownsampleFactor);
|
|
|
|
if (VolumetricTracingRTDownsampleFactor == 2)
|
|
{
|
|
static int32 OrderDithering2x2[4] = { 0, 2, 3, 1 };
|
|
int32 LocalFrameId = OrderDithering2x2[FrameId];
|
|
CurrentPixelOffset = FIntPoint(LocalFrameId % VolumetricTracingRTDownsampleFactor, LocalFrameId / VolumetricTracingRTDownsampleFactor);
|
|
}
|
|
else if (VolumetricTracingRTDownsampleFactor == 4)
|
|
{
|
|
static int32 OrderDithering4x4[16] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 };
|
|
int32 LocalFrameId = OrderDithering4x4[FrameId];
|
|
CurrentPixelOffset = FIntPoint(LocalFrameId % VolumetricTracingRTDownsampleFactor, LocalFrameId / VolumetricTracingRTDownsampleFactor);
|
|
}
|
|
else
|
|
{
|
|
// Default linear parse
|
|
CurrentPixelOffset = FIntPoint(FrameId % VolumetricTracingRTDownsampleFactor, FrameId / VolumetricTracingRTDownsampleFactor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateVolumetricTracingRT(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(FullResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
if (!VolumetricTracingRT.IsValid())
|
|
{
|
|
FPooledRenderTargetDesc Desc = FPooledRenderTargetDesc::Create2DDesc(
|
|
VolumetricTracingRTResolution, PF_FloatRGBA, FClearValueBinding(FLinearColor(0.0f, 0.0f, 0.0f, 1.0f)),
|
|
TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_UAV, false);
|
|
GRenderTargetPool.FindFreeElement(GraphBuilder.RHICmdList, Desc, VolumetricTracingRT, TEXT("VolumetricRenderTarget.Tracing"));
|
|
}
|
|
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricTracingRT);
|
|
}
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateVolumetricTracingRTDepth(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(FullResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
if (!VolumetricTracingRTDepth.IsValid())
|
|
{
|
|
FPooledRenderTargetDesc Desc = FPooledRenderTargetDesc::Create2DDesc(
|
|
VolumetricTracingRTResolution, PF_G16R16F, FClearValueBinding(FLinearColor(63000.0f, 63000.0f, 63000.0f, 63000.0f)),
|
|
TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_UAV, false);
|
|
GRenderTargetPool.FindFreeElement(GraphBuilder.RHICmdList, Desc, VolumetricTracingRTDepth, TEXT("VolumetricRenderTarget.TracingDepth"));
|
|
}
|
|
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricTracingRTDepth);
|
|
}
|
|
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateDstVolumetricReconstructRT(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(VolumetricReconstructRTResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
if (!VolumetricReconstructRT[CurrentRT].IsValid())
|
|
{
|
|
FPooledRenderTargetDesc Desc = FPooledRenderTargetDesc::Create2DDesc(
|
|
VolumetricReconstructRTResolution, PF_FloatRGBA, FClearValueBinding(FLinearColor(0.0f, 0.0f, 0.0f, 1.0f)),
|
|
TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false);
|
|
GRenderTargetPool.FindFreeElement(GraphBuilder.RHICmdList, Desc, VolumetricReconstructRT[CurrentRT], TEXT("VolumetricRenderTarget.Reconstruct"));
|
|
}
|
|
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricReconstructRT[CurrentRT]);
|
|
}
|
|
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateDstVolumetricReconstructRTDepth(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(VolumetricReconstructRTResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
if (!VolumetricReconstructRTDepth[CurrentRT].IsValid())
|
|
{
|
|
FPooledRenderTargetDesc Desc = FPooledRenderTargetDesc::Create2DDesc(
|
|
VolumetricReconstructRTResolution, PF_G16R16F, FClearValueBinding(FLinearColor(63000.0f, 63000.0f, 63000.0f, 63000.0f)),
|
|
TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false);
|
|
GRenderTargetPool.FindFreeElement(GraphBuilder.RHICmdList, Desc, VolumetricReconstructRTDepth[CurrentRT], TEXT("VolumetricRenderTarget.ReconstructDepth"));
|
|
}
|
|
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricReconstructRTDepth[CurrentRT]);
|
|
}
|
|
|
|
TRefCountPtr<IPooledRenderTarget> FVolumetricRenderTargetViewStateData::GetDstVolumetricReconstructRT()
|
|
{
|
|
return VolumetricReconstructRT[CurrentRT];
|
|
}
|
|
TRefCountPtr<IPooledRenderTarget> FVolumetricRenderTargetViewStateData::GetDstVolumetricReconstructRTDepth()
|
|
{
|
|
return VolumetricReconstructRTDepth[CurrentRT];
|
|
}
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateSrcVolumetricReconstructRT(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(VolumetricReconstructRTResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
check(VolumetricReconstructRT[1u - CurrentRT].IsValid());
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricReconstructRT[1u - CurrentRT]);
|
|
}
|
|
|
|
FRDGTextureRef FVolumetricRenderTargetViewStateData::GetOrCreateSrcVolumetricReconstructRTDepth(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(VolumetricReconstructRTResolution != FIntPoint::ZeroValue); // check that initialization has been done at least once
|
|
|
|
check(VolumetricReconstructRT[1u - CurrentRT].IsValid());
|
|
return GraphBuilder.RegisterExternalTexture(VolumetricReconstructRTDepth[1u - CurrentRT]);
|
|
}
|
|
|
|
FUintVector4 FVolumetricRenderTargetViewStateData::GetTracingCoordToZbufferCoordScaleBias() const
|
|
{
|
|
if (Mode == 2 || Mode == 1)
|
|
{
|
|
// In this case, the source depth buffer full resolution depth buffer is the full resolution scene one
|
|
const uint32 CombinedDownsampleFactor = VolumetricReconstructRTDownsampleFactor * VolumetricTracingRTDownsampleFactor;
|
|
return FUintVector4(CombinedDownsampleFactor, CombinedDownsampleFactor, // Scale is the combined downsample factor
|
|
CurrentPixelOffset.X * VolumetricReconstructRTDownsampleFactor, CurrentPixelOffset.Y * VolumetricReconstructRTDownsampleFactor);// Each sample will then sample from full res according to reconstructed RT offset times its downsample factor
|
|
}
|
|
|
|
// Otherwise, a half resolution depth buffer is used
|
|
const uint32 SourceDepthBufferRTDownsampleFactor = 2;
|
|
const uint32 CombinedDownsampleFactor = VolumetricReconstructRTDownsampleFactor * VolumetricTracingRTDownsampleFactor / SourceDepthBufferRTDownsampleFactor;
|
|
return FUintVector4( CombinedDownsampleFactor, CombinedDownsampleFactor, // Scale is the combined downsample factor
|
|
CurrentPixelOffset.X * VolumetricReconstructRTDownsampleFactor / VolumetricReconstructRTDownsampleFactor, // Each sample will then sample from full res according to reconstructed RT offset times its downsample factor
|
|
CurrentPixelOffset.Y * VolumetricReconstructRTDownsampleFactor / VolumetricReconstructRTDownsampleFactor);
|
|
}
|
|
|
|
FUintVector4 FVolumetricRenderTargetViewStateData::GetTracingCoordToFullResPixelCoordScaleBias() const
|
|
{
|
|
// In this case, the source depth buffer full resolution depth buffer is the full resolution scene one
|
|
const uint32 CombinedDownsampleFactor = VolumetricReconstructRTDownsampleFactor * VolumetricTracingRTDownsampleFactor;
|
|
return FUintVector4(CombinedDownsampleFactor, CombinedDownsampleFactor, // Scale is the combined downsample factor
|
|
CurrentPixelOffset.X * VolumetricReconstructRTDownsampleFactor, CurrentPixelOffset.Y * VolumetricReconstructRTDownsampleFactor);// Each sample will then sample from full res according to reconstructed RT offset times its downsample factor
|
|
}
|
|
|
|
|
|
/*=============================================================================
|
|
FSceneRenderer implementation.
|
|
=============================================================================*/
|
|
|
|
void InitVolumetricRenderTargetForViews(FRDGBuilder& GraphBuilder, TArrayView<FViewInfo> Views)
|
|
{
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
if (!ShouldViewRenderVolumetricCloudRenderTarget(ViewInfo))
|
|
{
|
|
continue;
|
|
}
|
|
FVolumetricRenderTargetViewStateData& VolumetricCloudRT = ViewInfo.ViewState->VolumetricCloudRenderTarget;
|
|
|
|
FIntPoint ViewRect = ViewInfo.ViewRect.Size();
|
|
VolumetricCloudRT.Initialise( // TODO this is going to reallocate a buffer each time dynamic resolution scaling is applied
|
|
ViewRect,
|
|
CVarVolumetricRenderTargetUvNoiseScale.GetValueOnAnyThread(),
|
|
CVarVolumetricRenderTargetMode.GetValueOnRenderThread(),
|
|
CVarVolumetricRenderTargetUpsamplingMode.GetValueOnAnyThread());
|
|
|
|
FViewUniformShaderParameters ViewVolumetricCloudRTParameters = *ViewInfo.CachedViewUniformShaderParameters;
|
|
{
|
|
const FIntPoint& VolumetricReconstructResolution = VolumetricCloudRT.GetCurrentVolumetricReconstructRTResolution();
|
|
const FIntPoint& VolumetricTracingResolution = VolumetricCloudRT.GetCurrentVolumetricTracingRTResolution();
|
|
const FIntPoint& CurrentPixelOffset = VolumetricCloudRT.GetCurrentTracingPixelOffset();
|
|
const uint32 VolumetricReconstructRTDownSample = VolumetricCloudRT.GetVolumetricReconstructRTDownsampleFactor();
|
|
const uint32 VolumetricTracingRTDownSample = VolumetricCloudRT.GetVolumetricTracingRTDownsampleFactor();
|
|
|
|
// We jitter and reconstruct the volumetric view before TAA so we do not want any of its jitter.
|
|
// We do use TAA remove bilinear artifact at up sampling time.
|
|
FViewMatrices ViewMatrices = ViewInfo.ViewMatrices;
|
|
ViewMatrices.HackRemoveTemporalAAProjectionJitter();
|
|
|
|
float DownSampleFactor = float(VolumetricReconstructRTDownSample * VolumetricTracingRTDownSample);
|
|
|
|
// Offset to the correct half resolution pixel
|
|
FVector2D CenterCoord = FVector2D(VolumetricReconstructRTDownSample / 2.0f);
|
|
FVector2D TargetCoord = FVector2D(CurrentPixelOffset) + FVector2D(0.5f, 0.5f);
|
|
FVector2D OffsetCoord = (TargetCoord - CenterCoord) * (FVector2D(-2.0f, 2.0f) / FVector2D(VolumetricReconstructResolution));
|
|
ViewMatrices.HackAddTemporalAAProjectionJitter(OffsetCoord);
|
|
|
|
ViewInfo.SetupViewRectUniformBufferParameters(
|
|
ViewVolumetricCloudRTParameters,
|
|
VolumetricTracingResolution,
|
|
FIntRect(0, 0, VolumetricTracingResolution.X, VolumetricTracingResolution.Y),
|
|
ViewMatrices,
|
|
ViewInfo.PrevViewInfo.ViewMatrices // This could also be changed if needed
|
|
);
|
|
}
|
|
ViewInfo.VolumetricRenderTargetViewUniformBuffer = TUniformBufferRef<FViewUniformShaderParameters>::CreateUniformBufferImmediate(ViewVolumetricCloudRTParameters, UniformBuffer_SingleFrame);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
class FReconstructVolumetricRenderTargetPS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FReconstructVolumetricRenderTargetPS);
|
|
SHADER_USE_PARAMETER_STRUCT(FReconstructVolumetricRenderTargetPS, FGlobalShader);
|
|
|
|
class FHistoryAvailable : SHADER_PERMUTATION_BOOL("PERMUTATION_HISTORY_AVAILABLE");
|
|
class FReprojectionBoxConstraint : SHADER_PERMUTATION_BOOL("PERMUTATION_REPROJECTION_BOX_CONSTRAINT");
|
|
using FPermutationDomain = TShaderPermutationDomain<FHistoryAvailable, FReprojectionBoxConstraint>;
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, TracingVolumetricTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, TracingVolumetricDepthTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, PreviousFrameVolumetricTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, PreviousFrameVolumetricDepthTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, HalfResDepthTexture)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, LinearTextureSampler)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
SHADER_PARAMETER(FVector4f, DstVolumetricTextureSizeAndInvSize)
|
|
SHADER_PARAMETER(FVector4f, PreviousVolumetricTextureSizeAndInvSize)
|
|
SHADER_PARAMETER(FIntPoint, CurrentTracingPixelOffset)
|
|
SHADER_PARAMETER(FIntPoint, ViewViewRectMin)
|
|
SHADER_PARAMETER(int32, DownSampleFactor)
|
|
SHADER_PARAMETER(int32, VolumetricRenderTargetMode)
|
|
SHADER_PARAMETER(FUintVector4, TracingVolumetricTextureValidCoordRect)
|
|
SHADER_PARAMETER(FVector4f, TracingVolumetricTextureValidUvRect)
|
|
SHADER_PARAMETER(FUintVector4, PreviousFrameVolumetricTextureValidCoordRect)
|
|
SHADER_PARAMETER(FVector4f, PreviousFrameVolumetricTextureValidUvRect)
|
|
SHADER_PARAMETER(float, TemporalFactor)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
|
|
{
|
|
return PermutationVector;
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return ShouldPipelineCompileVolumetricRenderTargetShaders(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("SHADER_RECONSTRUCT_VOLUMETRICRT"), TEXT("1"));
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FReconstructVolumetricRenderTargetPS, "/Engine/Private/VolumetricRenderTarget.usf", "ReconstructVolumetricRenderTargetPS", SF_Pixel);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void ReconstructVolumetricRenderTarget(
|
|
FRDGBuilder& GraphBuilder,
|
|
TArrayView<FViewInfo> Views,
|
|
FRDGTextureRef SceneDepthTexture,
|
|
FRDGTextureRef HalfResolutionDepthCheckerboardMinMaxTexture,
|
|
bool bWaitFinishFence)
|
|
{
|
|
if (!AnyViewRequiresProcessing(Views))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
if (!ShouldViewComposeVolumetricRenderTarget(ViewInfo))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FVolumetricRenderTargetViewStateData& VolumetricCloudRT = ViewInfo.ViewState->VolumetricCloudRenderTarget;
|
|
|
|
FRDGTextureRef DstVolumetric = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRT(GraphBuilder);
|
|
FRDGTextureRef DstVolumetricDepth = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRTDepth(GraphBuilder);
|
|
FRDGTextureRef SrcTracingVolumetric = VolumetricCloudRT.GetOrCreateVolumetricTracingRT(GraphBuilder);
|
|
FRDGTextureRef SrcTracingVolumetricDepth = VolumetricCloudRT.GetOrCreateVolumetricTracingRTDepth(GraphBuilder);
|
|
FRDGTextureRef PreviousFrameVolumetricTexture = VolumetricCloudRT.GetHistoryValid() ? VolumetricCloudRT.GetOrCreateSrcVolumetricReconstructRT(GraphBuilder) : SystemTextures.Black;
|
|
FRDGTextureRef PreviousFrameVolumetricDepthTexture = VolumetricCloudRT.GetHistoryValid() ? VolumetricCloudRT.GetOrCreateSrcVolumetricReconstructRTDepth(GraphBuilder) : SystemTextures.Black;
|
|
|
|
const uint32 TracingVolumetricCloudRTDownSample = VolumetricCloudRT.GetVolumetricTracingRTDownsampleFactor();
|
|
|
|
FReconstructVolumetricRenderTargetPS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FReconstructVolumetricRenderTargetPS::FHistoryAvailable>(VolumetricCloudRT.GetHistoryValid());
|
|
PermutationVector.Set<FReconstructVolumetricRenderTargetPS::FReprojectionBoxConstraint>(CVarVolumetricRenderTargetReprojectionBoxConstraint.GetValueOnAnyThread() > 0);
|
|
TShaderMapRef<FReconstructVolumetricRenderTargetPS> PixelShader(ViewInfo.ShaderMap, PermutationVector);
|
|
|
|
FReconstructVolumetricRenderTargetPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FReconstructVolumetricRenderTargetPS::FParameters>();
|
|
PassParameters->ViewUniformBuffer = ViewInfo.VolumetricRenderTargetViewUniformBuffer; // Using a special uniform buffer because the view has some special resolution and no split screen offset.
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(DstVolumetric, ERenderTargetLoadAction::ENoAction);
|
|
PassParameters->RenderTargets[1] = FRenderTargetBinding(DstVolumetricDepth, ERenderTargetLoadAction::ENoAction);
|
|
PassParameters->TracingVolumetricTexture = SrcTracingVolumetric;
|
|
PassParameters->TracingVolumetricDepthTexture = SrcTracingVolumetricDepth;
|
|
PassParameters->PreviousFrameVolumetricTexture = PreviousFrameVolumetricTexture;
|
|
PassParameters->PreviousFrameVolumetricDepthTexture = PreviousFrameVolumetricDepthTexture;
|
|
PassParameters->LinearTextureSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
PassParameters->CurrentTracingPixelOffset = VolumetricCloudRT.GetCurrentTracingPixelOffset();
|
|
PassParameters->ViewViewRectMin = ViewInfo.ViewRect.Min / GetMainDownsampleFactor(VolumetricCloudRT.GetMode());// because we use the special VolumetricRenderTargetViewUniformBuffer, we have to specify View.RectMin separately.
|
|
PassParameters->DownSampleFactor = TracingVolumetricCloudRTDownSample;
|
|
PassParameters->VolumetricRenderTargetMode = VolumetricCloudRT.GetMode();
|
|
PassParameters->HalfResDepthTexture = (VolumetricCloudRT.GetMode() == 0 || VolumetricCloudRT.GetMode() == 3) ? HalfResolutionDepthCheckerboardMinMaxTexture : SceneDepthTexture;
|
|
|
|
const bool bVisualizeConservativeDensityOrDebugSampleCount = ShouldViewVisualizeVolumetricCloudConservativeDensity(ViewInfo, ViewInfo.Family->EngineShowFlags) || GetVolumetricCloudDebugSampleCountMode(ViewInfo.Family->EngineShowFlags)>0;;
|
|
PassParameters->HalfResDepthTexture = bVisualizeConservativeDensityOrDebugSampleCount ?
|
|
((bool)ERHIZBuffer::IsInverted ? SystemTextures.Black : SystemTextures.White) :
|
|
((VolumetricCloudRT.GetMode() == 0 || VolumetricCloudRT.GetMode() == 3) ?
|
|
HalfResolutionDepthCheckerboardMinMaxTexture :
|
|
SceneDepthTexture);
|
|
|
|
GetTextureSafeUvCoordBound(SrcTracingVolumetric, PassParameters->TracingVolumetricTextureValidCoordRect, PassParameters->TracingVolumetricTextureValidUvRect);
|
|
GetTextureSafeUvCoordBound(PreviousFrameVolumetricTexture, PassParameters->PreviousFrameVolumetricTextureValidCoordRect, PassParameters->PreviousFrameVolumetricTextureValidUvRect);
|
|
|
|
FIntVector DstVolumetricSize = DstVolumetric->Desc.GetSize();
|
|
FVector2D DstVolumetricTextureSize = FVector2D(float(DstVolumetricSize.X), float(DstVolumetricSize.Y));
|
|
FVector2D PreviousVolumetricTextureSize = FVector2D(float(PreviousFrameVolumetricTexture->Desc.GetSize().X), float(PreviousFrameVolumetricTexture->Desc.GetSize().Y));
|
|
PassParameters->DstVolumetricTextureSizeAndInvSize = FVector4f(DstVolumetricTextureSize.X, DstVolumetricTextureSize.Y, 1.0f / DstVolumetricTextureSize.X, 1.0f / DstVolumetricTextureSize.Y);
|
|
PassParameters->PreviousVolumetricTextureSizeAndInvSize = FVector4f(PreviousVolumetricTextureSize.X, PreviousVolumetricTextureSize.Y, 1.0f / PreviousVolumetricTextureSize.X, 1.0f / PreviousVolumetricTextureSize.Y);
|
|
|
|
FPixelShaderUtils::AddFullscreenPass<FReconstructVolumetricRenderTargetPS>(
|
|
GraphBuilder, ViewInfo.ShaderMap, RDG_EVENT_NAME("VolumetricReconstruct"), PixelShader, PassParameters,
|
|
FIntRect(0, 0, DstVolumetricSize.X, DstVolumetricSize.Y));
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
class FComposeVolumetricRTOverScenePS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FComposeVolumetricRTOverScenePS);
|
|
SHADER_USE_PARAMETER_STRUCT(FComposeVolumetricRTOverScenePS, FGlobalShader);
|
|
|
|
class FUpsamplingMode : SHADER_PERMUTATION_RANGE_INT("PERMUTATION_UPSAMPLINGMODE", 0, 5);
|
|
class FRenderUnderWaterBuffer : SHADER_PERMUTATION_BOOL("PERMUTATION_RENDER_UNDERWATER_BUFFER"); // Render into the water scene color buffer (used when rendering from water system)
|
|
class FRenderCameraUnderWater : SHADER_PERMUTATION_BOOL("PERMUTATION_RENDER_CAMERA_UNDERWATER"); // When water us used and the camera is under water, use that permutation (to handle camera intersection with water and double cloud composition)
|
|
class FMSAASampleCount : SHADER_PERMUTATION_SPARSE_INT("MSAA_SAMPLE_COUNT", 1, 2, 4, 8);
|
|
using FPermutationDomain = TShaderPermutationDomain<FUpsamplingMode, FRenderUnderWaterBuffer, FRenderCameraUnderWater, FMSAASampleCount>;
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, VolumetricTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, VolumetricDepthTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, WaterLinearDepthTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2DMS<float>, MSAADepthTexture)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, LinearTextureSampler)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, WaterLinearDepthSampler)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
SHADER_PARAMETER(float, UvOffsetScale)
|
|
SHADER_PARAMETER(float, UvOffsetSampleAcceptanceWeight)
|
|
SHADER_PARAMETER(FVector4f, VolumetricTextureSizeAndInvSize)
|
|
SHADER_PARAMETER(FVector2f, FullResolutionToVolumetricBufferResolutionScale)
|
|
SHADER_PARAMETER(FVector2f, FullResolutionToWaterBufferScale)
|
|
SHADER_PARAMETER(FVector4f, SceneWithoutSingleLayerWaterViewRect)
|
|
SHADER_PARAMETER(FUintVector4, VolumetricTextureValidCoordRect)
|
|
SHADER_PARAMETER(FVector4f, VolumetricTextureValidUvRect)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
|
|
{
|
|
return PermutationVector;
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if ((!IsAnyForwardShadingEnabled(Parameters.Platform) || !RHISupportsMSAA(Parameters.Platform)) && PermutationVector.Get<FMSAASampleCount>() > 1)
|
|
{
|
|
// We only compile the MSAA support when Forward shading is enabled because MSAA can only be used in this case.
|
|
return false;
|
|
}
|
|
|
|
return ShouldPipelineCompileVolumetricRenderTargetShaders(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("SHADER_COMPOSE_VOLUMETRICRT"), TEXT("1"));
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FComposeVolumetricRTOverScenePS, "/Engine/Private/VolumetricRenderTarget.usf", "ComposeVolumetricRTOverScenePS", SF_Pixel);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void ComposeVolumetricRenderTargetOverScene(
|
|
FRDGBuilder& GraphBuilder,
|
|
TArrayView<FViewInfo> Views,
|
|
FRDGTextureRef SceneColorTexture,
|
|
FRDGTextureRef SceneDepthTexture,
|
|
bool bShouldRenderSingleLayerWater,
|
|
const FSceneWithoutWaterTextures& WaterPassData,
|
|
const FMinimalSceneTextures& SceneTextures)
|
|
{
|
|
if (!AnyViewRequiresProcessing(Views))
|
|
{
|
|
return;
|
|
}
|
|
|
|
FRHIBlendState* PreMultipliedColorTransmittanceBlend = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
if (!ShouldViewRenderVolumetricCloudRenderTarget(ViewInfo))
|
|
{
|
|
continue;
|
|
}
|
|
FVolumetricRenderTargetViewStateData& VolumetricCloudRT = ViewInfo.ViewState->VolumetricCloudRenderTarget;
|
|
FRDGTextureRef VolumetricTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRT(GraphBuilder);
|
|
FRDGTextureRef VolumetricDepthTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRTDepth(GraphBuilder);
|
|
|
|
// When reconstructed and back buffer resolution matches, force using a pixel perfect upsampling.
|
|
const uint32 VRTMode = VolumetricCloudRT.GetMode();
|
|
int UpsamplingMode = VolumetricCloudRT.GetUpsamplingMode();
|
|
UpsamplingMode = UpsamplingMode == 3 && (VRTMode == 1 || VRTMode == 2) ? 2 : UpsamplingMode;
|
|
|
|
// We only support MSAA up to 8 sample and in forward
|
|
check(SceneDepthTexture->Desc.NumSamples <= 8);
|
|
// We only support MSAA in forward, not in deferred.
|
|
const bool bForwardShading = IsForwardShadingEnabled(ViewInfo.GetShaderPlatform());
|
|
check(bForwardShading || (!bForwardShading && SceneDepthTexture->Desc.NumSamples==1));
|
|
|
|
FComposeVolumetricRTOverScenePS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FUpsamplingMode>(UpsamplingMode);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderUnderWaterBuffer>(0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderCameraUnderWater>((bShouldRenderSingleLayerWater && ViewInfo.IsUnderwater()) ? 1 : 0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FMSAASampleCount>(SceneDepthTexture->Desc.NumSamples);
|
|
TShaderMapRef<FComposeVolumetricRTOverScenePS> PixelShader(ViewInfo.ShaderMap, PermutationVector);
|
|
|
|
FComposeVolumetricRTOverScenePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FComposeVolumetricRTOverScenePS::FParameters>();
|
|
PassParameters->ViewUniformBuffer = ViewInfo.ViewUniformBuffer;
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture, ERenderTargetLoadAction::ELoad);
|
|
PassParameters->MSAADepthTexture = SceneDepthTexture;
|
|
PassParameters->VolumetricTexture = VolumetricTexture;
|
|
PassParameters->VolumetricDepthTexture = VolumetricDepthTexture;
|
|
PassParameters->LinearTextureSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
PassParameters->UvOffsetScale = VolumetricCloudRT.GetUvNoiseScale();
|
|
PassParameters->UvOffsetSampleAcceptanceWeight = GetUvNoiseSampleAcceptanceWeight();
|
|
PassParameters->FullResolutionToVolumetricBufferResolutionScale = FVector2f(1.0f / float(GetMainDownsampleFactor(VRTMode)), float(GetMainDownsampleFactor(VRTMode)));
|
|
PassParameters->SceneTextures = SceneTextures.UniformBuffer;
|
|
GetTextureSafeUvCoordBound(PassParameters->VolumetricTexture, PassParameters->VolumetricTextureValidCoordRect, PassParameters->VolumetricTextureValidUvRect);
|
|
|
|
PassParameters->WaterLinearDepthTexture = WaterPassData.DepthTexture;
|
|
PassParameters->WaterLinearDepthSampler = TStaticSamplerState<SF_Point>::GetRHI();
|
|
if (bShouldRenderSingleLayerWater)
|
|
{
|
|
const FSceneWithoutWaterTextures::FView& WaterPassViewData = WaterPassData.Views[ViewIndex];
|
|
PassParameters->FullResolutionToWaterBufferScale = FVector2f(1.0f / WaterPassData.RefractionDownsampleFactor, WaterPassData.RefractionDownsampleFactor);
|
|
PassParameters->SceneWithoutSingleLayerWaterViewRect = FVector4f(WaterPassViewData.ViewRect.Min.X, WaterPassViewData.ViewRect.Min.Y,
|
|
WaterPassViewData.ViewRect.Max.X, WaterPassViewData.ViewRect.Max.Y);
|
|
}
|
|
|
|
FVector2D VolumetricTextureSize = FVector2D(float(VolumetricTexture->Desc.GetSize().X), float(VolumetricTexture->Desc.GetSize().Y));
|
|
PassParameters->VolumetricTextureSizeAndInvSize = FVector4f(VolumetricTextureSize.X, VolumetricTextureSize.Y, 1.0f / VolumetricTextureSize.X, 1.0f / VolumetricTextureSize.Y);
|
|
|
|
FPixelShaderUtils::AddFullscreenPass<FComposeVolumetricRTOverScenePS>(
|
|
GraphBuilder, ViewInfo.ShaderMap, RDG_EVENT_NAME("VolumetricComposeOverScene"), PixelShader, PassParameters, ViewInfo.ViewRect,
|
|
PreMultipliedColorTransmittanceBlend);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void ComposeVolumetricRenderTargetOverSceneUnderWater(
|
|
FRDGBuilder& GraphBuilder,
|
|
TArrayView<FViewInfo> Views,
|
|
const FSceneWithoutWaterTextures& WaterPassData,
|
|
const FMinimalSceneTextures& SceneTextures)
|
|
{
|
|
if (!AnyViewRequiresProcessing(Views))
|
|
{
|
|
return;
|
|
}
|
|
|
|
FRHIBlendState* PreMultipliedColorTransmittanceBlend = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
if (!ShouldViewRenderVolumetricCloudRenderTarget(ViewInfo))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FVolumetricRenderTargetViewStateData& VolumetricCloudRT = ViewInfo.ViewState->VolumetricCloudRenderTarget;
|
|
FRDGTextureRef VolumetricTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRT(GraphBuilder);
|
|
FRDGTextureRef VolumetricDepthTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRTDepth(GraphBuilder);
|
|
const FSceneWithoutWaterTextures::FView& WaterPassViewData = WaterPassData.Views[ViewIndex];
|
|
|
|
// When reconstructed and back buffer resolution matches, force using a pixel perfect upsampling.
|
|
const uint32 VRTMode = VolumetricCloudRT.GetMode();
|
|
int UpsamplingMode = VolumetricCloudRT.GetUpsamplingMode();
|
|
UpsamplingMode = UpsamplingMode == 3 && (VRTMode == 1 || VRTMode == 2) ? 2 : UpsamplingMode;
|
|
|
|
FComposeVolumetricRTOverScenePS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FUpsamplingMode>(UpsamplingMode);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderUnderWaterBuffer>(1);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderCameraUnderWater>(0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FMSAASampleCount>(1);
|
|
TShaderMapRef<FComposeVolumetricRTOverScenePS> PixelShader(ViewInfo.ShaderMap, PermutationVector);
|
|
|
|
FComposeVolumetricRTOverScenePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FComposeVolumetricRTOverScenePS::FParameters>();
|
|
PassParameters->ViewUniformBuffer = ViewInfo.ViewUniformBuffer;
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(WaterPassData.ColorTexture, ERenderTargetLoadAction::ELoad);
|
|
PassParameters->VolumetricTexture = VolumetricTexture;
|
|
PassParameters->VolumetricDepthTexture = VolumetricDepthTexture;
|
|
PassParameters->WaterLinearDepthTexture = WaterPassData.DepthTexture;
|
|
PassParameters->LinearTextureSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
PassParameters->WaterLinearDepthSampler = TStaticSamplerState<SF_Point>::GetRHI();
|
|
PassParameters->UvOffsetScale = VolumetricCloudRT.GetUvNoiseScale();
|
|
PassParameters->UvOffsetSampleAcceptanceWeight = GetUvNoiseSampleAcceptanceWeight();
|
|
PassParameters->FullResolutionToVolumetricBufferResolutionScale = FVector2f(1.0f / float(GetMainDownsampleFactor(VRTMode)), float(GetMainDownsampleFactor(VRTMode)));
|
|
PassParameters->FullResolutionToWaterBufferScale = FVector2f(1.0f / WaterPassData.RefractionDownsampleFactor, WaterPassData.RefractionDownsampleFactor);
|
|
PassParameters->SceneWithoutSingleLayerWaterViewRect = FVector4f(WaterPassViewData.ViewRect.Min.X, WaterPassViewData.ViewRect.Min.Y,
|
|
WaterPassViewData.ViewRect.Max.X, WaterPassViewData.ViewRect.Max.Y);
|
|
PassParameters->SceneTextures = SceneTextures.UniformBuffer;
|
|
GetTextureSafeUvCoordBound(PassParameters->VolumetricTexture, PassParameters->VolumetricTextureValidCoordRect, PassParameters->VolumetricTextureValidUvRect);
|
|
|
|
FVector2D VolumetricTextureSize = FVector2D(float(VolumetricTexture->Desc.GetSize().X), float(VolumetricTexture->Desc.GetSize().Y));
|
|
PassParameters->VolumetricTextureSizeAndInvSize = FVector4f(VolumetricTextureSize.X, VolumetricTextureSize.Y, 1.0f / VolumetricTextureSize.X, 1.0f / VolumetricTextureSize.Y);
|
|
|
|
FPixelShaderUtils::AddFullscreenPass<FComposeVolumetricRTOverScenePS>(
|
|
GraphBuilder, ViewInfo.ShaderMap, RDG_EVENT_NAME("SLW::VolumetricComposeOverScene"), PixelShader, PassParameters, WaterPassViewData.ViewRect,
|
|
PreMultipliedColorTransmittanceBlend);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void ComposeVolumetricRenderTargetOverSceneForVisualization(
|
|
FRDGBuilder& GraphBuilder,
|
|
TArrayView<FViewInfo> Views,
|
|
FRDGTextureRef SceneColorTexture,
|
|
const FMinimalSceneTextures& SceneTextures)
|
|
{
|
|
if (!AnyViewRequiresProcessing(Views))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& ViewInfo = Views[ViewIndex];
|
|
if (!ShouldViewRenderVolumetricCloudRenderTarget(ViewInfo))
|
|
{
|
|
continue;
|
|
}
|
|
FVolumetricRenderTargetViewStateData& VolumetricCloudRT = ViewInfo.ViewState->VolumetricCloudRenderTarget;
|
|
FRDGTextureRef VolumetricTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRT(GraphBuilder);
|
|
FRDGTextureRef VolumetricDepthTexture = VolumetricCloudRT.GetOrCreateDstVolumetricReconstructRTDepth(GraphBuilder);
|
|
|
|
// When reconstructed and back buffer resolution matches, force using a pixel perfect upsampling.
|
|
const uint32 VRTMode = VolumetricCloudRT.GetMode();
|
|
|
|
FComposeVolumetricRTOverScenePS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FUpsamplingMode>(0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderUnderWaterBuffer>(0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderCameraUnderWater>(0);
|
|
PermutationVector.Set<FComposeVolumetricRTOverScenePS::FMSAASampleCount>(1);
|
|
TShaderMapRef<FComposeVolumetricRTOverScenePS> PixelShader(ViewInfo.ShaderMap, PermutationVector);
|
|
|
|
FComposeVolumetricRTOverScenePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FComposeVolumetricRTOverScenePS::FParameters>();
|
|
PassParameters->ViewUniformBuffer = ViewInfo.ViewUniformBuffer;
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture, ERenderTargetLoadAction::ELoad);
|
|
PassParameters->VolumetricTexture = VolumetricTexture;
|
|
PassParameters->VolumetricDepthTexture = VolumetricDepthTexture;
|
|
PassParameters->LinearTextureSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
PassParameters->UvOffsetScale = VolumetricCloudRT.GetUvNoiseScale();
|
|
PassParameters->UvOffsetSampleAcceptanceWeight = GetUvNoiseSampleAcceptanceWeight();
|
|
PassParameters->FullResolutionToVolumetricBufferResolutionScale = FVector2f(1.0f / float(GetMainDownsampleFactor(VRTMode)), float(GetMainDownsampleFactor(VRTMode)));
|
|
PassParameters->SceneTextures = SceneTextures.UniformBuffer;
|
|
GetTextureSafeUvCoordBound(PassParameters->VolumetricTexture, PassParameters->VolumetricTextureValidCoordRect, PassParameters->VolumetricTextureValidUvRect);
|
|
|
|
PassParameters->WaterLinearDepthTexture = GSystemTextures.GetBlackDummy(GraphBuilder);
|
|
|
|
FVector2D VolumetricTextureSize = FVector2D(float(VolumetricTexture->Desc.GetSize().X), float(VolumetricTexture->Desc.GetSize().Y));
|
|
PassParameters->VolumetricTextureSizeAndInvSize = FVector4f(VolumetricTextureSize.X, VolumetricTextureSize.Y, 1.0f / VolumetricTextureSize.X, 1.0f / VolumetricTextureSize.Y);
|
|
|
|
FPixelShaderUtils::AddFullscreenPass<FComposeVolumetricRTOverScenePS>(
|
|
GraphBuilder, ViewInfo.ShaderMap, RDG_EVENT_NAME("VolumetricComposeOverSceneForVisualization"), PixelShader, PassParameters, ViewInfo.ViewRect);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
FTemporalRenderTargetState::FTemporalRenderTargetState()
|
|
: CurrentRT(1)
|
|
, FrameId(0)
|
|
, bFirstTimeUsed(true)
|
|
, bHistoryValid(false)
|
|
, Resolution(FIntPoint::ZeroValue)
|
|
, Format(PF_MAX)
|
|
{
|
|
}
|
|
|
|
FTemporalRenderTargetState::~FTemporalRenderTargetState()
|
|
{
|
|
}
|
|
|
|
void FTemporalRenderTargetState::Initialise(const FIntPoint& ResolutionIn, EPixelFormat FormatIn)
|
|
{
|
|
// Update internal settings
|
|
|
|
if (bFirstTimeUsed)
|
|
{
|
|
bFirstTimeUsed = false;
|
|
bHistoryValid = false;
|
|
FrameId = 0;
|
|
}
|
|
|
|
CurrentRT = 1 - CurrentRT;
|
|
const uint32 PreviousRT = 1 - CurrentRT;
|
|
|
|
FIntVector ResolutionVector = FIntVector(ResolutionIn.X, ResolutionIn.Y, 0);
|
|
for (int32 i = 0; i < kRenderTargetCount; ++i)
|
|
{
|
|
if (RenderTargets[i].IsValid() && (RenderTargets[i]->GetDesc().GetSize() != ResolutionVector || Format != FormatIn))
|
|
{
|
|
// Resolution does not match so release target we are going to render in, keep the previous one at a different resolution.
|
|
RenderTargets[i].SafeRelease();
|
|
}
|
|
}
|
|
Resolution = ResolutionIn;
|
|
Format = FormatIn;
|
|
|
|
// Regular every frame update
|
|
bHistoryValid = RenderTargets[PreviousRT].IsValid();
|
|
}
|
|
|
|
FRDGTextureRef FTemporalRenderTargetState::GetOrCreateCurrentRT(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(Resolution.X > 0 && Resolution.Y > 0);
|
|
|
|
if (RenderTargets[CurrentRT].IsValid())
|
|
{
|
|
return GraphBuilder.RegisterExternalTexture(RenderTargets[CurrentRT]);
|
|
}
|
|
|
|
FRDGTextureRef RDGTexture = GraphBuilder.CreateTexture(
|
|
FRDGTextureDesc::Create2D(Resolution, Format, FClearValueBinding(FLinearColor(0.0f, 0.0f, 0.0f, 1.0f)),
|
|
TexCreate_ShaderResource | TexCreate_UAV | TexCreate_RenderTargetable), TEXT("VolumetricRenderTarget.GeneralTemporalTexture"));
|
|
return RDGTexture;
|
|
}
|
|
void FTemporalRenderTargetState::ExtractCurrentRT(FRDGBuilder& GraphBuilder, FRDGTextureRef RDGTexture)
|
|
{
|
|
check(Resolution.X > 0 && Resolution.Y > 0);
|
|
|
|
RenderTargets[CurrentRT] = GraphBuilder.ConvertToExternalTexture(RDGTexture);
|
|
}
|
|
|
|
FRDGTextureRef FTemporalRenderTargetState::GetOrCreatePreviousRT(FRDGBuilder& GraphBuilder)
|
|
{
|
|
check(Resolution.X > 0 && Resolution.Y > 0);
|
|
const uint32 PreviousRT = 1u - CurrentRT;
|
|
check(RenderTargets[PreviousRT].IsValid());
|
|
|
|
return GraphBuilder.RegisterExternalTexture(RenderTargets[PreviousRT]);
|
|
}
|
|
|
|
void FTemporalRenderTargetState::Reset()
|
|
{
|
|
bFirstTimeUsed = false;
|
|
bHistoryValid = false;
|
|
FrameId = 0;
|
|
for (int32 i = 0; i < kRenderTargetCount; ++i)
|
|
{
|
|
RenderTargets[i].SafeRelease();
|
|
}
|
|
Resolution = FIntPoint::ZeroValue;
|
|
Format = PF_MAX;
|
|
}
|
|
|