Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/RayTracing/RaytracingSkylight.cpp
2025-05-18 13:04:45 +08:00

720 lines
29 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
RaytracingSkyLight.cpp implements sky lighting with ray tracing
=============================================================================*/
#include "DeferredShadingRenderer.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "SceneTextureParameters.h"
#include "DataDrivenShaderPlatformInfo.h"
static int32 GRayTracingSkyLight = 0;
static FAutoConsoleVariableRef CVarRayTracingSkyLight(
TEXT("r.RayTracing.SkyLight"),
GRayTracingSkyLight,
TEXT("Enables ray tracing SkyLight (default = 0)"),
ECVF_RenderThreadSafe | ECVF_Scalability
);
#if RHI_RAYTRACING
#include "RayTracingSkyLight.h"
#include "RayTracingMaterialHitShaders.h"
#include "ClearQuad.h"
#include "DistanceFieldAmbientOcclusion.h"
#include "SceneRendering.h"
#include "ScenePrivate.h"
#include "SceneProxies/SkyLightSceneProxy.h"
#include "PostProcess/SceneRenderTargets.h"
#include "RenderGraphBuilder.h"
#include "RenderTargetPool.h"
#include "VisualizeTexture.h"
#include "RayGenShaderUtils.h"
#include "SceneTextureParameters.h"
#include "ScreenSpaceDenoise.h"
#include "RayTracingDefinitions.h"
#include "PathTracing.h"
#include "Nanite/NaniteRayTracing.h"
#include "RayTracing/RaytracingOptions.h"
#include "RayTracing/RayTracing.h"
#include "PostProcess/PostProcessing.h"
#include "PostProcess/SceneFilterRendering.h"
#include "HairStrands/HairStrandsRendering.h"
static int32 GRayTracingSkyLightSamplesPerPixel = -1;
static FAutoConsoleVariableRef CVarRayTracingSkyLightSamplesPerPixel(
TEXT("r.RayTracing.SkyLight.SamplesPerPixel"),
GRayTracingSkyLightSamplesPerPixel,
TEXT("Sets the samples-per-pixel for ray tracing SkyLight (default = -1)")
);
static float GRayTracingSkyLightMaxRayDistance = 1.0e7;
static FAutoConsoleVariableRef CVarRayTracingSkyLightMaxRayDistance(
TEXT("r.RayTracing.SkyLight.MaxRayDistance"),
GRayTracingSkyLightMaxRayDistance,
TEXT("Sets the max ray distance for ray tracing SkyLight (default = 1.0e7)")
);
static float GRayTracingSkyLightMaxShadowThickness = 1.0e3;
static FAutoConsoleVariableRef CVarRayTracingSkyLightMaxShadowThickness(
TEXT("r.RayTracing.SkyLight.MaxShadowThickness"),
GRayTracingSkyLightMaxShadowThickness,
TEXT("Sets the max shadow thickness for translucent materials for ray tracing SkyLight (default = 1.0e3)")
);
static int32 GRayTracingSkyLightSamplingStopLevel = 0;
static FAutoConsoleVariableRef CVarRayTracingSkyLightSamplingStopLevel(
TEXT("r.RayTracing.SkyLight.Sampling.StopLevel"),
GRayTracingSkyLightSamplingStopLevel,
TEXT("Sets the stop level for MIP-sampling (default = 0)")
);
static int32 GRayTracingSkyLightDenoiser = 1;
static FAutoConsoleVariableRef CVarRayTracingSkyLightDenoiser(
TEXT("r.RayTracing.SkyLight.Denoiser"),
GRayTracingSkyLightDenoiser,
TEXT("Denoising options (default = 1)")
);
static TAutoConsoleVariable<int32> CVarRayTracingSkyLightEnableTwoSidedGeometry(
TEXT("r.RayTracing.SkyLight.EnableTwoSidedGeometry"),
1,
TEXT("Enables two-sided geometry when tracing shadow rays (default = 1)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarRayTracingSkyLightEnableMaterials(
TEXT("r.RayTracing.SkyLight.EnableMaterials"),
1,
TEXT("Enables material shader binding for shadow rays. If this is disabled, then a default trivial shader is used. (default = 1)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarRayTracingSkyLightDecoupleSampleGeneration(
TEXT("r.RayTracing.SkyLight.DecoupleSampleGeneration"),
1,
TEXT("Decouples sample generation from ray traversal (default = 1)"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarRayTracingSkyLightEnableHairVoxel(
TEXT("r.RayTracing.SkyLight.HairVoxel"),
1,
TEXT("Include hair voxel representation to estimate sky occlusion"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarRayTracingSkyLightScreenPercentage(
TEXT("r.RayTracing.SkyLight.ScreenPercentage"),
100.0f,
TEXT("Screen percentage at which to evaluate sky occlusion"),
ECVF_RenderThreadSafe
);
int32 GetRayTracingSkyLightDecoupleSampleGenerationCVarValue()
{
return CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread();
}
int32 GetSkyLightSamplesPerPixel(const FSkyLightSceneProxy* SkyLightSceneProxy)
{
check(SkyLightSceneProxy != nullptr);
// Clamp to 2spp minimum due to poor 1spp denoised quality
return GRayTracingSkyLightSamplesPerPixel >= 0 ? GRayTracingSkyLightSamplesPerPixel : FMath::Max(SkyLightSceneProxy->SamplesPerPixel, 2);
}
bool ShouldRenderRayTracingSkyLight(const FSkyLightSceneProxy* SkyLightSceneProxy, EShaderPlatform ShaderPlatform)
{
if (SkyLightSceneProxy == nullptr || !IsRayTracingEnabled(ShaderPlatform))
{
return false;
}
bool bRayTracingSkyEnabled = (GRayTracingSkyLight > 0 && SkyLightSceneProxy->CastRayTracedShadow == ECastRayTracedShadow::UseProjectSetting)
|| SkyLightSceneProxy->CastRayTracedShadow == ECastRayTracedShadow::Enabled;
return bRayTracingSkyEnabled && ShouldRenderRayTracingSkyLightEffect() && (GetSkyLightSamplesPerPixel(SkyLightSceneProxy) > 0);
}
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSkyLightData, "SkyLight");
struct FSkyLightVisibilityRays
{
FVector4f DirectionAndPdf;
};
bool SetupSkyLightParameters(
FRDGBuilder& GraphBuilder, FScene* Scene, const FViewInfo& View,
bool bEnableSkylight,
FPathTracingSkylight* SkylightParameters,
FSkyLightData* SkyLightData)
{
// Check if parameters should be set based on if the sky light's texture has been processed and if its mip tree has been built yet
const bool bUseMISCompensation = true;
if (PrepareSkyTexture(GraphBuilder, Scene, View, bEnableSkylight, bUseMISCompensation, SkylightParameters))
{
SkyLightData->SamplesPerPixel = GetSkyLightSamplesPerPixel(Scene->SkyLight);
SkyLightData->MaxRayDistance = GRayTracingSkyLightMaxRayDistance;
SkyLightData->MaxNormalBias = GetRaytracingMaxNormalBias();
SkyLightData->bTransmission = Scene->SkyLight->bTransmission;
SkyLightData->MaxShadowThickness = GRayTracingSkyLightMaxShadowThickness;
ensure(SkyLightData->SamplesPerPixel > 0);
return true;
}
else
{
// skylight is not enabled
SkyLightData->SamplesPerPixel = -1;
SkyLightData->MaxRayDistance = 0.0f;
SkyLightData->MaxNormalBias = 0.0f;
SkyLightData->MaxShadowThickness = 0.0f;
return false;
}
}
void SetupSkyLightVisibilityRaysParameters(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
FSkyLightVisibilityRaysData* OutSkyLightVisibilityRaysData)
{
// Get the Scene View State
FSceneViewState* SceneViewState = (FSceneViewState*)View.State;
FRDGBufferRef SkyLightVisibilityRaysBuffer = nullptr;
FIntVector SkyLightVisibilityRaysDimensions;
// Check if the Sky Light Visibility Ray Data should be set based on if decoupled sample generation is being used
if (
(SceneViewState != nullptr) &&
(SceneViewState->SkyLightVisibilityRaysBuffer != nullptr) &&
(CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() == 1))
{
// Set the Sky Light Visibility Ray pooled buffer to the stored pooled buffer
SkyLightVisibilityRaysBuffer = GraphBuilder.RegisterExternalBuffer(SceneViewState->SkyLightVisibilityRaysBuffer);
// Set the Sky Light Visibility Ray Dimensions from the stored dimensions
SkyLightVisibilityRaysDimensions = SceneViewState->SkyLightVisibilityRaysDimensions;
}
else
{
// Create a dummy Sky Light Visibility Ray buffer in a dummy RDG
FRDGBufferDesc DummyBufferDesc = FRDGBufferDesc::CreateStructuredDesc(sizeof(FSkyLightVisibilityRays), 1);
SkyLightVisibilityRaysBuffer = GraphBuilder.CreateBuffer(DummyBufferDesc, TEXT("DummySkyLightVisibilityRays"));
FRDGBufferUAVRef DummyRDGBufferUAV = GraphBuilder.CreateUAV(SkyLightVisibilityRaysBuffer, EPixelFormat::PF_R32_UINT);
// Clear the dummy Sky Light Visibility Ray buffer
AddClearUAVPass(GraphBuilder, DummyRDGBufferUAV, 0);
// Set the Sky Light Visibility Ray Dimensions to a dummy value
SkyLightVisibilityRaysDimensions = FIntVector(1);
}
// Set Sky Light Visibility Ray Data information
OutSkyLightVisibilityRaysData->SkyLightVisibilityRays = GraphBuilder.CreateSRV(SkyLightVisibilityRaysBuffer, EPixelFormat::PF_R32_UINT);
OutSkyLightVisibilityRaysData->SkyLightVisibilityRaysDimensions = SkyLightVisibilityRaysDimensions;
}
class FRayTracingSkyLightRGS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FRayTracingSkyLightRGS)
SHADER_USE_ROOT_PARAMETER_STRUCT(FRayTracingSkyLightRGS, FGlobalShader)
class FEnableTwoSidedGeometryDim : SHADER_PERMUTATION_BOOL("ENABLE_TWO_SIDED_GEOMETRY");
class FEnableMaterialsDim : SHADER_PERMUTATION_BOOL("ENABLE_MATERIALS");
class FDecoupleSampleGeneration : SHADER_PERMUTATION_BOOL("DECOUPLE_SAMPLE_GENERATION");
class FHairLighting : SHADER_PERMUTATION_INT("USE_HAIR_LIGHTING", 2);
using FPermutationDomain = TShaderPermutationDomain<FEnableTwoSidedGeometryDim, FEnableMaterialsDim, FDecoupleSampleGeneration, FHairLighting>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileRayTracingShadersForProject(Parameters.Platform);
}
static ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId)
{
return ERayTracingPayloadType::RayTracingMaterial;
}
static const FShaderBindingLayout* GetShaderBindingLayout(const FShaderPermutationParameters& Parameters)
{
return RayTracing::GetShaderBindingLayout(Parameters.Platform);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, UpscaleFactor)
SHADER_PARAMETER_RDG_BUFFER_SRV(RaytracingAccelerationStructure, TLAS)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWSkyOcclusionMaskUAV)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float2>, RWSkyOcclusionRayDistanceUAV)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_STRUCT_REF(FSkyLightData, SkyLightData)
SHADER_PARAMETER_STRUCT_INCLUDE(FPathTracingSkylight, SkyLightParameters)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualVoxelParameters, VirtualVoxel)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FNaniteRayTracingUniformParameters, NaniteRayTracing)
SHADER_PARAMETER_STRUCT_INCLUDE(FSkyLightVisibilityRaysData, SkyLightVisibilityRaysData)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FRayTracingSkyLightRGS, "/Engine/Private/Raytracing/RaytracingSkylightRGS.usf", "SkyLightRGS", SF_RayGen);
void FDeferredShadingSceneRenderer::PrepareRayTracingSkyLight(const FViewInfo& View, const FScene& Scene, TArray<FRHIRayTracingShader*>& OutRayGenShaders)
{
if (!ShouldRenderRayTracingSkyLight(Scene.SkyLight, View.GetShaderPlatform()))
{
return;
}
// Declare all RayGen shaders that require material closest hit shaders to be bound
FRayTracingSkyLightRGS::FPermutationDomain PermutationVector;
for (uint32 TwoSidedGeometryIndex = 0; TwoSidedGeometryIndex < 2; ++TwoSidedGeometryIndex)
{
for (uint32 EnableMaterialsIndex = 0; EnableMaterialsIndex < 2; ++EnableMaterialsIndex)
{
for (uint32 DecoupleSampleGeneration = 0; DecoupleSampleGeneration < 2; ++DecoupleSampleGeneration)
{
for (int32 HairLighting = 0; HairLighting < 2; ++HairLighting)
{
PermutationVector.Set<FRayTracingSkyLightRGS::FEnableTwoSidedGeometryDim>(TwoSidedGeometryIndex != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FEnableMaterialsDim>(EnableMaterialsIndex != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FDecoupleSampleGeneration>(DecoupleSampleGeneration != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FHairLighting>(HairLighting);
TShaderMapRef<FRayTracingSkyLightRGS> RayGenerationShader(View.ShaderMap, PermutationVector);
OutRayGenShaders.Add(RayGenerationShader.GetRayTracingShader());
}
}
}
}
}
class FGenerateSkyLightVisibilityRaysCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FGenerateSkyLightVisibilityRaysCS);
SHADER_USE_PARAMETER_STRUCT(FGenerateSkyLightVisibilityRaysCS, FGlobalShader);
static const uint32 kGroupSize = 16;
using FPermutationDomain = FShaderPermutationNone;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileRayTracingShadersForProject(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("TILE_SIZE"), kGroupSize);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(int32, SamplesPerPixel)
SHADER_PARAMETER_STRUCT_INCLUDE(FPathTracingSkylight, SkylightParameters)
SHADER_PARAMETER_STRUCT_REF(FSkyLightData, SkyLightData)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
// Writable variant to allow for Sky Light Visibility Ray output
SHADER_PARAMETER_STRUCT_INCLUDE(FWritableSkyLightVisibilityRaysData, WritableSkyLightVisibilityRaysData)
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FGenerateSkyLightVisibilityRaysCS, "/Engine/Private/RayTracing/GenerateSkyLightVisibilityRaysCS.usf", "MainCS", SF_Compute);
static void GenerateSkyLightVisibilityRays(
FRDGBuilder& GraphBuilder,
FViewInfo& View,
FPathTracingSkylight& SkylightParameters,
FSkyLightData& SkyLightData,
FRDGBufferRef& SkyLightVisibilityRaysBuffer,
FIntVector& Dimensions
)
{
// Allocating mask of 256 x 256 rays
Dimensions = FIntVector(256, 256, 0);
// Compute Pass parameter definition
FGenerateSkyLightVisibilityRaysCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FGenerateSkyLightVisibilityRaysCS::FParameters>();
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->SkyLightData = CreateUniformBufferImmediate(SkyLightData, EUniformBufferUsage::UniformBuffer_SingleDraw);
PassParameters->SkylightParameters = SkylightParameters;
// Output structured buffer creation
FRDGBufferDesc BufferDesc = FRDGBufferDesc::CreateStructuredDesc(sizeof(FSkyLightVisibilityRays), Dimensions.X * Dimensions.Y * SkyLightData.SamplesPerPixel);
SkyLightVisibilityRaysBuffer = GraphBuilder.CreateBuffer(BufferDesc, TEXT("SkyLightVisibilityRays"));
PassParameters->WritableSkyLightVisibilityRaysData.SkyLightVisibilityRaysDimensions = FIntVector(Dimensions.X, Dimensions.Y, 0);
PassParameters->WritableSkyLightVisibilityRaysData.OutSkyLightVisibilityRays = GraphBuilder.CreateUAV(SkyLightVisibilityRaysBuffer, EPixelFormat::PF_R32_UINT);
auto ComputeShader = View.ShaderMap->GetShader<FGenerateSkyLightVisibilityRaysCS>();
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("GenerateSkyLightVisibilityRays"),
ComputeShader,
PassParameters,
FComputeShaderUtils::GetGroupCount(FIntPoint(Dimensions.X, Dimensions.Y), FGenerateSkyLightVisibilityRaysCS::kGroupSize)
);
}
DECLARE_GPU_STAT_NAMED(RayTracingSkyLight, TEXT("Ray Tracing SkyLight"));
void FDeferredShadingSceneRenderer::RenderRayTracingSkyLight(
FRDGBuilder& GraphBuilder,
FRDGTextureRef SceneColorTexture,
FRDGTextureRef& OutSkyLightTexture,
FRDGTextureRef& OutHitDistanceTexture)
{
FSkyLightSceneProxy* SkyLight = Scene->SkyLight;
// Fill Sky Light parameters
const bool bShouldRenderRayTracingSkyLight = ShouldRenderRayTracingSkyLight(SkyLight, Scene->GetShaderPlatform());
FPathTracingSkylight SkylightParameters;
FSkyLightData SkyLightData;
if (!SetupSkyLightParameters(GraphBuilder, Scene, Views[0], bShouldRenderRayTracingSkyLight, &SkylightParameters, &SkyLightData))
{
OutSkyLightTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
OutHitDistanceTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
return;
}
RDG_EVENT_SCOPE_STAT(GraphBuilder, RayTracingSkyLight, "RayTracingSkyLight");
RDG_GPU_STAT_SCOPE(GraphBuilder, RayTracingSkyLight);
check(SceneColorTexture);
float ResolutionFraction = 1.0f;
if (GRayTracingSkyLightDenoiser != 0)
{
ResolutionFraction = FMath::Clamp(CVarRayTracingSkyLightScreenPercentage.GetValueOnRenderThread() / 100.0f, 0.25f, 1.0f);
}
int32 UpscaleFactor = int32(1.0 / ResolutionFraction);
ResolutionFraction = 1.0f / UpscaleFactor;
{
FRDGTextureDesc Desc = SceneColorTexture->Desc;
Desc.Format = PF_FloatRGBA;
Desc.Flags &= ~(TexCreate_FastVRAM);
Desc.Extent /= UpscaleFactor;
OutSkyLightTexture = GraphBuilder.CreateTexture(Desc, TEXT("RayTracingSkylight"));
Desc.Format = PF_G16R16;
OutHitDistanceTexture = GraphBuilder.CreateTexture(Desc, TEXT("RayTracingSkyLightHitDistance"));
}
FRDGBufferRef SkyLightVisibilityRaysBuffer;
FIntVector SkyLightVisibilityRaysDimensions;
if (CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() == 1)
{
GenerateSkyLightVisibilityRays(GraphBuilder, Views[0], SkylightParameters, SkyLightData, SkyLightVisibilityRaysBuffer, SkyLightVisibilityRaysDimensions);
}
else
{
FRDGBufferDesc BufferDesc = FRDGBufferDesc::CreateStructuredDesc(sizeof(FSkyLightVisibilityRays), 1);
SkyLightVisibilityRaysBuffer = GraphBuilder.CreateBuffer(BufferDesc, TEXT("SkyLightVisibilityRays"));
SkyLightVisibilityRaysDimensions = FIntVector(1);
}
const FRDGTextureDesc& SceneColorDesc = SceneColorTexture->Desc;
FRDGTextureUAV* SkyLightkUAV = GraphBuilder.CreateUAV(OutSkyLightTexture);
FRDGTextureUAV* RayDistanceUAV = GraphBuilder.CreateUAV(OutHitDistanceTexture);
// Fill Scene Texture parameters
FSceneTextureParameters SceneTextures = GetSceneTextureParameters(GraphBuilder, Views[0]);
const FRayTracingScene& RayTracingScene = Scene->RayTracingScene;
for (FViewInfo& View : Views)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
FRayTracingSkyLightRGS::FParameters *PassParameters = GraphBuilder.AllocParameters<FRayTracingSkyLightRGS::FParameters>();
PassParameters->RWSkyOcclusionMaskUAV = SkyLightkUAV;
PassParameters->RWSkyOcclusionRayDistanceUAV = RayDistanceUAV;
PassParameters->SkyLightParameters = SkylightParameters;
PassParameters->SkyLightData = CreateUniformBufferImmediate(SkyLightData, EUniformBufferUsage::UniformBuffer_SingleDraw);
PassParameters->SkyLightVisibilityRaysData.SkyLightVisibilityRaysDimensions = SkyLightVisibilityRaysDimensions;
if (CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() == 1)
{
PassParameters->SkyLightVisibilityRaysData.SkyLightVisibilityRays = GraphBuilder.CreateSRV(SkyLightVisibilityRaysBuffer, EPixelFormat::PF_R32_UINT);
}
PassParameters->SceneTextures = SceneTextures;
PassParameters->UpscaleFactor = UpscaleFactor;
PassParameters->TLAS = View.GetRayTracingSceneLayerViewChecked(ERayTracingSceneLayer::Base);
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->Scene = GetSceneUniformBufferRef(GraphBuilder);
PassParameters->NaniteRayTracing = Nanite::GRayTracingManager.GetUniformBuffer();
const bool bUseHairLighting =
HairStrands::HasViewHairStrandsData(View) &&
HairStrands::HasViewHairStrandsVoxelData(View) &&
CVarRayTracingSkyLightEnableHairVoxel.GetValueOnRenderThread() > 0;
if (bUseHairLighting)
{
PassParameters->VirtualVoxel = HairStrands::BindHairStrandsVoxelUniformParameters(View);
}
FRayTracingSkyLightRGS::FPermutationDomain PermutationVector;
PermutationVector.Set<FRayTracingSkyLightRGS::FEnableTwoSidedGeometryDim>(CVarRayTracingSkyLightEnableTwoSidedGeometry.GetValueOnRenderThread() != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FEnableMaterialsDim>(CVarRayTracingSkyLightEnableMaterials.GetValueOnRenderThread() != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FDecoupleSampleGeneration>(CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() != 0);
PermutationVector.Set<FRayTracingSkyLightRGS::FHairLighting>(bUseHairLighting ? 1 : 0);
TShaderMapRef<FRayTracingSkyLightRGS> RayGenerationShader(GetGlobalShaderMap(FeatureLevel), PermutationVector);
ClearUnusedGraphResources(RayGenerationShader, PassParameters);
FIntPoint RayTracingResolution = View.ViewRect.Size() / UpscaleFactor;
GraphBuilder.AddPass(
RDG_EVENT_NAME("SkyLightRayTracing %dx%d", RayTracingResolution.X, RayTracingResolution.Y),
PassParameters,
ERDGPassFlags::Compute,
[PassParameters, this, &View, RayGenerationShader, RayTracingResolution](FRHICommandList& RHICmdList)
{
FRHIBatchedShaderParameters& GlobalResources = RHICmdList.GetScratchShaderParameters();
SetShaderParameters(GlobalResources, RayGenerationShader, *PassParameters);
FRHIUniformBuffer* SceneUniformBuffer = PassParameters->Scene->GetRHI();
FRHIUniformBuffer* NaniteRayTracingUniformBuffer = PassParameters->NaniteRayTracing->GetRHI();
TOptional<FScopedUniformBufferStaticBindings> StaticUniformBufferScope = RayTracing::BindStaticUniformBufferBindings(View, SceneUniformBuffer, NaniteRayTracingUniformBuffer, RHICmdList);
FRayTracingPipelineState* Pipeline = View.MaterialRayTracingData.PipelineState;
FShaderBindingTableRHIRef SBT = View.MaterialRayTracingData.ShaderBindingTable;
if (CVarRayTracingSkyLightEnableMaterials.GetValueOnRenderThread() == 0)
{
// Declare default pipeline
FRayTracingPipelineStateInitializer Initializer;
const FShaderBindingLayout* ShaderBindingLayout = RayTracing::GetShaderBindingLayout(ShaderPlatform);
if (ShaderBindingLayout)
{
Initializer.ShaderBindingLayout = &ShaderBindingLayout->RHILayout;
}
Initializer.MaxPayloadSizeInBytes = GetRayTracingPayloadTypeMaxSize(ERayTracingPayloadType::RayTracingMaterial);
FRHIRayTracingShader* RayGenShaderTable[] = { RayGenerationShader.GetRayTracingShader() };
Initializer.SetRayGenShaderTable(RayGenShaderTable);
FRHIRayTracingShader* HitGroupTable[] = { GetRayTracingDefaultOpaqueShader(View.ShaderMap) };
Initializer.SetHitGroupTable(HitGroupTable);
FRHIRayTracingShader* MissGroupTable[] = { GetRayTracingDefaultMissShader(View.ShaderMap) };
Initializer.SetMissShaderTable(MissGroupTable);
Pipeline = PipelineStateCache::GetAndOrCreateRayTracingPipelineState(RHICmdList, Initializer);
SBT = Scene->RayTracingSBT.AllocateTransientRHI(RHICmdList, ERayTracingShaderBindingMode::RTPSO, ERayTracingHitGroupIndexingMode::Disallow, Initializer.GetMaxLocalBindingDataSize());
RHICmdList.SetDefaultRayTracingHitGroup(SBT, Pipeline, 0);
RHICmdList.SetRayTracingMissShader(SBT, 0, Pipeline, 0 /* ShaderIndexInPipeline */, 0, nullptr, 0);
RHICmdList.CommitShaderBindingTable(SBT);
}
RHICmdList.RayTraceDispatch(Pipeline, RayGenerationShader.GetRayTracingShader(), SBT, GlobalResources, RayTracingResolution.X, RayTracingResolution.Y);
});
}
// Denoising
if (GRayTracingSkyLightDenoiser != 0)
{
const IScreenSpaceDenoiser* DefaultDenoiser = IScreenSpaceDenoiser::GetDefaultDenoiser();
const IScreenSpaceDenoiser* DenoiserToUse = DefaultDenoiser;
IScreenSpaceDenoiser::FDiffuseIndirectInputs DenoiserInputs;
DenoiserInputs.Color = OutSkyLightTexture;
DenoiserInputs.RayHitDistance = OutHitDistanceTexture;
IScreenSpaceDenoiser::FAmbientOcclusionRayTracingConfig RayTracingConfig;
RayTracingConfig.ResolutionFraction = ResolutionFraction;
RayTracingConfig.RayCountPerPixel = GetSkyLightSamplesPerPixel(SkyLight);
bool bAllViewsSameGPU = true;
#if WITH_MGPU
for (int32 ViewIndex = 1; ViewIndex < Views.Num(); ViewIndex++)
{
if (Views[ViewIndex].GPUMask != Views[0].GPUMask)
{
bAllViewsSameGPU = false;
}
}
#endif
if (bAllViewsSameGPU && DenoiserToUse == DefaultDenoiser)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, Views[0].GPUMask);
RDG_EVENT_SCOPE(GraphBuilder, "%s(SkyLight) %s",
DenoiserToUse->GetDebugName(),
Views.Num() > 1 ?
*FString::Printf(TEXT("%d views"), Views.Num()) :
*FString::Printf(TEXT("%dx%d"), Views[0].ViewRect.Width(), Views[0].ViewRect.Height()));
// Multi-view version of DenoiseSkyLight, which saves memory by sharing persistent render targets across views.
// Persistent render targets are stored on the first view, so PrevViewInfo for the first view is passed in.
IScreenSpaceDenoiser::FDiffuseIndirectOutputs DenoiserOutputs = IScreenSpaceDenoiser::DenoiseSkyLight(
GraphBuilder,
Views,
&Views[0].PrevViewInfo,
SceneTextures,
DenoiserInputs,
RayTracingConfig);
OutSkyLightTexture = DenoiserOutputs.Color;
}
else
{
int32 ViewIndex = 0;
int32 LastViewIndex = Views.Num() - 1;
for (FViewInfo& View : Views)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE(GraphBuilder, "%s%s(SkyLight) %dx%d",
DenoiserToUse != DefaultDenoiser ? TEXT("ThirdParty ") : TEXT(""),
DenoiserToUse->GetDebugName(),
View.ViewRect.Width(), View.ViewRect.Height());
IScreenSpaceDenoiser::FDiffuseIndirectOutputs DenoiserOutputs = DenoiserToUse->DenoiseSkyLight(
GraphBuilder,
View,
&View.PrevViewInfo,
SceneTextures,
DenoiserInputs,
RayTracingConfig);
// Need to set output used by the caller on the last iteration of the view loop
if (ViewIndex == LastViewIndex)
{
OutSkyLightTexture = DenoiserOutputs.Color;
}
++ViewIndex;
}
}
}
for (FViewInfo& View : Views)
{
FSceneViewState* SceneViewState = (FSceneViewState*)View.State;
if (SceneViewState != nullptr)
{
if (CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() == 1)
{
// Set the Sky Light Visibility Ray dimensions and its extracted pooled RDG buffer on the scene view state
GraphBuilder.QueueBufferExtraction(SkyLightVisibilityRaysBuffer, &SceneViewState->SkyLightVisibilityRaysBuffer);
SceneViewState->SkyLightVisibilityRaysDimensions = SkyLightVisibilityRaysDimensions;
}
else
{
// Set invalid Sky Light Visibility Ray dimensions and pooled RDG buffer
SceneViewState->SkyLightVisibilityRaysBuffer = nullptr;
SceneViewState->SkyLightVisibilityRaysDimensions = FIntVector(1);
}
}
}
}
class FCompositeSkyLightPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FCompositeSkyLightPS)
SHADER_USE_PARAMETER_STRUCT(FCompositeSkyLightPS, FGlobalShader)
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileRayTracingShadersForProject(Parameters.Platform);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RENDER_TARGET_BINDING_SLOTS()
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SkyLightTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SkyLightTextureSampler)
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FCompositeSkyLightPS, "/Engine/Private/RayTracing/CompositeSkyLightPS.usf", "CompositeSkyLightPS", SF_Pixel);
#endif // RHI_RAYTRACING
void FDeferredShadingSceneRenderer::CompositeRayTracingSkyLight(
FRDGBuilder& GraphBuilder,
const FMinimalSceneTextures& SceneTextures,
FRDGTextureRef SkyLightRT,
FRDGTextureRef HitDistanceRT)
#if RHI_RAYTRACING
{
check(SkyLightRT);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
FSceneTextureParameters SceneTextureParameters = GetSceneTextureParameters(GraphBuilder, SceneTextures.UniformBuffer);
FCompositeSkyLightPS::FParameters *PassParameters = GraphBuilder.AllocParameters<FCompositeSkyLightPS::FParameters>();
PassParameters->SkyLightTexture = SkyLightRT;
PassParameters->SkyLightTextureSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->View = Views[ViewIndex].GetShaderParameters();
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.Color.Target, ERenderTargetLoadAction::ELoad);
PassParameters->SceneTextures = SceneTextureParameters;
// dxr_todo: Unify with RTGI compositing workflow
GraphBuilder.AddPass(
RDG_EVENT_NAME("GlobalIlluminationComposite"),
PassParameters,
ERDGPassFlags::Raster,
[this, &View, PassParameters, SceneTextureExtent = SceneTextures.Config.Extent](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
TShaderMapRef<FCompositeSkyLightPS> PixelShader(View.ShaderMap);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
// Additive blending
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_One>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
RHICmdList.SetViewport((float)View.ViewRect.Min.X, (float)View.ViewRect.Min.Y, 0.0f, (float)View.ViewRect.Max.X, (float)View.ViewRect.Max.Y, 1.0f);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
View.ViewRect.Min.X, View.ViewRect.Min.Y,
View.ViewRect.Width(), View.ViewRect.Height(),
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
SceneTextureExtent,
VertexShader
);
});
}
}
#else
{
unimplemented();
}
#endif