// 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 CVarRayTracingSkyLightEnableTwoSidedGeometry( TEXT("r.RayTracing.SkyLight.EnableTwoSidedGeometry"), 1, TEXT("Enables two-sided geometry when tracing shadow rays (default = 1)"), ECVF_RenderThreadSafe ); static TAutoConsoleVariable 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 CVarRayTracingSkyLightDecoupleSampleGeneration( TEXT("r.RayTracing.SkyLight.DecoupleSampleGeneration"), 1, TEXT("Decouples sample generation from ray traversal (default = 1)"), ECVF_RenderThreadSafe ); static TAutoConsoleVariable CVarRayTracingSkyLightEnableHairVoxel( TEXT("r.RayTracing.SkyLight.HairVoxel"), 1, TEXT("Include hair voxel representation to estimate sky occlusion"), ECVF_RenderThreadSafe ); static TAutoConsoleVariable 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; 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, RWSkyOcclusionMaskUAV) SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, 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& 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(TwoSidedGeometryIndex != 0); PermutationVector.Set(EnableMaterialsIndex != 0); PermutationVector.Set(DecoupleSampleGeneration != 0); PermutationVector.Set(HairLighting); TShaderMapRef 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(); 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(); 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(); 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(CVarRayTracingSkyLightEnableTwoSidedGeometry.GetValueOnRenderThread() != 0); PermutationVector.Set(CVarRayTracingSkyLightEnableMaterials.GetValueOnRenderThread() != 0); PermutationVector.Set(CVarRayTracingSkyLightDecoupleSampleGeneration.GetValueOnRenderThread() != 0); PermutationVector.Set(bUseHairLighting ? 1 : 0); TShaderMapRef 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 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(); PassParameters->SkyLightTexture = SkyLightRT; PassParameters->SkyLightTextureSampler = TStaticSamplerState::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 VertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); // Additive blending GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::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