UE5.8 Lumen 动态全局光照:让光线真正在场景里反弹起来
引子:烘焙室的噩梦
灯光师小美最怕周三下午。每次策划改完关卡布局,她都要重新烘焙 lightmap。一个小房间的灯光烘焙,快的二十分钟,慢的两小时。更崩溃的是,烘焙到 97% 时引擎报错,原因是某个 Static Mesh 的 UV2 重叠了。
「能不能不烘焙?」她问阿杰。
阿杰打开 Project Settings,把 Dynamic Global Illumination 从 None 改成 Lumen,重启编辑器。十分钟后,小美拖动一盏灯,墙上的反射光跟着实时变化。她愣了一下:「以后周三下午我能睡午觉了?」
这就是 Lumen 的魅力。它不是让画面更炫,而是把灯光调整从「小时级」压缩到「秒级」。
一、全局光照到底在算什么
要理解 Lumen,先要知道全局光照(Global Illumination,GI)在解决什么问题。
直接光照很简单:灯照到物体,物体被照亮。但现实世界里,光线会反弹。墙面反射的光会照亮角落,地板反射的光会给人物下巴补一层暖色。这些二次、三次、甚至无限次反弹的光,就是间接光照。
传统实时渲染很难算这个。老办法是烘焙 lightmap:提前离线计算每个静态表面的间接光,存成贴图。好处是运行时便宜,坏处是:
- 静态物体才能烘焙;
- 灯光位置一变就要重烘;
- 大场景烘焙时间指数增长;
- UV 出一点问题就满屏黑斑。
Lumen 的思路是:间接光也在运行时算。相机每动一帧,Lumen 就重新评估光线怎么反弹。
flowchart LR
A[直接光照] --> B[第一次反弹]
B --> C[第二次反弹]
C --> D[第三次反弹]
D --> E[...]
E --> F[最终图像]二、Lumen 的两大武器:Surface Cache 和 Ray Tracing
Lumen 不是单一算法,而是一套组合拳。它的核心可以拆成两部分:
2.1 Surface Cache
Lumen 不会直接对着无穷复杂的几何算光线。它先把场景表面的材质属性(颜色、法线、粗糙度、自发光)缓存到一组低分辨率贴图里,这些贴图叫 Surface Cache 或 Cards。每张 Card 对应一个表面区域,从多个方向捕获。
算间接光时,Lumen 主要对着这些 Card 打射线,而不是对着原始三角形。这大大降低了计算复杂度。
flowchart TD
A[场景几何] --> B[生成 Cards]
B --> C[捕获材质属性到 Surface Cache]
C --> D[从 Surface Cache 发射/接收光线]
D --> E[累加间接光照]2.2 Ray Tracing
有了 Surface Cache,还需要知道光线往哪走、碰到什么。Lumen 提供两种追踪方式:
- Software Ray Tracing:用 Mesh Distance Fields 和 Global Distance Fields 追踪。不需要 RTX 显卡,兼容性好;
- Hardware Ray Tracing:用 GPU 光追核心追踪真实三角形。质量更高,但需要硬件支持。
architecture-beta
group lumen[Lumen 管线]
service sc as Surface Cache Cards in lumen
service sw as Software Ray Tracing in lumen
service hw as Hardware Ray Tracing in lumen
service fg as Final Gather in lumen
service out as 图像输出
sc:T --> fg:L
sw:T --> fg:B
hw:T --> fg:R
fg:B --> out:TUE5.8 默认推荐 Hardware Ray Tracing,如果硬件不支持则回退到 Software。
三、Software Ray Tracing 的里子
Software Ray Tracing 是 Lumen 的兜底方案,理解它对排查问题很重要。
3.1 Distance Fields
Distance Field(距离场)是给每个静态网格离线生成的一个有符号距离场。简单来说,空间中的每个点都存储了它到最近表面的距离。正值在物体外,负值在物体内。
追踪光线时,Lumen 可以利用距离场快速判断射线是否靠近表面,从而大步前进。这比逐三角形相交快得多。
sequenceDiagram
participant R as 射线起点
participant D as Distance Field
participant H as 命中点
R->>D: 查询当前点距离
D-->>R: 返回安全距离
R->>R: 沿射线前进安全距离
loop 直到命中或超出范围
R->>D: 查询新位置距离
D-->>R: 返回更小距离
R->>R: 继续前进
end
R->>H: 到达表面附近3.2 Detail Tracing vs Global Tracing
Software Ray Tracing 有两种模式:
- Detail Tracing:前 2 米用每个网格自己的 Mesh Distance Field,远处用合并后的 Global Distance Field。精度高,但在 kitbash 场景里很贵;
- Global Tracing:全程用 Global Distance Field。快,但薄墙和细小物体容易漏光。
大多数项目用 Global Tracing 就够了。如果你的场景有很多薄墙、窗户、小遮挡物,Detail Tracing 会稳一些,但代价也高。
四、Hardware Ray Tracing 的优势与代价
Hardware Ray Tracing 直接对三角形求交,质量明显更好,尤其体现在:
- 镜面反射;
- 细小几何的遮挡;
- 毛发、植被等 distance field 表现差的物体。
但它的开销也很真实:
- 场景实例超过 10 万个时,构建和更新加速结构(BLAS/TLAS)的 CPU 成本会凸显;
- 需要 RTX 20 系 / RX 6000 系以上显卡;
- 移动平台基本不用想。
用公式描述两种路径的成本:
其中:
- 是每帧发射的射线数;
- 是距离场步进成本;
- 是启用 Detail Tracing 的射线比例;
- 是硬件光追加速结构更新成本。
当你的场景实例数 很大时, 会吃掉不少预算。这时候 Software Ray Tracing 反而更稳。
五、Lumen 的光照更新机制
Lumen 不是每帧都从零算所有东西的。它用了多层缓存和时域累积:
- Surface Cache 更新:每帧只更新变化了的 Card;
- Screen Probe Gather:在屏幕空间放置 probe,收集周围间接光;
- Final Gather:把 probe 结果插值到像素;
- Temporal Filter:多帧混合,减少噪点。
flowchart TD
A[光源/几何变化] --> B[更新 Surface Cache]
B --> C[Screen Probe 收集光线]
C --> D[Final Gather]
D --> E[Temporal Filter]
E --> F[输出 GI]这意味着 Lumen 对快速移动的光源或相机会有点延迟。你拖一盏灯,墙面反射可能要几帧才完全跟上。大多数场景下这没问题,但做快节奏闪烁灯效时要注意。
六、性能调优:从能用到能 ship
Lumen 默认设置是为高端硬件准备的。要 ship 到主机或中低端 PC,必须调。
6.1 关键控制台变量
[/Script/Engine.RendererSettings]
r.Lumen.ScreenProbeGather.DownsampleFactor=16
r.Lumen.ScreenProbeGather.TracingOctahedronResolution=2
r.Lumen.Reflections.DownsampleFactor=2
r.Lumen.Reflections.MaxRoughnessToTrace=0.4
r.LumenScene.SurfaceCache.MeshCardsMinSize=20DownsampleFactor:probe 密度,越大越稀疏越便宜;TracingOctahedronResolution:每个 probe 发射的射线数,越小越便宜;Reflections.DownsampleFactor:反射分辨率降采样;MaxRoughnessToTrace:粗糙度超过这个值就不追反射;MeshCardsMinSize:小于这个尺寸的物体不生成 Card。
6.2 场景层面的优化
- 限制重叠动态光源数量,一个表面别超过 4 盏;
- 小道具可以关闭 Generate Mesh Distance Fields;
- 自发光面积别太大,不然 Lumen 要从很多方向追;
- 薄墙和窗户的 distance field 要仔细检查,漏光大户。
6.3 一个真实案例
小美团队做一个地下城关卡,开启 Lumen 后帧率从 62 掉到 38。Profiler 显示 Final Gather 占了 4.2ms。她把 TracingOctahedronResolution 从 4 降到 2,DownsampleFactor 从 8 提到 16,帧率回到 58。画面暗部噪点稍微多了点,但 Temporal Filter 很快把它压下去。
七、漏光与常见 bug
Lumen 最常见的投诉是「墙角漏光」。原因通常有几个:
7.1 Distance Field 分辨率不够
薄墙在 distance field 里被表示成一层雾,光线从「雾」里穿过去。解决:
- 提高 Distance Field Resolution Scale;
- 把薄墙做厚一点;
- 用 Hardware Ray Tracing。
7.2 Lumen Scene View Distance 不够
默认 Software Ray Tracing 只覆盖相机周围 200 米。超出这个范围只有 Screen Traces,容易漏。可以提高到 800 米,但 GPU 成本也涨。
7.3 自发光物体没进 Lumen Scene
如果一个自发光物体太小或被遮挡,Lumen Scene 没把它捕获进去,它的间接光就会缺失。可以调大 Lumen Scene Detail 让它包含更小的物体。
7.4 快速移动相机
相机跑太快,Lumen Scene 更新跟不上,会出现间接光「弹入」。开放世界载具场景要格外注意。
八、Lumen 与 Lightmap 的取舍
Lumen 不兼容 Static Lighting 的 lightmap。一旦启用 Lumen,预计算光照就被禁用。这意味着:
- 想同时用 lightmap 和 Lumen 是不行的;
- 对性能极其敏感的平台(老主机、低端移动),可能还是要回退到 baked GI;
- UE5.8 的 Lumen Lite 就是为了拓展适用平台。
graph TD
A[项目启动] --> B{目标平台}
B -->|高端 PC / PS5 / XSX| C[Lumen HQ]
B -->|中低端 PC / Switch 2| D[Lumen Lite]
B -->|移动 / 老主机| E[Baked Lightmap / SSGI]
C --> F[动态世界]
D --> F
E --> G[静态世界或混合方案]九、Lumen Reflections:不止于间接光
Lumen 除了全局光照,还负责动态反射。传统 Screen Space Reflections(SSR)只能反射屏幕内看得见的东西,相机外的物体一转身就消失。Lumen Reflections 通过 ray tracing 可以追到屏幕外的物体。
9.1 反射的工作方式
Lumen Reflections 同样依赖 Surface Cache 和 ray tracing。对于光滑表面,它会发射更多射线,得到清晰的反射;对于粗糙表面,它会用 Radiance Cache 做更便宜的模糊反射。
flowchart LR
A[光滑表面] --> B[高分辨率反射追踪]
C[粗糙表面] --> D[Radiance Cache 模糊反射]
B --> E[最终反射图像]
D --> E9.2 反射的性能控制
两个关键参数:
r.Lumen.Reflections.DownsampleFactor:反射分辨率降采样,2 表示半分辨率,4 表示四分之一;r.Lumen.Reflections.MaxRoughnessToTrace:粗糙度超过这个值就不追了,直接用其他反射方案。
主机项目通常把反射降到半分辨率,并把最大粗糙度限制在 0.4 左右。这样既能保留镜子、水面、金属的质感,又不会让 rough 材质也跑昂贵的反射追踪。
十、Card Placement:Surface Cache 的地基
Lumen 的 Surface Cache 不是凭空来的。引擎在导入静态网格时,会离线生成一组 Cards。每张 Card 是一个小平面,代表网格表面某个区域,从特定方向看去。
Card 的质量直接影响 Lumen 效果。如果 Card 覆盖不好,就会出现:
- 某些表面间接光缺失;
- 自发光物体不照亮周围;
- 移动物体附近的光照更新不及时。
你可以用控制台命令 r.Lumen.Visualize.CardPlacement 1 查看 Card 分布。常见问题包括:
- 复杂曲面 Card 太少;
- 薄物体背面没有 Card;
- 超大平面 Card 密度不均。
解决方式通常是:
- 调大 Static Mesh 的 Lumen Card Resolution;
- 把过于复杂的模型拆成几个简单模型;
- 对不重要的小物体禁用 Generate Mesh Distance Fields。
十一、常用可视化与调试命令
Lumen 提供了丰富的调试视图,排查问题离不开它们:
Show > Visualize > Lumen Overview # 同时看三种可视化
Show > Visualize > Lumen Scene # 看 Lumen 眼中的场景
Show > Visualize > Mesh Distance Fields # 看距离场质量
Show > Visualize > Global Distance Field # 看全局距离场
r.Lumen.Visualize.CardPlacement 1 # 看 Card 分布
r.Lumen.Visualize.SurfaceCache 1 # 看 Surface Cache 覆盖
r.Lumen.Visualize.IndirectDiffuse 1 # 只看间接漫反射小美每次遇到漏光,第一步就是打开 Lumen Scene 视图。如果 Lumen Scene 里某个表面是黑的或粉的,说明 Surface Cache 没覆盖到,问题往往在 Card 或 distance field 上。
十二、从 Baked GI 迁移到 Lumen:一份实操清单
如果你的项目原本用 lightmap,迁移到 Lumen 不是改个设置就完事的。下面这份清单来自一个真实的中型项目迁移经历。
12.1 项目设置阶段
- 关闭 Static Lighting,开启 Lumen GI 和 Reflections;
- 启用 Generate Mesh Distance Fields(Software Ray Tracing 需要);
- 检查 Post Process Volume 的 Lumen 相关参数;
- 为不同平台准备 Scalability 配置。
12.2 资产检查阶段
- 所有 Static Mesh 检查 UV 是否适合 Surface Cache;
- 薄墙、窗户、门洞检查 distance field;
- 自发光物体确认 Card 覆盖;
- 植被确认是否启用 Two-Sided Foliage,以及对 Lumen 的影响。
12.3 性能验证阶段
- 在目标平台上跑
stat GPU和stat Lumen; - 测试最复杂关卡的帧率;
- 检查移动相机时的 Lumen 更新延迟;
- 对比 Lumen HQ、Lumen Lite 和关闭 Lumen 三种模式。
12.4 团队培训阶段
- 灯光师要学会用 Lumen 视图排查漏光;
- 地编要知道哪些几何体会导致 distance field 问题;
- 程序要掌握主要控制台变量和 Scalability 配置。
十三、一个地下城关卡的 Lumen 调优实录
下面这个案例来自小美团队的实际项目,能帮你把前面讲的理论串起来。
13.1 关卡背景
一个地下墓穴关卡,面积约 4000 平方米,有大量石柱、火把、浮雕和水面。原计划用 baked lightmap,但策划要求火把可以动态点燃和熄灭,只能上 Lumen。
13.2 初始性能
开启 Lumen HQ 后,在 RTX 3070 上帧率 42fps。Profiler 显示:
- Surface Cache Update:1.8ms
- Screen Probe Gather:3.1ms
- Final Gather:2.4ms
- Lumen Reflections:1.9ms
合计 9.2ms,已经占了一整帧预算的四分之一。
13.3 优化步骤
第一步:砍反射。
水面虽然需要反射,但不需要全分辨率。把 Reflections.DownsampleFactor 从 1 改到 2,反射开销降到 0.9ms。画面几乎看不出变化。
第二步:降 probe 密度。
地下城光线变化慢,不需要太高 probe 密度。ScreenProbeGather.DownsampleFactor 从 8 提到 16,Screen Probe Gather 从 3.1ms 降到 1.7ms。
第三步:控制 trace 距离。
地下城是一个封闭空间,光线不需要跑太远。Max Trace Distance 从默认的 10000 降到 3000,少了大量无意义的远距离追踪。
第四步:清理小物体。
场景里有大量小碎石和瓦罐,它们都生成了 Distance Field 和 Cards。把小于 20cm 的物体从 Lumen Scene 中排除,Surface Cache Update 从 1.8ms 降到 0.9ms。
13.4 最终结果
优化后 Lumen 总开销 4.8ms,帧率稳定在 58fps。画面损失了少许反射锐度和间接光高频细节,但在昏暗的地下城里几乎不可察觉。
flowchart LR
A[初始 9.2ms] --> B[反射降采样 -1.0ms]
B --> C[Probe 降密度 -1.4ms]
C --> D[缩短 Trace -0.8ms]
D --> E[排除小物体 -0.9ms]
E --> F[最终 4.8ms]这个案例说明:Lumen 的性能空间很大,关键是你愿意放弃哪部分质量。
十四、UE5.8 给 Lumen 带来了什么
UE5.8 并没有重写 Lumen,但做了不少打磨工作。最大的变化是 Lumen Lite 的成熟,它为 Switch 2 和中低端 PC 提供了可行的 GI 方案。除此之外,5.8 还:
- 改进了 Hardware Ray Tracing 在大场景下的稳定性;
- 优化了 Surface Cache 的更新策略,减少快速移动相机时的 pop-in;
- 增强了 Lumen 与 MegaLights、Virtual Shadow Maps 的协同;
- 提供了更完善的可视化调试工具。
对于已经在用 Lumen 的项目,升级到 5.8 主要是验证工作:确认既有设置在新版本下性能是否一致,漏光问题是否改善。对于还没用 Lumen 的项目,5.8 是一个更安全的切入点。Lumen 和 Nanite 一起,构成了 UE5 实时渲染的两大支柱:一个负责几何,一个负责光线。两者配合好了,传统管线里那些「先烘焙再调整」的噩梦,基本就告一段落了。
十五、Lumen 与 Nanite:一对互相成就的组合
Lumen 和 Nanite 经常被一起提到,但它们不是绑定的。Lumen 可以在非 Nanite 网格上工作,Nanite 也可以在没有 Lumen 的项目里使用。不过,它们组合在一起时效果最好。
原因是:Lumen 需要频繁捕获场景表面的材质信息来更新 Surface Cache。如果场景里全是高面数模型且没有 Nanite,捕获 pass 会非常慢。Nanite 让高面数几何在远距离自动简化,Lumen 捕获 Surface Cache 时也就更快。
反过来,Lumen 让 Nanite 网格的光照更真实。没有 Lumen,Nanite 再精细也只是死几何;有了 Lumen,岩石的凹凸会在墙壁上投下微弱的间接阴影,金属表面会反射周围环境。
graph LR
A[Nanite 自动 LOD] --> B[减少 Surface Cache 捕获开销]
B --> C[Lumen 实时 GI]
C --> D[更真实的光照]
D --> A在开放世界项目里,这个组合尤其重要。World Partition 负责加载和卸载关卡区域,Nanite 负责几何流送,Lumen 负责光照一致性。三者协同,才能做出玩家能连续走几公里而不明显感觉到加载边界的游戏世界。
十六、Far Field:开放世界的远距离 GI
对于开放世界,Lumen 默认的 200 米追踪距离远远不够。Hardware Ray Tracing 模式下,UE5 提供了 Far Field 机制。
Far Field 依赖 World Partition 的 HLOD。当射线超过 Max Trace Distance 后,Lumen 会转而追踪远处的 HLOD 几何。这样可以在 1 公里甚至更远的距离上保持间接光和天空阴影的合理性。
启用方式是在 DefaultEngine.ini 里加:
[/Script/Engine.RendererSettings]
r.LumenScene.FarField=1
r.LumenScene.FarField.MaxTraceDistance=100000代价是:
- 需要构建 HLOD;
- 远距离追踪增加 GPU 开销;
- 对 Software Ray Tracing 无效。
《黑客帝国觉醒》技术演示就是靠 Far Field 实现了大尺度城市的光照一致性。
十七、写在最后
Lumen 把全局光照从「离线预计算」变成「运行时动态」。这对反复调整灯光的工作流程是革命性的。但自由有代价:你要学会调 probe 密度、控制 trace 距离、检查 distance field、在不同平台间做取舍。
小美现在周三下午确实能睡午觉了。但她也会在周四上午花两小时排查一个漏光 bug。工具不会消除所有问题,它只是把问题从「等待烘焙」转移到了「调参和验证」。对大多数团队来说,这笔交易很划算。过去改一盏灯要两小时,现在两分钟;过去漏光只能重烘,现在可以实时看效果。省下来的时间,足够你多试几种创意,也多修几个真正的 bug。能把人从重复劳动里解放出来的工具,永远值得认真学。Lumen 就是这样一把工具。希望下次你拖动一盏灯的时候,能感受到这种自由,而不是被两小时烘焙时间绑在工位上。对灯光师来说,这大概是 UE5 最人性化的一次升级。技术再宏大,最终服务的还是具体的人。小美的周三下午,就是最好的证明。从那以后,她再也没有因为 lightmap 烘焙失败而加班。当然,漏光 bug 还是偶尔会来串门。但至少,她能在五分钟内定位问题,而不是等两小时烘焙完才发现。这就够了。