You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb trivial #jira UE-140499 #preflight 61f9192c80608c7029b3a8ed #ROBOMERGE-AUTHOR: guillaume.abadie #ROBOMERGE-SOURCE: CL 18806910 in //UE5/Release-5.0/... via CL 18808614 via CL 18822202 #ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545) [CL 18822504 by guillaume abadie in ue5-main branch]
243 lines
9.2 KiB
C++
243 lines
9.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "PostProcess/PostProcessBloomSetup.h"
|
|
#include "PostProcess/PostProcessDownsample.h"
|
|
#include "PostProcess/PostProcessFFTBloom.h"
|
|
#include "PostProcess/PostProcessWeightedSampleSum.h"
|
|
#include "PixelShaderUtils.h"
|
|
|
|
namespace
|
|
{
|
|
const int32 GBloomSetupComputeTileSizeX = 8;
|
|
const int32 GBloomSetupComputeTileSizeY = 8;
|
|
|
|
TAutoConsoleVariable<float> CVarBloomCross(
|
|
TEXT("r.GaussianBloom.Cross"),
|
|
0.0f,
|
|
TEXT("Experimental feature to give bloom kernel a more bright center sample (values between 1 and 3 work without causing aliasing)\n")
|
|
TEXT("Existing bloom get lowered to match the same brightness\n")
|
|
TEXT("<0 for a anisomorphic lens flare look (X only)\n")
|
|
TEXT(" 0 off (default)\n")
|
|
TEXT(">0 for a cross look (X and Y)"),
|
|
ECVF_RenderThreadSafe);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FBloomSetupParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Input)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, InputTexture)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, InputSampler)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, EyeAdaptationTexture)
|
|
SHADER_PARAMETER(float, BloomThreshold)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
FBloomSetupParameters GetBloomSetupParameters(
|
|
const FViewInfo& View,
|
|
const FScreenPassTextureViewport& InputViewport,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef EyeAdaptationTexture,
|
|
float BloomThreshold)
|
|
{
|
|
FBloomSetupParameters Parameters;
|
|
Parameters.View = View.ViewUniformBuffer;
|
|
Parameters.Input = GetScreenPassTextureViewportParameters(InputViewport);
|
|
Parameters.InputTexture = InputTexture;
|
|
Parameters.InputSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
Parameters.EyeAdaptationTexture = EyeAdaptationTexture;
|
|
Parameters.BloomThreshold = BloomThreshold;
|
|
return Parameters;
|
|
}
|
|
|
|
class FBloomSetupPS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FBloomSetupPS);
|
|
SHADER_USE_PARAMETER_STRUCT(FBloomSetupPS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FBloomSetupParameters, BloomSetup)
|
|
SHADER_PARAMETER(FScreenTransform, SvPositionToInputTextureUV)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FBloomSetupPS, "/Engine/Private/PostProcessBloom.usf", "BloomSetupPS", SF_Pixel);
|
|
|
|
class FBloomSetupCS : public FGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FBloomSetupCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FBloomSetupCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FBloomSetupParameters, BloomSetup)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWOutputTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), GBloomSetupComputeTileSizeX);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), GBloomSetupComputeTileSizeY);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FBloomSetupCS, "/Engine/Private/PostProcessBloom.usf", "BloomSetupCS", SF_Compute);
|
|
} //!namespace
|
|
|
|
FScreenPassTexture AddBloomSetupPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FBloomSetupInputs& Inputs)
|
|
{
|
|
check(Inputs.SceneColor.IsValid());
|
|
check(Inputs.EyeAdaptationTexture);
|
|
check(Inputs.Threshold > -1.0f);
|
|
|
|
const bool bIsComputePass = View.bUseComputePasses;
|
|
|
|
FRDGTextureDesc OutputDesc = Inputs.SceneColor.Texture->Desc;
|
|
OutputDesc.Reset();
|
|
OutputDesc.Flags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable;
|
|
|
|
const FScreenPassTextureViewport Viewport(Inputs.SceneColor);
|
|
const FScreenPassRenderTarget Output(GraphBuilder.CreateTexture(OutputDesc, TEXT("BloomSetup")), Viewport.Rect, View.GetOverwriteLoadAction());
|
|
|
|
if (bIsComputePass)
|
|
{
|
|
FBloomSetupCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FBloomSetupCS::FParameters>();
|
|
PassParameters->BloomSetup = GetBloomSetupParameters(View, Viewport, Inputs.SceneColor.Texture, Inputs.EyeAdaptationTexture, Inputs.Threshold);
|
|
PassParameters->RWOutputTexture = GraphBuilder.CreateUAV(Output.Texture);
|
|
|
|
TShaderMapRef<FBloomSetupCS> ComputeShader(View.ShaderMap);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("BloomSetup %dx%d (CS)", Viewport.Rect.Width(), Viewport.Rect.Height()),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(Viewport.Rect.Size(), FIntPoint(GBloomSetupComputeTileSizeX, GBloomSetupComputeTileSizeY)));
|
|
}
|
|
else
|
|
{
|
|
FBloomSetupPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FBloomSetupPS::FParameters>();
|
|
PassParameters->BloomSetup = GetBloomSetupParameters(View, Viewport, Inputs.SceneColor.Texture, Inputs.EyeAdaptationTexture, Inputs.Threshold);
|
|
PassParameters->SvPositionToInputTextureUV = (
|
|
FScreenTransform::ChangeTextureBasisFromTo(FScreenPassTextureViewport(Output), FScreenTransform::ETextureBasis::TexelPosition, FScreenTransform::ETextureBasis::ViewportUV) *
|
|
FScreenTransform::ChangeTextureBasisFromTo(FScreenPassTextureViewport(Inputs.SceneColor), FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV));
|
|
PassParameters->RenderTargets[0] = Output.GetRenderTargetBinding();
|
|
|
|
TShaderMapRef<FBloomSetupPS> PixelShader(View.ShaderMap);
|
|
FPixelShaderUtils::AddFullscreenPass(
|
|
GraphBuilder,
|
|
View.ShaderMap,
|
|
RDG_EVENT_NAME("BloomSetup %dx%d (PS)", Viewport.Rect.Width(), Viewport.Rect.Height()),
|
|
PixelShader,
|
|
PassParameters,
|
|
Output.ViewRect);
|
|
}
|
|
|
|
return FScreenPassTexture(Output);
|
|
}
|
|
|
|
EBloomQuality GetBloomQuality()
|
|
{
|
|
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.BloomQuality"));
|
|
|
|
return static_cast<EBloomQuality>(FMath::Clamp(
|
|
CVar->GetValueOnRenderThread(),
|
|
static_cast<int32>(EBloomQuality::Disabled),
|
|
static_cast<int32>(EBloomQuality::MAX) - 1));
|
|
}
|
|
|
|
static_assert(
|
|
static_cast<uint32>(EBloomQuality::MAX) == FSceneDownsampleChain::StageCount,
|
|
"The total number of stages in the scene downsample chain and the number of bloom quality levels must match.");
|
|
|
|
FScreenPassTexture AddGaussianBloomPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FSceneDownsampleChain* SceneDownsampleChain)
|
|
{
|
|
check(SceneDownsampleChain);
|
|
check(!IsFFTBloomEnabled(View));
|
|
|
|
const FFinalPostProcessSettings& Settings = View.FinalPostProcessSettings;
|
|
|
|
const EBloomQuality BloomQuality = GetBloomQuality();
|
|
|
|
FScreenPassTexture PassOutputs;
|
|
if (BloomQuality != EBloomQuality::Disabled)
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "Bloom");
|
|
|
|
const float CrossBloom = CVarBloomCross.GetValueOnRenderThread();
|
|
|
|
const FVector2D CrossCenterWeight(FMath::Max(CrossBloom, 0.0f), FMath::Abs(CrossBloom));
|
|
|
|
check(BloomQuality != EBloomQuality::Disabled);
|
|
const uint32 BloomQualityIndex = static_cast<uint32>(BloomQuality);
|
|
const uint32 BloomQualityCountMax = static_cast<uint32>(EBloomQuality::MAX);
|
|
|
|
struct FBloomStage
|
|
{
|
|
const float Size;
|
|
const FLinearColor& Tint;
|
|
};
|
|
|
|
FBloomStage BloomStages[] =
|
|
{
|
|
{ Settings.Bloom6Size, Settings.Bloom6Tint },
|
|
{ Settings.Bloom5Size, Settings.Bloom5Tint },
|
|
{ Settings.Bloom4Size, Settings.Bloom4Tint },
|
|
{ Settings.Bloom3Size, Settings.Bloom3Tint },
|
|
{ Settings.Bloom2Size, Settings.Bloom2Tint },
|
|
{ Settings.Bloom1Size, Settings.Bloom1Tint }
|
|
};
|
|
|
|
const uint32 BloomQualityToSceneDownsampleStage[] =
|
|
{
|
|
static_cast<uint32>(-1), // Disabled (sentinel entry to preserve indices)
|
|
3, // Q1
|
|
3, // Q2
|
|
4, // Q3
|
|
5, // Q4
|
|
6 // Q5
|
|
};
|
|
|
|
static_assert(UE_ARRAY_COUNT(BloomStages) == BloomQualityCountMax, "Array must be one less than the number of bloom quality entries.");
|
|
static_assert(UE_ARRAY_COUNT(BloomQualityToSceneDownsampleStage) == BloomQualityCountMax, "Array must be one less than the number of bloom quality entries.");
|
|
|
|
check(BloomQualityIndex < BloomQualityCountMax);
|
|
|
|
// Use bloom quality to select the number of downsample stages to use for bloom.
|
|
const uint32 BloomStageCount = BloomQualityToSceneDownsampleStage[BloomQualityIndex];
|
|
|
|
const float TintScale = (1.0f / BloomQualityCountMax) * Settings.BloomIntensity;
|
|
|
|
for (uint32 StageIndex = 0, SourceIndex = BloomQualityCountMax - 1; StageIndex < BloomStageCount; ++StageIndex, --SourceIndex)
|
|
{
|
|
const FBloomStage& BloomStage = BloomStages[StageIndex];
|
|
|
|
if (BloomStage.Size > SMALL_NUMBER)
|
|
{
|
|
FGaussianBlurInputs PassInputs;
|
|
PassInputs.NameX = TEXT("BloomX");
|
|
PassInputs.NameY = TEXT("BloomY");
|
|
PassInputs.Filter = SceneDownsampleChain->GetTexture(SourceIndex);
|
|
PassInputs.Additive = PassOutputs;
|
|
PassInputs.CrossCenterWeight = FVector2f(CrossCenterWeight); // LWC_TODO: Precision loss
|
|
PassInputs.KernelSizePercent = BloomStage.Size * Settings.BloomSizeScale;
|
|
PassInputs.TintColor = BloomStage.Tint * TintScale;
|
|
|
|
PassOutputs = AddGaussianBlurPass(GraphBuilder, View, PassInputs);
|
|
}
|
|
}
|
|
}
|
|
|
|
return PassOutputs;
|
|
}
|