前两节给了两个极端:路径追踪无偏但烧算力,光子映射高效但有偏差。族谱上介于两者之间、乃至跳脱两者之外的算法还有一大群,共同点是承认"有些光照是低频的、可缓存的、可复用的",用空间或时间上的复用换算力。本节盘点四个代表性成员——辐照度缓存、即时辐射度、双向路径追踪、顶点连接合并——并顺手为第 7 章铺路:实时管线的所有"全局光照方案",血统几乎都出自这一节。
漫反射间接光有个温和的性质:空间变化平缓——墙角的间接光和它旁边十厘米处的几乎一样。辐照度缓存(Irradiance Caching)据此记账:在间接光变化剧烈的地方(几何转折、遮挡边界附近)密密地算真值并缓存,平缓的地方大幅稀疏,未缓存位置用邻近缓存点的梯度插值。判断"能不能插值"的标准也直白:缓存点与本点的连线是否通畅、法线夹角多大、距离多远。离线渲染里它曾把间接漫反射的计算量砍掉一个量级;它的现代转世你其实已经见过——实时管线里遍布场景的光照探针,本质就是把辐照度缓存搬进每帧预算:探针在离线或低频更新时算好球谐系数,运行时插值取用。
即时辐射度(Instant Radiosity)的思路更激进:先从光源撒一批路径,路径的每个落点直接当成一盏虚拟点光源(VPL),然后整个场景的光照计算退化成"对着几百盏虚拟灯做直接光照"。妙处在于复用:所有间接光被折算成直接光的形状,成熟的阴影射线与直接光照代码原样上岗,数百次弹射的效果一轮就出来。软肋也来自这个折算:虚拟光源离表面太近时,点光源模型的贡献爆炸(平方反比的分母趋零),画面炸出亮斑——工程上要做近距离钳制,而钳制引入偏差。这个思路在实时管线里的名字叫"反射阴影贴图"(RSM):从光源视角的 G-buffer 里直接取点当虚拟灯,一盏真实灯间接照亮全屋的效果,实时可跑。
2.3 预告过的双向路径追踪(BDPT)在这里补完工程细节:从相机和光源各走一条半路径,把两条路径的所有"头对头"连接方式(端点直连、经阴影射线验证)全部计入贡献,用 MIS 按生成概率分账。它对"两头都窄"的路径——灯在房间内、相机在门外透过钥匙孔看的经典场景——有数量级的效率优势。顶点连接合并(VCM)则更进一步:把 BDPT 的确定性连接与光子映射的局部合并统一到一个框架里,每个光路顶点既可直连也可用光子核合并,权重自动平衡,兼顾无偏段的锐利与合并段的高效。两者是离线高端渲染器的"疑难杂症科"——常规路径追踪收敛良好的场景轮不到它们出场,钥匙孔、焦散链、发丝高光这类硬骨头才请上手术台。
把族谱用一遍。需求:一套静态室内建筑的十分钟回合制游戏过场,相机缓慢移动,一盏吊灯带磨砂灯罩,桌面需要茶具的柔焦散。排班方案:主体间接漫反射用辐照度缓存思想——稀疏缓存点离线算好,相机移动时插值(静态场景缓存全程有效,收益最大);吊灯的柔和直接光用即时辐射度——灯罩表面取两百个虚拟点光源,软阴影与柔光一次到位;茶具焦散是光源侧窄路,请 6.2 的渐进光子映射单独包干;水面或镜面若有,路径追踪的 BSDF 采样原样接管。四路结果按 MIS 权重合流,总时间比纯路径追踪降约八成。解读:排班的原则是按光照的"频率特性"分工——低频的缓存、折算,高频锐利的追踪,窄路的给光子。变式:把"静态"改成"实时对战",缓存的离线性立刻失效,排班要整个推倒重排——这正是下一章的主题:当预算从分钟压到毫秒,族谱上还能剩谁。
路径追踪与光子映射各占一头之后,中间地带的居民——缓存、虚拟灯、双向会师——各有各的命门。把它们的失效模式整理成纪律,比背公式有用。
辐照度缓存这类空间复用方法,收益与风险写在同一句话里:邻近点光照相似才可插值。翻译成工程纪律是两条守恒律。第一条,缓存点密度必须匹配光照频率:拐角、阴影边界、小光源附近,辐照度在一两厘米内就能翻倍,稀疏插值直接糊出漏光;开阔墙面上一米一个点都嫌密。自适应密度(梯度超阈即加密)是成熟实现的标配,均匀密度只配教学演示。第二条,缓存值必须带有效期:光源移动、材质变更、几何重构,任何一条都会让旧缓存变成毒药——脏区失效比整表重建重要,时间戳与脏区队列是缓存系统里最先写也最容易漏的两段代码。
虚拟灯一派还剩一笔账没算:近场爆炸的定量边界。虚拟点光源的贡献按距离平方反比增长,一盏灯恰好贴着着色点时,单项贡献可以超过全画面总和——闪烁亮斑由此而来。工程上把单灯贡献钳到场景平均辐照度的若干倍,或给贡献距离设下限;两种做法都引入轻微偏差,但相比闪烁是合算的交易。钳制阈值要按场景尺度归一,绝对数值不通用。
失效清单可以直接当排障表用:
| 症状 | 根因 | 处置 |
|---|---|---|
| 拐角漏光 | 缓存密度不足 | 梯度加密、角点加权 |
| 光斑边缘发糊 | 插值半径过大 | 收半径、限制插值点数 |
| 灯动之后画面发旧 | 缓存未失效 | 时间戳、脏区队列 |
| 远处表面集体偏色 | 插值跨过材质边界 | 按材质分区缓存 |
| 动画序列闪烁 | 缓存点每帧重排 | 固定空间锚点、增量更新 |
最后给"什么都不用"留个位置:场景小、光源宽、镜头静态时,纯路径追踪加直接光采样就是最优解。中间地带的全部方法都在为"预算不够、场景不配合"付利息,场景配合时别付这笔利息——技术选型的成熟标志,是能说出"这里不需要高级技术"。
族谱收束成一句话:路径追踪管宽路,光子映射管窄路,缓存管低频,虚拟灯管折算,双向管两头窄——五句话对应五套实现,没有哪套值得在没有对应症状时上马。判断顺序照着症状走:先问噪声集中在哪里(窄路还是全局),再问场景动不动(缓存能不能活),最后问预算排不排得开(双向的复杂度买不买得起)。三问过后,族谱上能上的通常只剩一两个名字——选型最难的部分从来不是技术,是承认大多数时候并不需要它们。把这三问写进渲染器的技术设计文档模板,新项目立项时照单填空,评审会上关于"要不要上双向"的争论会少一大半:文档替人吵架,是最便宜的吵架方式。
族谱盘完,离线世界的理论装备齐全。下一章预算骤变:从"几分钟一帧"到"16 毫秒一帧",看看这套理论在实时世界里还剩多少、又被迫长出什么新器官。