// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= DistanceFieldObjectCulling.cpp =============================================================================*/ #include "DistanceFieldAmbientOcclusion.h" #include "DeferredShadingRenderer.h" #include "PostProcess/PostProcessing.h" #include "PostProcess/SceneFilterRendering.h" #include "DistanceFieldLightingShared.h" #include "ScreenRendering.h" #include "DistanceFieldLightingPost.h" #include "OneColorShader.h" #include "GlobalDistanceField.h" #include "FXSystem.h" #include "PostProcess/PostProcessSubsurface.h" #include "PipelineStateCache.h" #include "ClearQuad.h" #include "ShaderCompilerCore.h" int32 GAOScatterTileCulling = 1; FAutoConsoleVariableRef CVarAOScatterTileCulling( TEXT("r.AOScatterTileCulling"), GAOScatterTileCulling, TEXT("Whether to use the rasterizer for binning occluder objects into screenspace tiles."), ECVF_RenderThreadSafe ); int32 GAverageDistanceFieldObjectsPerCullTile = 512; FAutoConsoleVariableRef CVarMaxDistanceFieldObjectsPerCullTile( TEXT("r.AOAverageObjectsPerCullTile"), GAverageDistanceFieldObjectsPerCullTile, TEXT("Determines how much memory should be allocated in distance field object culling data structures. Too much = memory waste, too little = flickering due to buffer overflow."), ECVF_RenderThreadSafe | ECVF_ReadOnly ); class FCullObjectsForViewCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FCullObjectsForViewCS); SHADER_USE_PARAMETER_STRUCT(FCullObjectsForViewCS, FGlobalShader); public: BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldCulledObjectBufferParameters, CulledObjectBufferParameters) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldObjectBufferParameters, ObjectBufferParameters) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View) SHADER_PARAMETER(uint32, NumConvexHullPlanes) SHADER_PARAMETER_ARRAY(FVector4, ViewFrustumConvexHull, [6]) SHADER_PARAMETER(uint32, ObjectBoundingGeometryIndexCount) SHADER_PARAMETER(float, AOObjectMaxDistance) SHADER_PARAMETER(float, AOMaxViewDistance) END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment); OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize); } }; IMPLEMENT_GLOBAL_SHADER(FCullObjectsForViewCS, "/Engine/Private/DistanceFieldObjectCulling.usf", "CullObjectsForViewCS", SF_Compute); void CullObjectsToView(FRDGBuilder& GraphBuilder, FScene* Scene, const FViewInfo& View, const FDistanceFieldAOParameters& Parameters, FDistanceFieldCulledObjectBufferParameters& CulledObjectBufferParameters) { AddClearUAVPass(GraphBuilder, CulledObjectBufferParameters.RWObjectIndirectArguments, 0); { const int32 NumObjectsInBuffer = Scene->DistanceFieldSceneData.NumObjectsInBuffer; auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->CulledObjectBufferParameters = CulledObjectBufferParameters; PassParameters->ObjectBufferParameters = DistanceField::SetupObjectBufferParameters(Scene->DistanceFieldSceneData); PassParameters->View = View.ViewUniformBuffer; PassParameters->NumConvexHullPlanes = View.ViewFrustum.Planes.Num(); for (int32 i = 0; i < View.ViewFrustum.Planes.Num(); i++) { PassParameters->ViewFrustumConvexHull[i] = FVector4(View.ViewFrustum.Planes[i], View.ViewFrustum.Planes[i].W); } PassParameters->ObjectBoundingGeometryIndexCount = StencilingGeometry::GLowPolyStencilSphereIndexBuffer.GetIndexCount(); PassParameters->AOObjectMaxDistance = Parameters.ObjectMaxOcclusionDistance; PassParameters->AOMaxViewDistance = GetMaxAOViewDistance(); auto ComputeShader = View.ShaderMap->GetShader(); const int32 GroupSize = FMath::DivideAndRoundUp(NumObjectsInBuffer, UpdateObjectsGroupSize); FComputeShaderUtils::AddPass( GraphBuilder, RDG_EVENT_NAME("ObjectFrustumCulling"), ComputeShader, PassParameters, FIntVector(GroupSize, 1, 1)); } } /** */ class FBuildTileConesCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FBuildTileConesCS); public: BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, RWTileConeAxisAndCos) SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, RWTileConeDepthRanges) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DistanceFieldNormalTexture) SHADER_PARAMETER_SAMPLER(SamplerState, DistanceFieldNormalSampler) END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment); OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), GDistanceFieldAOTileSizeX); OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), GDistanceFieldAOTileSizeY); OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor); // To reduce shader compile time of compute shaders with shared memory, doesn't have an impact on generated code with current compiler (June 2010 DX SDK) OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization); } FBuildTileConesCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { BindForLegacyShaderParameters(this, Initializer.PermutationId, Initializer.ParameterMap, false); AOParameters.Bind(Initializer.ParameterMap); NumGroups.Bind(Initializer.ParameterMap, TEXT("NumGroups")); ViewDimensionsParameter.Bind(Initializer.ParameterMap, TEXT("ViewDimensions")); } FBuildTileConesCS() { } void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, FScene* Scene, FVector2D NumGroupsValue, const FDistanceFieldAOParameters& Parameters) { FRHIComputeShader* ShaderRHI = RHICmdList.GetBoundComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); SetShaderValue(RHICmdList, ShaderRHI, ViewDimensionsParameter, View.ViewRect); SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue); } private: LAYOUT_FIELD(FAOParameters, AOParameters); LAYOUT_FIELD(FShaderParameter, ViewDimensionsParameter); LAYOUT_FIELD(FShaderParameter, NumGroups); }; IMPLEMENT_GLOBAL_SHADER(FBuildTileConesCS, "/Engine/Private/DistanceFieldObjectCulling.usf", "BuildTileConesMain", SF_Compute); /** */ class FObjectCullVS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FObjectCullVS); public: BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldCulledObjectBufferParameters, DistanceFieldCulledObjectBuffers) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldAtlasParameters, DistanceFieldAtlas) END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform); } FObjectCullVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer): FGlobalShader(Initializer) { BindForLegacyShaderParameters(this, Initializer.PermutationId, Initializer.ParameterMap, false); AOParameters.Bind(Initializer.ParameterMap); ConservativeRadiusScale.Bind(Initializer.ParameterMap, TEXT("ConservativeRadiusScale")); } FObjectCullVS() {} void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FDistanceFieldAOParameters& Parameters) { FRHIVertexShader* ShaderRHI = RHICmdList.GetBoundVertexShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); const int32 NumRings = StencilingGeometry::GLowPolyStencilSphereVertexBuffer.GetNumRings(); const float RadiansPerRingSegment = PI / (float)NumRings; // Boost the effective radius so that the edges of the sphere approximation lie on the sphere, instead of the vertices const float ConservativeRadiusScaleValue = 1.0f / FMath::Cos(RadiansPerRingSegment); SetShaderValue(RHICmdList, ShaderRHI, ConservativeRadiusScale, ConservativeRadiusScaleValue); } private: LAYOUT_FIELD(FAOParameters, AOParameters); LAYOUT_FIELD(FShaderParameter, ConservativeRadiusScale); }; IMPLEMENT_GLOBAL_SHADER(FObjectCullVS, "/Engine/Private/DistanceFieldObjectCulling.usf", "ObjectCullVS", SF_Vertex); class FObjectCullPS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FObjectCullPS); public: BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FTileIntersectionParameters, TileIntersectionParameters) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldCulledObjectBufferParameters, DistanceFieldCulledObjectBuffers) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldAtlasParameters, DistanceFieldAtlas) END_SHADER_PARAMETER_STRUCT() class FCountingPass : SHADER_PERMUTATION_BOOL("SCATTER_CULLING_COUNT_PASS"); using FPermutationDomain = TShaderPermutationDomain; static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); TileIntersectionModifyCompilationEnvironment(Parameters.Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor); } /** Default constructor. */ FObjectCullPS() {} /** Initialization constructor. */ FObjectCullPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { BindForLegacyShaderParameters(this, Initializer.PermutationId, Initializer.ParameterMap, false); AOParameters.Bind(Initializer.ParameterMap); NumGroups.Bind(Initializer.ParameterMap, TEXT("NumGroups")); } void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FVector2D NumGroupsValue, const FDistanceFieldAOParameters& Parameters) { FRHIPixelShader* ShaderRHI = RHICmdList.GetBoundPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue); } private: LAYOUT_FIELD(FAOParameters, AOParameters); LAYOUT_FIELD(FShaderParameter, NumGroups); }; IMPLEMENT_GLOBAL_SHADER(FObjectCullPS, "/Engine/Private/DistanceFieldObjectCulling.usf", "ObjectCullPS", SF_Pixel); BEGIN_SHADER_PARAMETER_STRUCT(FObjectCullParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FObjectCullVS::FParameters, VS) SHADER_PARAMETER_STRUCT_INCLUDE(FObjectCullPS::FParameters, PS) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures) RDG_BUFFER_ACCESS(ObjectIndirectArguments, ERHIAccess::IndirectArgs) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() const uint32 ComputeStartOffsetGroupSize = 64; /** */ class FComputeCulledTilesStartOffsetCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FComputeCulledTilesStartOffsetCS); SHADER_USE_PARAMETER_STRUCT(FComputeCulledTilesStartOffsetCS, FGlobalShader); public: BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View) SHADER_PARAMETER_STRUCT_INCLUDE(FTileIntersectionParameters, TileIntersectionParameters) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldCulledObjectBufferParameters, DistanceFieldCulledObjectBuffers) SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldAtlasParameters, DistanceFieldAtlas) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures) END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment); TileIntersectionModifyCompilationEnvironment(Parameters.Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("COMPUTE_START_OFFSET_GROUP_SIZE"), ComputeStartOffsetGroupSize); } }; IMPLEMENT_GLOBAL_SHADER(FComputeCulledTilesStartOffsetCS, "/Engine/Private/DistanceFieldObjectCulling.usf", "ComputeCulledTilesStartOffsetCS", SF_Compute); void ScatterTilesToObjects( FRDGBuilder& GraphBuilder, bool bCountingPass, const FViewInfo& View, const FDistanceFieldSceneData& DistanceFieldSceneData, FIntPoint TileListGroupSize, const FDistanceFieldAOParameters& Parameters, FRDGBufferRef ObjectIndirectArguments, const FDistanceFieldCulledObjectBufferParameters& CulledObjectBufferParameters, const FTileIntersectionParameters& TileIntersectionParameters, TRDGUniformBufferRef SceneTexturesUniformBuffer) { FObjectCullPS::FPermutationDomain PermutationVector; PermutationVector.Set(bCountingPass); auto VertexShader = View.ShaderMap->GetShader(); auto PixelShader = View.ShaderMap->GetShader(PermutationVector); auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->VS.DistanceFieldCulledObjectBuffers = CulledObjectBufferParameters; PassParameters->VS.DistanceFieldAtlas = DistanceField::SetupAtlasParameters(DistanceFieldSceneData); PassParameters->PS.TileIntersectionParameters = TileIntersectionParameters; PassParameters->PS.DistanceFieldCulledObjectBuffers = CulledObjectBufferParameters; PassParameters->PS.DistanceFieldAtlas = DistanceField::SetupAtlasParameters(DistanceFieldSceneData); PassParameters->SceneTextures = SceneTexturesUniformBuffer; PassParameters->ObjectIndirectArguments = ObjectIndirectArguments; if (GRHIRequiresRenderTargetForPixelShaderUAVs) { FRDGTextureDesc DummyDesc = FRDGTextureDesc::Create2D(TileListGroupSize, PF_B8G8R8A8, FClearValueBinding::Black, TexCreate_RenderTargetable); PassParameters->RenderTargets[0] = FRenderTargetBinding(GraphBuilder.CreateTexture(DummyDesc, TEXT("Dummy")), ERenderTargetLoadAction::ENoAction); } ClearUnusedGraphResources(VertexShader, &PassParameters->VS); ClearUnusedGraphResources(PixelShader, &PassParameters->PS); GraphBuilder.AddPass( bCountingPass ? RDG_EVENT_NAME("CountTileObjectIntersections") : RDG_EVENT_NAME("CullTilesToObjects"), PassParameters, ERDGPassFlags::Raster, [PassParameters, VertexShader, PixelShader, &View, TileListGroupSize, Parameters, ObjectIndirectArguments](FRHICommandListImmediate& RHICmdList) { FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); RHICmdList.SetViewport(0, 0, 0.0f, TileListGroupSize.X, TileListGroupSize.Y, 1.0f); // Render backfaces since camera may intersect GraphicsPSOInit.RasterizerState = View.bReverseCulling ? TStaticRasterizerState::GetRHI() : TStaticRasterizerState::GetRHI(); GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); GraphicsPSOInit.PrimitiveType = PT_TriangleList; GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader(); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); VertexShader->SetParameters(RHICmdList, View, Parameters); PixelShader->SetParameters(RHICmdList, View, FVector2D(TileListGroupSize.X, TileListGroupSize.Y), Parameters); SetShaderParameters(RHICmdList, VertexShader, VertexShader.GetVertexShader(), PassParameters->VS); SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), PassParameters->PS); RHICmdList.SetStreamSource(0, StencilingGeometry::GLowPolyStencilSphereVertexBuffer.VertexBufferRHI, 0); RHICmdList.DrawIndexedPrimitiveIndirect( StencilingGeometry::GLowPolyStencilSphereIndexBuffer.IndexBufferRHI, ObjectIndirectArguments->GetIndirectRHICallBuffer(), 0); }); } FIntPoint GetTileListGroupSizeForView(const FViewInfo& View) { return FIntPoint( FMath::DivideAndRoundUp(FMath::Max(View.ViewRect.Size().X / GAODownsampleFactor, 1), GDistanceFieldAOTileSizeX), FMath::DivideAndRoundUp(FMath::Max(View.ViewRect.Size().Y / GAODownsampleFactor, 1), GDistanceFieldAOTileSizeY)); } void BuildTileObjectLists( FRDGBuilder& GraphBuilder, FScene* Scene, TArray& Views, FRDGBufferRef ObjectIndirectArguments, const FDistanceFieldCulledObjectBufferParameters& CulledObjectBufferParameters, FTileIntersectionParameters TileIntersectionParameters, FRDGTextureRef DistanceFieldNormal, const FDistanceFieldAOParameters& Parameters) { ensure(GAOScatterTileCulling); RDG_EVENT_SCOPE(GraphBuilder, "BuildTileList"); TRDGUniformBufferRef SceneTexturesUniformBuffer = CreateSceneTextureUniformBuffer(GraphBuilder, Scene->GetFeatureLevel()); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { const FViewInfo& View = Views[ViewIndex]; RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); const FIntPoint TileListGroupSize = GetTileListGroupSizeForView(View); { auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->RWTileConeAxisAndCos = TileIntersectionParameters.RWTileConeAxisAndCos; PassParameters->RWTileConeDepthRanges = TileIntersectionParameters.RWTileConeDepthRanges; PassParameters->SceneTextures = SceneTexturesUniformBuffer; PassParameters->DistanceFieldNormalTexture = DistanceFieldNormal; PassParameters->DistanceFieldNormalSampler = TStaticSamplerState::GetRHI(); auto ComputeShader = View.ShaderMap->GetShader(); ClearUnusedGraphResources(ComputeShader, PassParameters); GraphBuilder.AddPass( RDG_EVENT_NAME("BuildTileCones"), PassParameters, ERDGPassFlags::Compute, [PassParameters, ComputeShader, Scene, &View, TileListGroupSize, Parameters](FRHICommandListImmediate& RHICmdList) { RHICmdList.SetComputeShader(ComputeShader.GetComputeShader()); ComputeShader->SetParameters(RHICmdList, View, Scene, FVector2D(TileListGroupSize.X, TileListGroupSize.Y), Parameters); SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetComputeShader(), *PassParameters); DispatchComputeShader(RHICmdList, ComputeShader.GetShader(), TileListGroupSize.X, TileListGroupSize.Y, 1); UnsetShaderUAVs(RHICmdList, ComputeShader, ComputeShader.GetComputeShader()); }); } // Start at 0 tiles per object AddClearUAVPass(GraphBuilder, TileIntersectionParameters.RWNumCulledTilesArray, 0); // Rasterize object bounding shapes and intersect with screen tiles to compute how many tiles intersect each object ScatterTilesToObjects(GraphBuilder, true, View, Scene->DistanceFieldSceneData, TileListGroupSize, Parameters, ObjectIndirectArguments, CulledObjectBufferParameters, TileIntersectionParameters, SceneTexturesUniformBuffer); // Start at 0 threadgroups AddClearUAVPass(GraphBuilder, TileIntersectionParameters.RWObjectTilesIndirectArguments, 0); { auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->View = View.ViewUniformBuffer; PassParameters->TileIntersectionParameters = TileIntersectionParameters; PassParameters->DistanceFieldCulledObjectBuffers = CulledObjectBufferParameters; PassParameters->DistanceFieldAtlas = DistanceField::SetupAtlasParameters(Scene->DistanceFieldSceneData); PassParameters->SceneTextures = SceneTexturesUniformBuffer; auto ComputeShader = View.ShaderMap->GetShader(); const int32 GroupSize = FMath::DivideAndRoundUp(Scene->DistanceFieldSceneData.NumObjectsInBuffer, ComputeStartOffsetGroupSize); FComputeShaderUtils::AddPass( GraphBuilder, RDG_EVENT_NAME("ComputeStartOffsets"), ComputeShader, PassParameters, FIntVector(GroupSize, 1, 1)); } // Start at 0 tiles per object AddClearUAVPass(GraphBuilder, TileIntersectionParameters.RWNumCulledTilesArray, 0); // Rasterize object bounding shapes and intersect with screen tiles, and write out intersecting tile indices for the cone tracing pass ScatterTilesToObjects(GraphBuilder, false, View, Scene->DistanceFieldSceneData, TileListGroupSize, Parameters, ObjectIndirectArguments, CulledObjectBufferParameters, TileIntersectionParameters, SceneTexturesUniformBuffer); } }