2025-02-11 12:27:00 +08:00
---
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< FSortedLightSceneInfo , SceneRenderingAllocator > 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< FSortedLightSetSceneInfo > ();
{
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, SortLights);
RDG_GPU_STAT_SCOPE(GraphBuilder, SortLights);
ComputeLightGridOutput = GatherLightsAndComputeLightGrid(GraphBuilder, bComputeLightGrid, SortedLightSet);
}
...
}
```
2025-02-11 15:54:25 +08:00
PS. 简单光源都可以被分块或分簇渲染,但对于非简单光源,只有满足以下条件的光源才可被分块或分簇渲染:
- 没有使用光源的附加特性( TextureProfile、LightFunction、LightingChannel) 。
- 没有开启阴影。
- 非平行光或矩形光。
另外,是否支持分块渲染,还需要光源场景代理的`IsTiledDeferredLightingSupported` 返回true, 长度为0的点光源才支持分块渲染。
## GatherLightsAndComputeLightGrid
2025-02-11 12:27:00 +08:00
```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;
}
2025-02-11 15:54:25 +08:00
```
- GatherAndSortLights: 收集与排序当前场景中所有的可见光源( 当前View) 。
- ComputeLightGrid: 是在锥体空间( frustum space) 裁剪局部光源和反射探针到3D格子中, 构建每个视图相关的光源列表和格子。
# RenderLights() -> RenderLight()
## InternalRenderLight()