《实时全局光照:GI 探针、SSGI、体积光照与 Lumen 思路》

全局光照(GI)处理的是光在场景中多次弹跳后的间接照明——墙体反射的天光、桌下漫反射的暗角、镜面上的环境倒影,这些细节决定了画面的“真实感”。本文从直接光与间接光的区分讲起,覆盖烘焙光照与 Lightmap、Irradiance Volume 光照探针、反射探针与镜面 GI、屏幕空间 SSGI、以及 Lumen/RTGI 等动态 GI 思路,最后给出混合方案的工程选型。

一个场景的亮度分成两部分:直接光(从光源直达表面)与间接光(光在物体间弹跳后到达)。直接光好算,间接光则是"真实感"的分水岭——没有 GI 的画面像舞台布光,有了 GI 才像自然世界。实时渲染的 GI 难题在于:精确 GI 需要路径追踪(见 光线追踪与混合渲染),成本太高。于是业界用一条光谱:烘焙 Lightmap(最便宜)、光照探针(动态物体)、屏幕空间 SSGI(临场感)、直到 Lumen/RTGI(全动态)。本文按成本从低到高梳理这条谱系,并给出选型决策。


一、直接光与间接光

一句话:直接光是光源直达的光,间接光是弹过一圈的光;间接光让阴影区不再死黑、让色彩在场景中"洇染",是真实感的主要来源。

1.1 渲染方程视角

渲染方程把出射辐射度写成直接项与间接项之和:

L_o = L_e + ∫ f_r · L_i · cosθ dω
            ├─ 直接项:光源直接照射
            └─ 间接项:来自场景其他表面的反射光

实时渲染对直接项做得非常好(Shadow Map、级联阴影见 光照与阴影),间接项则靠近似——因为它的积分维度是"全场景所有表面"。

1.2 间接光的两种形态

形态物理来源视觉表现实时常用方案
漫反射间接光表面向半球均匀反射阴影泛光、暗部色彩Lightmap、探针、SSGI
镜面间接光高光/镜面方向反射环境倒影、光泽反射反射探针、SSR、RTGI

1.3 天光(Sky Light)

没有天光时"天空"也可以被视为一个巨大光源:环境贴图(Cubemap/HDRI)提供从上到下的辐射,是最廉价的 GI 起点。天光 + 环境光遮蔽(AO)就能让静态场景立起"空间感",是 GI 的第一步。


二、烘焙光照与 Lightmap

一句话:烘焙(Baking)用离线渲染器把间接光预计算进 Lightmap(逐纹素光照图),运行时只是采样——代价全在制作期,运行时几乎为零。

2.1 烘焙流程

  1. 建模 → 拆 UV2(第二套光照 UV,与纹理 UV 分离);
  2. 离线光照(Radiosity / 路径追踪 / 辐射度)计算每个纹素的漫反射间接光照;
  3. 输出 Lightmap 纹理(通常 RGBA16F 或 RGBM 编码);
  4. 运行时采样 Lightmap,乘以反照率即可。
// GLSL:Lightmap 采样
vec3 gi = texture(lightmap, vUv2).rgb * texture(albedoTex, vUv).rgb;
color = directLight * albedo + gi;   // 直接 + 间接

2.2 优缺点

优点缺点
运行成本极低只能用于静态物体/静态光源
画质高(离线精确)光照无法动态变化(日夜/开关灯)
低端设备可用大场景 UV 展开与烘焙时间长
天然平滑移动物体需要探针补偿

2.3 烘焙的变体

  • Baked GI(纯 Lightmap):静态场景专用;
  • 间接 Lightmap + 动态直光:Lightmap 只存间接光,直光实时算——灯光变暗时间接光同步变暗;
  • Lightmass / 烘焙工具:Unreal Lightmass、Unity GPU Progressive Lightmapper 等。

编码上 Lightmap 常用 RGBM(RGB + Multiplier)或 LDR+AO,降低带宽;高动态范围需求用 RGB9_E5 或 RG11B10F。


三、Irradiance Volume:光照探针

一句话:Lightmap 覆盖静态表面,动态物体没法采样表面光照,于是用"体素网格里的探针"记录周围空间的光照,运行时按位置插值——这是动态物体 GI 的标准方案。

3.1 探针(Light Probe)

在场景空间布点(网格、球体、随机),每个探针预计算该点的辐照度(irradiance)——来自各个方向的天光/间接光入射的积分结果,常存为:

  • 球谐(Spherical Harmonics,SH)系数:通常 3 阶 9 个系数,压缩方向信息;
  • 或预滤波 Cubemap:存方向辐射,采样更直接但更占空间。
// 探针数据:一阶/二阶/三阶 SH 系数
struct SH9 {
    float r[9], g[9], b[9];   // 每通道 9 个 SH 系数
};

3.2 运行时插值

动态物体按位置取周围 8 个探针(网格布局)或 K 近邻,做权重插值,把 SH 系数按法线方向求值得到漫反射 GI:

// GLSL:SH 采样漫反射间接光
vec3 shEval(const in SH9 sh, vec3 n) {
    // 用法线方向对 SH 基函数求值(省略系数展开)
    float r = dot(sh.r, basis(n));
    float g = dot(sh.g, basis(n));
    float b = dot(sh.b, basis(n));
    return vec3(r, g, b);
}

3.3 探针布置与陷阱

  • 间距:探针太疏会插值出错误光照,太密成本高;按场景几何复杂度自适应;
  • 遮挡:探针无法感知墙体,跨墙插值会"漏光"(light leaking)——用可见性/体积烘焙修正;
  • 动态探针:可用低分辨率反射(上一帧深度)实时更新少数探针,支撑部分动态 GI。

四、反射探针与镜面 GI

一句话:漫反射 GI 解决"暗部泛光",镜面 GI 解决"高光与环境倒影"——反射探针把场景快照进 Cubemap,运行时按粗糙度做 mipmap 采样,一帧搞定大部分镜面间接光。

4.1 反射探针(Reflection Probe)

在场景位置放一个探针,渲染周围 6 面 Cubemap(或等距柱状),预过滤成带 mip 的粗糙度序列:mip0 最锐(镜面),mipN 最糊(粗糙)。运行时 PBR 采样:

采样级别 ≈ 粗糙度(roughness)→ mip level
粗糙度低 → 采 mip0(锐利倒影)
粗糙度高 → 采高 mip(糊成漫反射色)
// GLSL:PBR 镜面间接光采样(split-sum 近似)
vec3 R = reflect(-V, N);
float lod = roughness * MAX_MIP_LEVEL;
vec3 prefiltered = textureLod(envCube, R, lod).rgb;
vec2 brdf = texture(brdfLUT, vec2(NdotV, roughness)).rg;
vec3 specularGI = prefiltered * (F0 * brdf.x + brdf.y);

4.2 探针的局限与修补

  • 一个探针只能覆盖小范围,大场景需要多个探针 + 混合;
  • 探针快照是静态的,移动物体不会反映在倒影里;
  • 补偿:**SSR(屏幕空间反射)**用上一帧深度/颜色重建反射,见 后处理管线;探针 + SSR 是 AAA 的标准镜面 GI 组合。

4.3 平面反射(Planar Reflection)

水平面/地面常用专门的平面反射:以平面镜像相机渲染一次场景。成本高(全场景重渲),但水面这类大面积镜面效果远超探针。实时方案常把"探针 + SSR + 平面反射"按表面类型分配。


五、SSGI:屏幕空间全局光照

一句话:SSGI 把屏幕空间当成场景的"代理"——用上一帧的颜色与深度,在屏幕空间做光线步进采样,把远处理深处隐藏的间接光"带回来",零额外场景数据却有临场感。

5.1 原理

SSGI(Screen-Space Global Illumination)与 SSR 同源:

  1. 对每个像素,随机采样半球若干方向;
  2. 用深度缓冲沿方向做光线步进(Ray March),找到命中点;
  3. 把命中点上一帧的颜色当作该方向的入射光;
  4. 累加所有命中样本,得到漫反射/镜面间接光。
SSGI 一次命中:
  像素 P → 采样方向 D → 步进到表面 S → 取 S 的上一帧颜色作为入射光
  多个方向命中 → 平均 → 叠加到 P 的 GI

5.2 优点与硬伤

  • 优点:无需任何场景预处理;动态(几何、灯光、动画都实时反映);可与探针/Lightmap 叠加补足动态细节。
  • 硬伤:只能看到屏幕内的信息——被屏幕边缘切掉或藏在背面的间接光永远采不到,常配合"上一帧颜色 + 时域累积"减轻空洞。
// GLSL:SSGI 单方向步进示意
vec3 march(inout vec3 dir) {
    vec3 p = worldPos + normal * bias;
    for (int i = 0; i < STEPS; ++i) {
        p += dir * stepLen;
        vec4 sp = projView * vec4(p, 1.0);
        vec2 uv = sp.xy / sp.w * 0.5 + 0.5;
        float depth = texture(depthTex, uv).r;
        if (uv 越界) break;
        if (sp.z < depth) {
            return texture(prevColorTex, uv).rgb;   // 命中 → 取色
        }
    }
    return vec3(0.0);                               // 未命中
}

5.3 时域降噪

SSGI 的随机采样噪声很大,必须配时域累积 + 降噪(原理见 抗锯齿与时序):用运动向量把上帧结果重投影,与当前帧混合,把噪声平均成平滑的间接光。


六、动态 GI 思路:Lumen 与 RTGI

一句话:全动态 GI 是终极形态——Lumen 用"软件光追 + 全局表面缓存"模拟多次弹跳,RTGI 用硬件光追直接算间接光;前者省显存、通用,后者物理准确但成本高。

6.1 Lumen(UE5)的核心思路

Lumen 不追求逐像素精确,而是:

  • 全局表面缓存(Global Surface Cache):把场景网格的材质与光照缓存到低分辨率图集,供光线命中时查色;
  • 软件光追 + Mesh SDF:用有向距离场(SDF)做光线步进,命中表面缓存取色;
  • 屏幕空间优先:能命中屏幕空间的先用(快),命中不到才查 SDF/表面缓存;
  • 多次弹跳:把一次弹跳的结果再当作光源做第二次弹跳,模拟漫反射扩散。
Lumen 一次弹跳:
  屏幕空间命中(快) → 有则取屏幕颜色
  ↓ 未命中
  SDF 步进(Mesh SDF) → 命中 → 查 Global Surface Cache
  ↓
  反射/漫反射间接光 → 再次弹跳迭代

6.2 RTGI(硬件光追 GI)

用 RT Core(见 光线追踪)对间接光发射少量光线,命中后采样材质与光照,再经时域降噪。物理上更准确,但每像素几十根间接光线 + 降噪的开销仍高于 Lumen 的软光追。

6.3 动态 GI 对比

方案动态几何多次弹跳成本硬件需求
烘焙 Lightmap否是(离线)极低无
光照探针部分部分低无
SSGI是单次近似中无
Lumen是多次近似中高中端
RTGI是精确高光追硬件

七、混合方案与工程选型

一句话:现实中几乎没人只用一种 GI——主流的混合是"烘焙打底、探针管动态物体、SSGI/光追补细节",按平台预算把成本阶梯排列。

7.1 经典混合架构

层负责技术
底层 GI静态场景漫反射Lightmap
动态物体角色/载具漫反射Irradiance Volume
镜面 GI金属/水面/光泽反射探针 + SSR
细节补充动态光遮挡/弹跳SSGI
终极(高端)全动态Lumen / RTGI

7.2 按平台选型

  • 低端移动:Lightmap + 探针 + 天光,几乎零动态 GI;
  • 中端移动/PC:Lightmap + 探针 + SSGI + 反射探针;
  • 高端 PC / 主机:Lumen 或 RTGI + 屏幕空间降噪;
  • 影视/离线:路径追踪全精确。

7.3 工程决策清单

  • 场景几何是否静态?(静态多 → 烘焙收益大)
  • 是否有日夜/开关灯?(有 → 需要动态 GI 至少管灯光)
  • 移动物体多吗?(多 → 探针/动态探针必需)
  • 高端平台还是全平台?(预算决定是否上 Lumen/RTGI)
// 概念:运行时 GI 组合的开关策略
struct GISettings {
    bool useBaked;      // Lightmap 采样
    bool useProbes;     // SH 探针插值
    bool useSSGI;       // 屏幕空间步进
    bool useRT;         // 硬件光追(可选)
};
// 高端平台开 RT,中端降级到 SSGI,低端只剩 baked + probes

八、移动端与降级策略

一句话:移动端几乎没有实时多次弹跳的预算,工程重点是把 GI 质量"做进烘焙、省在运行时",并把动态部分限制在探针与廉价 SSGI 上。

8.1 移动端预算特征

  • 带宽与功耗是硬约束,全屏 GI Pass 每秒几十 MB 读写不可接受;
  • 无光追硬件,Lumen 式软光追也不现实(除非降分辨率 + 降采样率);
  • 结论:烘焙优先,动态 GI 用探针与低分辨率 SSGI。

8.2 移动端 GI 组合

层移动端方案备注
漫反射 GILightmap(低分辨率/压缩)RGBM 编码省带宽
动态物体SH 探针(3 阶 9 系数)每探针仅 108 字节
镜面单个环境 Cubemap + 粗糙度 mip不额外开销
动态补充半分辨率 SSGI + 时域只在需要处启用

8.3 降级技巧

  • 半分辨率 GI 缓冲 + 上采样(GI 是低频信号,低分辨率感知损失小);
  • 帧交替计算 SSGI(隔帧更新,配合时域累积);
  • 探针网格稀疏化 + 可见性预计算,减少运行时插值错误;
  • 用 GL_EXT_texture_compression 压缩 Lightmap,降带宽。

总结

实时全局光照是一张"成本—精度"光谱:烘焙 Lightmap 用离线算力换运行零成本,光照探针让动态物体共享空间光照,SSGI 用屏幕空间信息补充临场细节,Lumen 用软件光追 + 表面缓存逼近全动态多次弹跳,RTGI 则用硬件光追换取物理精确。工程上几乎总是混合使用,把各层的成本按平台预算阶梯排列。

技术类型成本动态性适合
Lightmap离线烘焙极低静态静态场景、移动端
Irradiance Volume探针低动态物体角色/动态物体
反射探针 + SSR镜面中低半动态金属/水面
SSGI屏幕空间中全动态桌面/主机细节补充
Lumen / RTGI动态 GI高全动态高端主机 / PC

实践路径:先搭"天光 + Lightmap + SH 探针 + 反射探针"的最小 GI 栈,用 RenderDoc 检查静态场景的暗部不再死黑;再加 SSGI 观察动态物体的临场感;高端平台再评估 Lumen/RTGI。每一步都以"间接光是否可信"为验收标准,避免叠加过多 GI 层导致光影打架。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「计算机图形学」更多文章

  1. 《glTF 资产格式与场景加载管线》
  2. 《Mesh Shader 新一代几何管线:Task/Mesh 着色器》
  3. 《GPU Driven 渲染与 LOD:从 CPU 瓶颈到 GPU 剔除》