--- title: Untitled date: 2025-02-11 11:30:34 excerpt: tags: rating: ⭐ --- # FSortedLightSetSceneInfo 有序的光源集合相关定义: ```c++ /** Data for a simple dynamic light. */ class FSimpleLightEntry { public: FVector3f Color; float Radius; float Exponent; float InverseExposureBlend = 0.0f; float VolumetricScatteringIntensity; bool bAffectTranslucency; }; struct FSortedLightSceneInfo { union { struct { // Note: the order of these members controls the light sort order! // Currently bHandledByLumen is the MSB and LightType is LSB /** The type of light. */ uint32 LightType : LightType_NumBits; /** Whether the light has a texture profile. */ uint32 bTextureProfile : 1; /** Whether the light uses a light function. */ uint32 bLightFunction : 1; /** Whether the light uses lighting channels. */ uint32 bUsesLightingChannels : 1; /** Whether the light casts shadows. */ uint32 bShadowed : 1; /** Whether the light is NOT a simple light - they always support tiled/clustered but may want to be selected separately. */ uint32 bIsNotSimpleLight : 1; /* We want to sort the lights that write into the packed shadow mask (when enabled) to the front of the list so we don't waste slots in the packed shadow mask. */ uint32 bDoesNotWriteIntoPackedShadowMask : 1; /** * True if the light doesn't support clustered deferred, logic is inverted so that lights that DO support clustered deferred will sort first in list * Super-set of lights supporting tiled, so the tiled lights will end up in the first part of this range. */ uint32 bClusteredDeferredNotSupported : 1; /** Whether the light should be handled by Lumen's Final Gather, these will be sorted to the end so they can be skipped */ uint32 bHandledByLumen : 1; } Fields; /** Sort key bits packed into an integer. */ int32 Packed; } SortKey; const FLightSceneInfo* LightSceneInfo; int32 SimpleLightIndex; /** Initialization constructor. */ explicit FSortedLightSceneInfo(const FLightSceneInfo* InLightSceneInfo) : LightSceneInfo(InLightSceneInfo), SimpleLightIndex(-1) { SortKey.Packed = 0; SortKey.Fields.bIsNotSimpleLight = 1; } explicit FSortedLightSceneInfo(int32 InSimpleLightIndex) : LightSceneInfo(nullptr), SimpleLightIndex(InSimpleLightIndex) { SortKey.Packed = 0; SortKey.Fields.bIsNotSimpleLight = 0; }}; /** * Stores info about sorted lights and ranges. * The sort-key in FSortedLightSceneInfo gives rise to the following order: * [SimpleLights,Clustered,UnbatchedLights,LumenLights] * Note that some shadowed lights can be included in the clustered pass when virtual shadow maps and one pass projection are used. */struct FSortedLightSetSceneInfo { int32 SimpleLightsEnd; int32 ClusteredSupportedEnd; /** First light with shadow map or */ int32 UnbatchedLightStart; int32 LumenLightStart; FSimpleLightArray SimpleLights; TArray SortedLights; }; ``` ## 开始获取有序光源集合 UE的光源分配由`FDeferredShadingSceneRenderer::Render`内的`bComputeLightGrid`变量决定的,bComputeLightGrid的赋值逻辑如下: ```c++ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { ... bool bComputeLightGrid = false; if (RendererOutput == ERendererOutput::FinalSceneColor) { if (bUseVirtualTexturing) { // Note, should happen after the GPU-Scene update to ensure rendering to runtime virtual textures is using the correctly updated scene FVirtualTextureSystem::Get().EndUpdate(GraphBuilder, MoveTemp(VirtualTextureUpdater), FeatureLevel); } #if RHI_RAYTRACING GatherRayTracingWorldInstancesForView(GraphBuilder, ReferenceView, RayTracingScene, InitViewTaskDatas.RayTracingRelevantPrimitives); #endif // RHI_RAYTRACING bool bAnyLumenEnabled = false; { if (bUseGBuffer) { bComputeLightGrid = bRenderDeferredLighting; } else { bComputeLightGrid = ViewFamily.EngineShowFlags.Lighting; } for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { FViewInfo& View = Views[ViewIndex]; bAnyLumenEnabled = bAnyLumenEnabled || GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen || GetViewPipelineState(View).ReflectionsMethod == EReflectionsMethod::Lumen; } bComputeLightGrid |= ( ShouldRenderVolumetricFog() || VolumetricCloudWantsToSampleLocalLights(Scene, ViewFamily.EngineShowFlags) || ViewFamily.ViewMode != VMI_Lit || bAnyLumenEnabled || VirtualShadowMapArray.IsEnabled() || ShouldVisualizeLightGrid()); } } ... } ``` 获取有序的光源集合 ```c++ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { ... // 有序的光源集合. FSortedLightSetSceneInfo& SortedLightSet = *GraphBuilder.AllocObject(); { RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, SortLights); RDG_GPU_STAT_SCOPE(GraphBuilder, SortLights); ComputeLightGridOutput = GatherLightsAndComputeLightGrid(GraphBuilder, bComputeLightGrid, SortedLightSet); } ... } ``` PS. 简单光源都可以被分块或分簇渲染,但对于非简单光源,只有满足以下条件的光源才可被分块或分簇渲染: - 没有使用光源的附加特性(TextureProfile、LightFunction、LightingChannel)。 - 没有开启阴影。 - 非平行光或矩形光。 另外,是否支持分块渲染,还需要光源场景代理的`IsTiledDeferredLightingSupported`返回true,长度为0的点光源才支持分块渲染。 ## GatherLightsAndComputeLightGrid ```c++ FComputeLightGridOutput FDeferredShadingSceneRenderer::GatherLightsAndComputeLightGrid(FRDGBuilder& GraphBuilder, bool bNeedLightGrid, FSortedLightSetSceneInfo& SortedLightSet) { SCOPED_NAMED_EVENT(GatherLightsAndComputeLightGrid, FColor::Emerald); FComputeLightGridOutput Result = {}; bool bShadowedLightsInClustered = ShouldUseClusteredDeferredShading() && CVarVirtualShadowOnePassProjection.GetValueOnRenderThread() && VirtualShadowMapArray.IsEnabled(); const bool bUseLumenDirectLighting = ShouldRenderLumenDirectLighting(Scene, Views[0]); GatherAndSortLights(SortedLightSet, bShadowedLightsInClustered, bUseLumenDirectLighting); if (!bNeedLightGrid) { SetDummyForwardLightUniformBufferOnViews(GraphBuilder, ShaderPlatform, Views); return Result; } bool bAnyViewUsesForwardLighting = false; bool bAnyViewUsesLumen = false; for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { const FViewInfo& View = Views[ViewIndex]; bAnyViewUsesForwardLighting |= View.bTranslucentSurfaceLighting || ShouldRenderVolumetricFog() || View.bHasSingleLayerWaterMaterial || VolumetricCloudWantsToSampleLocalLights(Scene, ViewFamily.EngineShowFlags) || ShouldVisualizeLightGrid(); bAnyViewUsesLumen |= GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen || GetViewPipelineState(View).ReflectionsMethod == EReflectionsMethod::Lumen; } const bool bCullLightsToGrid = GLightCullingQuality && (IsForwardShadingEnabled(ShaderPlatform) || bAnyViewUsesForwardLighting || IsRayTracingEnabled() || ShouldUseClusteredDeferredShading() || bAnyViewUsesLumen || ViewFamily.EngineShowFlags.VisualizeMeshDistanceFields || VirtualShadowMapArray.IsEnabled()); // Store this flag if lights are injected in the grids, check with 'AreLightsInLightGrid()' bAreLightsInLightGrid = bCullLightsToGrid; Result = ComputeLightGrid(GraphBuilder, bCullLightsToGrid, SortedLightSet); return Result; } ``` - GatherAndSortLights:收集与排序当前场景中所有的可见光源(当前View)。 - ComputeLightGrid:是在锥体空间(frustum space)裁剪局部光源和反射探针到3D格子中,构建每个视图相关的光源列表和格子。 # RenderLights() -> RenderLight() ## InternalRenderLight()