6.1 路径追踪:迷你渲染器从零到收敛


6.1 路径追踪:迷你渲染器从零到收敛

前五章的零件全部到货,本节开工总装——这是全册主线实验的高潮。我们要把一台迷你路径追踪器从第一版裸循环迭代到收敛出图,每一步改动都交代动机与效果:为什么递归要换成迭代,为什么直接光要单独采样,为什么高光区域要两套采样分账。全部读完后,你不仅有一台能跑的渲染器,更有一条亲手摸过的收敛曲线。

第一版:把递归拆成循环

先上主循环。与 Whitted 递归相比有三处结构变化:递归拆成循环加"吞吐率"变量;方向不再只走镜面,而是按材质采样随机选;终止不再数深度,而是俄罗斯轮盘赌按剩余能量概率抽生死。

function radiance(ray): throughput = (1, 1, 1) # 沿途累计的能量权重 L = (0, 0, 0) # 累计的出射亮度 for bounce in 0..MAX: hit = scene.intersect(ray) if not hit: L += throughput * sky(ray.dir); break L += throughput * hit.emission # 自发光直接入账 r = random() # 轮盘赌:按反照率最大分量定存活率 if r > max(throughput): break throughput = throughput / max(throughput) # 活下来则补偿权重,保期望 wi, pdf = bsdf_sample(hit, -ray.dir) # 按材质分布抽下一跳方向 throughput = throughput * bsdf_eval(hit, wi, -ray.dir) * dot(n, wi) / pdf ray = make_ray(hit.pos + n * EPS, wi) # 第3章的偏移防自交 return L

三个细节各有讲究。轮盘赌的存活率取材质反照率的最大分量:越吸光的表面越早死,且除以存活率保证期望不变——这是 2.2 蒙特卡洛"除以概率"规则的又一次现身。方向采样按 BSDF 分布抽:光走"材质愿意走"的方向,pdf 里的偏好在除法里精确抵消,无偏性完好。发射上限仍是必要的兜底:轮盘赌理论上永不保证终止,工程上留一道 MAX 保险丝。第一版立刻可跑:三个球加一面墙的场景,每像素 1 样本,出图——噪点狂舞但整体明暗已经正确,尤其是墙角出现了光栅化管线怎么也凑不出的柔和过渡:那是数百万条随机路径撞出来的间接光。

第二版:直接光采样,噪声的第一刀

看第一版的噪点会发现一个规律:光源越小,噪点越大。病根在采样策略——靠 BSDF 采样"碰巧"弹到光源的概率,随光源立体角缩小而骤降,偶尔弹中的样本带着巨大贡献,把整幅画面搅出麻点。药方是下一事件估计(Next Event Estimation,俗称直接光采样):在每个命中点主动向光源连一条阴影射线,直接光的贡献解析地算,不再指望运气:

# 在轮盘赌之前插入: light_pdf, pl = light_sample() # 在光源上随机取点 if not scene.occluded(hit.pos, pl): L += throughput * bsdf_eval(hit, dir_to_light, -ray.dir) * dot(n, dir_to_light) * light_radiance / light_pdf

效果立竿见影:每像素 16 样本的第二版,已经比每像素 256 样本的第一版干净——小光源场景下差距还有一个量级。直接光从此走解析路线,BSDF 采样只负责间接光。

第三版:MIS 分账,别把高光算重

两套采样并存后新问题来了:视线接近镜面方向时,BSDF 采样偶尔也直接命中光源,而直接光采样已经把光源算过一遍——同一笔贡献记两次,镜面高光区域出现亮斑。多重重要性采样(MIS)给出精确的分账规则:每条路径按它被各策略生成的概率反比加权,谁擅长就谁多记。直觉版:直接光采样对小面光源效率极高(概率大),但采窄高光束效率极低;BSDF 采样恰好相反——MIS 按概率自动把权重拨给擅长的一方,两头都不吃亏。代码上只多两行:直接光那笔乘上 MIS 权重一,BSDF 采样命中光源那笔乘上 MIS 权重二,权重由各自的 pdf 用平衡启发式算出。第三版跑 64 样本,画面已接近成片质感。

图:从 1 到 4096 样本的收敛实录

图:从 1 到 4096 样本的收敛实录

收敛的算术与萤火虫

四个档位连起来就是一条收敛曲线,背后的算术值得单独一读:蒙特卡洛误差按样本数平方根的倒数衰减,样本翻 4 倍噪声减半,翻 100 倍才降一个量级——这就是"渲染农场烧一晚上"的数学出处,也是第 7 章降噪器存在的全部理由:与其等平方根,不如用时空邻居的信息把噪声猜掉。诊断收敛问题还有一把专门的探针:萤火虫——画面上孤立的超亮白点。成因是高贡献路径被低概率采到:一条侥幸穿过灯罩缝隙、又在镜面间弹了八次的路径贡献惊人,除以 pdf 后依然巨大。对策两类:钳制(对单样本贡献设上限,有偏但救命,实时管线标配)、重采样(按贡献引导样本分布,如第 7 章预告的重采样技术,无偏方向的努力)。

轮盘赌的两条纪律与一个收尾零件

轮盘赌写得随意会悄悄引入偏差,两条纪律要立好。其一,存活概率与反照率挂钩但设上下限:概率取反照率的最大分量,再钳到 0.05 与 0.95 之间——下限防止深色表面瞬间团灭路径(把深色材质渲染成黑洞),上限防止几乎不吸收的表面无限弹跳烧机时。其二,存活必须补偿:存活的路径贡献除以存活概率,期望才守恒;漏除的渲染器症状是"粗糙材质整体偏暗,深度越深越暗"——反照率越低暗得越狠,正是漏除的特征指纹。另外,前几跳不要开赌:前三跳贡献最大、方差最高,轮盘赌在这里淘汰样本等于专杀有效兵员,惯例是第三跳以后再开。

收尾零件是像素滤波:同一像素内的落点不必都压在像素中心,按一个小核(盒、三角或高斯)散布,多个样本加权平均。它不改变物理,却决定边缘观感——盒滤波的锯齿与过宽高斯的整体发糊都常见,半径取一到两个像素直径是特写与远景都稳妥的起点。

还有一个新手常见的预算浪费值得点名:把样本预算平均分给所有效果。直接光已由解析采样解决,漫反射间接光一两个配好分布的样本就够,真正吃样本的往往只有高光链与窄光源。让每像素总样本数恒定、按效果重要性重新分配射线数,通常比整体加倍便宜得多——收敛服从平方根定律,省一半样本等于省四分之三时间。这笔账在第 7 章的实时预算里还会再算一遍,届时它从省钱技巧升级成生死线。

最后补一个数值直觉:把三个版本的降噪量排成数轴——第一版每像素 4096 样本才勉强可看,第二版 512 样本达标,第三版 64 样本起步;每前进一步都是把"盲采"换成"会采"的一次兑现。收敛曲线的斜率被平方根定律锁死,但截距可以靠采样策略大幅左移——这句话是本章的压缩表示,第 7 章的一切预算魔法都是在实时条件下重演这个左移。动手建议:三个版本各存一张标准场景出图,标注样本数与耗时,这组对照图日后就是你向团队解释"为什么必须做重要性采样"的最短材料。

本节要点回顾

  • 迭代加吞吐率替换递归,轮盘赌按反照率定生死、除以存活率保期望,MAX 兜底防不停机。
  • 直接光采样是第一刀:解析算直接光,小光源场景降噪一个量级以上。
  • MIS 是分账规则:按生成概率反比加权,直接光与 BSDF 采样各记所长,高光不再重复计账。
  • 收敛服从平方根定律:样本翻 4 倍噪声减半;交付级静帧与实时之间隔着的,正是第 7 章要补的降噪课。
  • 萤火虫来自高贡献低概率路径:钳制治标、重采样治本。

主力机已能收敛出图,但它有一块天生的盲区——灯罩下的焦散它采了万遍仍不得要领。下一节请出专治窄路的另一半地图:光子映射。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U