Lighting Architecture — Clustered Deferred, Froxels & MegaLights光照架构 — 集群延迟光照、Froxel 与 MegaLights
Light Evaluation Overview — The Three-Tier System光照计算概览 — 三层系统
UE5's deferred renderer evaluates local lights (point, spot, rect) in a layered architecture that separates lights by type, count, and quality requirement. Understanding this is essential for performance work — "too many lights" is almost always a problem in a specific tier, not globally.
UE5 的延迟渲染器以分层架构计算局部灯光(点光、聚光、矩形光), 按类型、数量和质量需求分离灯光。理解这一点对性能工作至关重要—— "灯光太多"几乎总是某个特定层级的问题,而非全局性问题。
Light Classification — CPU Culling Before GPU灯光分类 — GPU 前的 CPU 剔除
Before any GPU work happens, the CPU culls lights against the view frustum and sorts them by type.
This happens in FDeferredShadingSceneRenderer::GatherLightsAndComputeVisibility().
Each visible light is placed into one of several buckets:
在任何 GPU 工作发生之前,CPU 针对视图锥体剔除灯光并按类型排序。
这在 FDeferredShadingSceneRenderer::GatherLightsAndComputeVisibility() 中发生。
每个可见灯光被放入以下几个桶之一:
| Bucket桶 | Content内容 | Rendered via渲染方式 |
|---|---|---|
| DirectionalLights | Up to 4 directional lights, Skylight最多 4 个方向光、天空光 | Full-screen quad per light每个灯光全屏四边形 |
| SimpleLights | CPU particle lights (no shadow)CPU 粒子灯光(无阴影) | Injected into light grid, clustered pass注入灯光网格,集群通道 |
| ClusteredLights | All local lights: point/spot/rect所有局部灯光:点/聚/矩形 | Clustered deferred pass via froxel grid通过 Froxel 网格的集群延迟通道 |
| ShadowedLights | Local lights with shadow maps带阴影贴图的局部灯光 | Shadow rendered first, then combined in clustered pass先渲染阴影,再在集群通道中合并 |
// FSceneRenderer::PrepareViewStateForCapture (simplified concept) // Actual: GatherLightsAndComputeVisibility in DeferredShadingRenderer.cpp for (auto& LightProxy : Scene->Lights) { if (!LightProxy.AffectsBounds(ViewFrustum)) continue; // frustum cull if (LightProxy.LightType == LightType_Directional) DirectionalLights.Add(LightProxy); else if (LightProxy.ShouldRenderWithMegaLights()) MegaLightsPool.Add(LightProxy); // UE 5.5+ else ClusteredLights.Add(LightProxy); // goes into froxel grid }
Light Grid — Frustum Voxels (Froxels)灯光网格 — 视锥体体素(Froxel)
The light grid is the acceleration structure that prevents the GPU from evaluating every light for every pixel. The camera frustum is divided into a 3D grid of froxels (frustum voxels). For each cell, a compute shader determines which lights overlap it. During shading, each pixel only iterates the lights in its froxel — not all lights in the scene.
灯光网格是防止 GPU 对每个像素计算每个灯光的加速结构。 相机视锥体被划分为Froxel(视锥体体素)的 3D 网格。 对于每个单元格,计算 Shader 确定哪些灯光与之重叠。 着色时,每个像素只迭代其 Froxel 中的灯光——而不是场景中的所有灯光。
// LightGridInjection.cpp — ComputeLightGrid() overview // Pass 1: Clear the light grid (per-froxel count buffer) AddClearUAVPass(GraphBuilder, LightGridBuffer, 0); // Pass 2: CullLightsCS — determine which lights touch which froxels // Each thread = one froxel. Tests each light's AABB/sphere vs. froxel. TShaderMapRef<FCullLightsCS> CullShader(...); GraphBuilder.AddPass(RDG_EVENT_NAME("LightGridCull"), Params, ERDGPassFlags::Compute, [=](auto& RHICmdList) { FComputeShaderUtils::Dispatch(RHICmdList, CullShader, *Params, FIntVector(GridX, GridY, GridZ)); // one thread per froxel }); // Pass 3: Build light lists — scatter light indices into froxel list buffer TShaderMapRef<FBuildLightListCS> BuildShader(...); // Output: LightGrid[froxelIdx] = (offset, count) into LightList[]
Clustered Deferred Shading Pass集群延迟着色通道
Once the light grid is built, the clustered deferred shading pass iterates every pixel of the GBuffer and applies all lights in that pixel's froxel. This is a single compute dispatch that replaces the old approach of rendering a sphere/cone mesh for every light.
一旦灯光网格建立,集群延迟着色通道遍历 GBuffer 的每个像素, 并应用该像素 Froxel 中的所有灯光。这是一次单一的计算调度, 取代了以前为每个灯光渲染球体/锥体网格的旧方法。
// ClusteredDeferredShadingPass.cpp — RenderClusteredDeferredLighting() void FDeferredShadingSceneRenderer::RenderClusteredDeferredLighting( FRDGBuilder& GraphBuilder, FSceneTextures& SceneTextures, FRDGBufferRef LightGridBuffer, FRDGBufferRef LightList) { auto* PassParams = GraphBuilder.AllocParameters<FClusteredShadingCS::FParameters>(); PassParams->GBufferA = SceneTextures.GBufferA; // normal + shading model PassParams->GBufferB = SceneTextures.GBufferB; // roughness, metallic PassParams->SceneDepth = SceneTextures.Depth; PassParams->LightGrid = GraphBuilder.CreateSRV(LightGridBuffer); PassParams->LightDataBuffer= GraphBuilder.CreateSRV(LightDataBuffer); PassParams->OutDiffuseColor= GraphBuilder.CreateUAV(SceneColor); // One thread per pixel, grouped 8×8 FComputeShaderUtils::AddFullscreenPass( GraphBuilder, ShaderMap, RDG_EVENT_NAME("ClusteredDeferredLighting"), Shader, PassParams, FIntVector(FMath::DivideAndRoundUp(Width, 8), FMath::DivideAndRoundUp(Height, 8), 1)); } // Inside the shader (ClusteredDeferredShadingCommon.usf): // uint FroxelIdx = ComputeFroxelIndex(PixelPos, Depth); // uint LightOffset, LightCount = LightGrid[FroxelIdx]; // for (uint i = 0; i < LightCount; ++i) { // FDeferredLightData Light = LightDataBuffer[LightList[LightOffset + i]]; // Lighting += EvaluateLight(GBuffer, Light, ShadowMap); // }
MegaLights — GPU Ray-Traced Many-Light System (UE 5.5+)MegaLights — GPU 光追多灯光系统(UE 5.5+)
MegaLights is a new system introduced in UE 5.5 that extends the lighting architecture to support hundreds or thousands of shadow-casting local lights in a scene — something previously impossible without unacceptable frame time. It uses stochastic sampling: instead of evaluating all N lights per pixel, each pixel traces 1 ray toward a probabilistically sampled light, and the result is denoised over multiple frames.
MegaLights 是 UE 5.5 中引入的新系统,将光照架构扩展为支持场景中 数百甚至数千个投影局部灯光——这在之前以可接受的帧时间是不可能实现的。 它使用随机采样:不是对每个像素计算所有 N 个灯光, 而是每个像素向一个概率采样的灯光追踪 1 条光线,结果在多帧上降噪。
MegaLights integrates with Virtual Shadow Maps: each MegaLight automatically gets a VSM page allocation so that shadows are correct and cached. The key enabling technology is that VSM already caches static geometry shadows, so MegaLights only needs to re-evaluate light pages when something moves.
MegaLights 与虚拟阴影贴图集成:每个 MegaLight 自动获得 VSM 页面分配以使阴影正确并被缓存。 关键使能技术是 VSM 已经缓存了静态几何体阴影,所以 MegaLights 只需在有物体移动时重新计算灯光页面。
// Enabling MegaLights (Project Settings or per-light): // Project Settings → Rendering → MegaLights r.MegaLights=1 // Enable MegaLights globally r.MegaLights.ShadowsEnabled=1 // Enable shadow casting for MegaLights r.MegaLights.SamplesPerPixel=1 // Rays per pixel (1 = default, 2 = higher quality) r.MegaLights.UseHardwareRayTracing=1 // Use HWRT for shadow rays (more accurate) // Per-light in Blueprint/details panel: // PointLight → Details → "Mega Lights" → Enable for this light // Only lights marked as MegaLights participate in the many-light pool // stat MegaLights — shows light pool size, rays/frame, denoiser cost
Light Functions & IES Profiles灯光函数与 IES 配置文件
Light Functions let you mask or modulate a light's intensity using a Material — think of a stained-glass window casting colored shadows, a flickering fire light, or a flashlight with a non-circular beam. IES Profiles are measured real-world light distribution curves that define how light falls off in different directions.
灯光函数让你用材质遮罩或调制灯光强度——想象彩色玻璃窗投射的彩色阴影、 闪烁的火焰灯光,或具有非圆形光束的手电筒。 IES 配置文件是测量的真实世界灯光分布曲线,定义灯光在不同方向上的衰减方式。
Light Function Atlas (UE 5.2+)灯光函数图集(UE 5.2+)
Prior to the Light Function Atlas, each light function material required a separate full-screen render pass.
With the atlas system (LightFunctionAtlas.h/.cpp), all light functions are rendered into a shared
2D texture atlas, and the clustered shading pass reads them in a single indirection. This enables dozens
of lights with unique light functions at nearly zero per-light overhead.
在灯光函数图集之前,每个灯光函数材质需要单独的全屏渲染通道。
有了图集系统(LightFunctionAtlas.h/.cpp),所有灯光函数被渲染到共享的 2D 纹理图集中,
集群着色通道通过单次间接访问读取它们。这使得具有独特灯光函数的数十个灯光的每灯光开销几乎为零。
// LightFunctionRendering.cpp — RenderLightFunctionForMaterial() // Each unique light function material → rendered into an atlas tile // Atlas tile UV is stored in the light data buffer // IES profile → stored as a 1D texture (luminous intensity vs angle) // IESTextureManager.cpp: manages the IES texture array (up to 64 profiles) // Clustered shading reads: LightData.IESTextureIndex → sample IES texture // Usage in Blueprint/Editor: // PointLight → Details → Light → Light Function Material (any Material) // PointLight → Details → Light → IES Texture (import .ies file) // Console: r.LightFunctionAtlas=1 (default enabled in 5.2+)
Forward Light Loop (Desktop & Mobile)前向灯光循环(桌面端与移动端)
For forward-rendered objects (translucent materials, forward renderer on mobile), the light loop works differently. Instead of a deferred pass, the surface shader itself loops over lights. UE5 uses the same froxel grid to supply lights to the forward loop, so complexity is still O(lights-in-froxel) not O(all-lights).
对于前向渲染的对象(半透明材质、移动端前向渲染器),灯光循环的工作方式不同。 不是延迟通道,而是表面 Shader 本身循环遍历灯光。 UE5 使用相同的 Froxel 网格为前向循环提供灯光, 因此复杂度仍然是 O(froxel 中的灯光数量),而不是 O(所有灯光)。
// ForwardLightingCommon.ush — Desktop forward lighting loop float3 GetForwardDirectLighting(FMaterialPixelParameters Params, ...) { float3 Color = 0; // Get froxel index for this pixel uint FroxelIndex = ComputeFroxelIndex(Params.SvPosition, Params.ScreenPosition.w); // Read light count and offset from the grid uint LightDataOffset, LocalLightCount; GetLocalLightCountAndOffset(FroxelIndex, LightDataOffset, LocalLightCount); // Evaluate each local light in this froxel LOOP for (uint i = 0; i < LocalLightCount && i < MAX_LIGHTS_PER_PIXEL; ++i) { FDeferredLightData LightData = LoadLocalLightData(LightDataOffset + i); Color += EvaluateLocalLight(Params, LightData); } // Also evaluate directional lights (always applied) Color += EvaluateDirectionalLight(Params, DirectionalLightData); return Color; }
Stochastic Lighting — Dynamic Indirect Many-Light随机光照 — 动态间接多灯光
Stochastic Lighting (StochasticLighting/) is a complementary system to MegaLights
focused on indirect many-light illumination. Where Lumen provides physically-based GI from surfaces,
Stochastic Lighting uses a ReSTIR-based approach to evaluate indirect illumination from a large pool of
dynamic lights, including emissive materials. This handles scenarios like a scene lit mostly by Niagara
particle emitters or dense light grids.
随机光照(StochasticLighting/)是 MegaLights 的补充系统,
专注于间接多灯光照明。Lumen 从表面提供基于物理的 GI,
而随机光照使用基于 ReSTIR 的方法,从大量动态灯光池(包括自发光材质)计算间接照明。
这处理了主要由 Niagara 粒子发射器或密集灯光网格照亮的场景。
Performance Tuning性能调优
| CVar | Effect效果 |
|---|---|
| r.TiledDeferredShading=1 | Enable tiled/clustered deferred (should always be 1)启用分块/集群延迟(应始终为 1) |
| r.TiledDeferredShading.MinimumCount | Min lights to switch from per-light pass to clustered (default 80)从逐灯光通道切换到集群的最小灯光数(默认 80) |
| r.LightFunctionAtlas | Use light function atlas (1 = enabled, reduces render passes)使用灯光函数图集(1 = 启用,减少渲染通道数) |
| r.MegaLights | Enable MegaLights for many shadow-casting lights为大量投影灯光启用 MegaLights |
| r.MegaLights.SamplesPerPixel | 1 = fastest, 2 = better quality but 2× cost1 = 最快,2 = 质量更好但成本翻倍 |
| r.CapsuleShadows | Enable capsule contact shadows from skeletal meshes从骨骼网格启用胶囊体接触阴影 |
| showflag.LightGrid=1 | Visualize the froxel light grid in viewport在视口中可视化 Froxel 灯光网格 |
stat SceneRendering to identify whether the bottleneck is in LightGrid injection, the clustered shading pass, or shadow map rendering. Often the real bottleneck is shadow maps, not the shading math — consider using MegaLights + VSM caching for scenes with many shadow-casting lights.
实用技巧 — "为什么 100 个灯光让我的场景变慢?"使用 stat SceneRendering 识别瓶颈是在灯光网格注入、集群着色通道还是阴影贴图渲染中。通常真正的瓶颈是阴影贴图而不是着色数学——对于有很多投影灯光的场景,考虑使用 MegaLights + VSM 缓存。
Source Navigation源码导航
All paths relative to Engine/Source/Runtime/Renderer/Private/
所有路径相对于 Engine/Source/Runtime/Renderer/Private/
- LightGridInjection.cppFroxel grid construction: culling lights into froxel cellsFroxel 网格构建:将灯光剔除到 Froxel 单元格中
- Froxel/Froxel.h/.cppFroxel math, frustum voxel parameterizationFroxel 数学,视锥体体素参数化
- ClusteredDeferredShadingPass.cppMain clustered deferred dispatch: GBuffer → scene color主集群延迟调度:GBuffer → 场景颜色
- LightRendering.cppDirectional light full-screen passes, simple light batching方向光全屏通道,简单灯光批处理
- MegaLights/MegaLights.cppMegaLights orchestrator: light pool, ReSTIR sampling, denoisingMegaLights 协调器:灯光池、ReSTIR 采样、降噪
- MegaLights/MegaLightsRayTracing.cppHWRT shadow ray dispatches for MegaLightsMegaLights 的 HWRT 阴影光线调度
- LightFunctionRendering.cppLight function material rendering灯光函数材质渲染
- LightFunctionAtlas.h/.cppLight function atlas management (all functions into one atlas)灯光函数图集管理(所有函数合并到一个图集)
- IESTextureManager.h/.cppIES profile texture array, loading, index managementIES 配置文件纹理数组、加载、索引管理
- StochasticLighting/StochasticLighting.cppReSTIR-based dynamic indirect many-light illumination基于 ReSTIR 的动态间接多灯光照明