一张噪点减少的图,可能仍然把同一束直接光加了两遍。一张稳定偏暗的图,可能来自截断路径,也可能只是输出时漏了 sRGB 编码。继续增加采样数只能处理其中一部分问题。

本篇用累计渲染器回答一个具体问题:小面积灯照亮盒子时,怎样区分随机误差、参考误差和实现错误?实验保留线性像素,重复运行不同种子,再用解析用例检查几何、材质、采样与颜色输出。图像中的直接光和探针中的完整光传输分别验证,不能互相替代。

先说明图像在估计什么

沿用第 22 篇的小灯盒。灯位于 y=0.99,半边长 0.12,面积 0.0576,朝下发出恒定辐亮度 40。相机在 (0,0,3.2),朝向原点,竖直视场角 0.75 弧度。32×32 个像素都从中心发出主光线;没有像素内抗锯齿采样。漫反射表面只计算一次直接照明,直接可见的灯返回其发射值,背景为零。

这一定义排除了两个容易混淆的目标:本组图不估计像素面积平均值,也不包含墙面之间的间接反射。因此,用带抗锯齿的离线成图或第 21 篇的完整路径图作逐像素参考,会把目标不同产生的差异混入实现误差。

对每个可见表面点,确定性参考把灯划成 64×64 与 128×128 网格,分别做面积中点积分。积分项是第 22 篇的 Lₑρ cosθ cosθₗ V/(πr²),再乘每个灯面小块的面积。表面点仍按原约定沿法线偏移 10⁻⁷,阴影射线检查同一 BVH。

128乘128灯面网格生成的直接光参考

图为程序实际生成的 32×32 直接光参考,放大显示像素。显示经过 L/(1+L) 压缩和 sRGB 编码,后面的误差计算使用压缩前的浮点线性 RGB。

两档参考的线性 MSE 为 4.9121×10⁻¹⁵。程序既检查绝对细化误差,也要求它小于本次所有随机试验中最小 MSE 的 1%;本次最小值约为 1.6368×10⁻⁷。这个检查说明网格细化差异远低于所观察的随机误差,但不能证明参考没有共同错误。两档积分共享几何、可见性和光源配置,若表面法线或阴影射线实现有错,两份结果可能一起错。

一次误差与多次误差

令 Xₘ 是第 m 次运行得到的线性图像,R 是固定参考,P 是像素数。每次图像误差定义为:

em=13Pp=1Pc{r,g,b}(Xm,p,cRp,c)2. e_m=\frac{1}{3P}\sum_{p=1}^{P}\sum_{c\in\{r,g,b\}} (X_{m,p,c}-R_{p,c})^2.

没有按图像各自的最大值归一化,也没有先编码成八位 PNG 再计算。若把所有线性辐亮度和参考一起放大两倍,MSE 会变成四倍;它带有亮度单位的平方,跨曝光直接比较没有意义。黑色附近的相对误差还会出现分母过小的问题,本实验使用绝对平方误差。

对 BSDF 采样、灯面采样和 MIS,分别运行 N=16、64、256,每档使用种子 1–8,总计 72 次。每次固定采样数结束,不因图像好看提前停止。随机生成器为 mt19937,开区间均匀数沿用第 20 篇的转换。每幅图使用一个随机流,按像素顺序消费;因此,不同 N 的相同像素并不保证使用相同的随机数前缀。

方法 N=16 平均 MSE N=64 平均 MSE N=256 平均 MSE
BSDF 8.0338×10⁻² 1.9979×10⁻² 5.2793×10⁻³
灯面 2.8448×10⁻⁶ 7.1106×10⁻⁷ 1.8380×10⁻⁷
MIS 2.7959×10⁻⁶ 7.2704×10⁻⁷ 1.8895×10⁻⁷

各档平均 MSE 大致随 N 增大四倍而降到四分之一,符合独立有限方差均值估计的 1/N 趋势。这里只有三个采样档、八个种子,不能由此证明任意场景都收敛,也不能要求每一次运行的误差严格单调下降。小灯在 BSDF 分布下很难被抽中,少数命中产生大贡献,这正是它误差较大的原因。

N=256 时,八次 MSE 均值的标准误分别约为 1.0201×10⁻⁴、6.2448×10⁻⁹、4.3956×10⁻⁹。这里先得到八个整幅图误差,再计算样本标准差除以 √8;没有把 1024 个像素当成 1024 次独立试验。八次重复也可能漏掉罕见事件,标准误小不等于不存在未采到的大贡献。

MIS 每次迭代各取一个灯面样本和一个 BSDF 样本,其余两种方法每次只取一类样本。表格比较的是指定 N 下的误差,不是相同计算成本下的性能。不同方法复用种子还会产生配对相关;若要比较时间效率,应使用第 22 篇那种固定时间预算,并保留实际耗时。

预先选定种子1的BSDF采样16次结果 同一预选种子1的BSDF采样256次结果 种子1灯面采样16次结果

三幅实际结果依次为 BSDF 的 N=16、256,以及灯面采样的 N=16。种子 1 在展示前固定,没有从八幅图中挑选最漂亮的一幅。小灯场景中灯面采样很有效,但不能据此推断它对强镜面高光也占优势。

平均图误差为什么不等于偏差

每个像素分量都有 M=8 个估计。令平均图为 X̄,各分量的样本方差使用分母 M−1,再对全部像素分量平均,得到 s²。逐次 MSE 的平均满足有限样本恒等式:

eˉ=MSE(Xˉ,R)+M1Ms2. \bar e=\operatorname{MSE}(\bar X,R)+\frac{M-1}{M}s^2.

推导只需把 Xₘ−R 写成 (Xₘ−X̄)+(X̄−R),展开平方。交叉项求和为零,因为各次偏离均值的和为零。剩下第一项除以 M,而样本方差除以 M−1,所以必须带上 7/8,不能直接把两者相加。

例如灯面采样 N=256,平均逐次 MSE 为 1.8380×10⁻⁷,平均图到参考的误差为 2.3291×10⁻⁸,平均样本方差为 1.8344×10⁻⁷。代入右侧可恢复左侧。Python 从 73,728 条线性像素记录重算 72 个 MSE,并对九组配置逐一检查这个恒等式。

这不是把“方差加偏差平方”中的真实偏差测出来了。X̄ 仍然只有八次运行,R 也不是真值;平均图误差同时含有限重复噪声、参考误差与可能的系统偏差。将它命名为 bias² 会把未知量说成已知量。

BSDF256次采样的线性绝对误差乘10 灯面256次采样的线性绝对误差乘10

两张误差图都先逐通道计算 |X−R|,统一乘 10,再经过与普通图相同的压缩和 sRGB 编码。黑色表示零误差,亮处表示误差较大。固定倍率便于比较,但强误差会被压缩,因此具体大小仍看线性统计,不能从显示亮度反推 MSE。

高采样参考也会波动

完整路径另用第 21 篇的盒子做固定探针:起点 (−0.65,−0.8,0),方向朝下。这样保留间接反射,同时避免把直接光图片误称完整光传输验收。

参考 A、B 分别使用种子 101、102,各运行 262,144 条路径;评估组使用种子 1–8,各 16,384 条。完整路径从第三次散射起以 0.8 生存率做俄罗斯轮盘,并补偿吞吐量;4096 次应急上限触发异常,不静默截断。另运行只允许两个命中顶点的 D=2 版本。低采样组沿用第 21 篇参数和种子,所以这是相同配置的重跑,不是新增一组独立证据。

红通道统计 实测值
高采样参考 A 0.782146
高采样参考 B 0.780248
八次完整路径均值 0.788720
完整路径均值的标准误 0.001968
八次 D=2 均值 0.551532

A 与 B 相差约 0.001897,已说明“高采样”并不意味着精确真值。以两者平均为参考,完整路径红通道的平均平方误差约为 8.37×10⁻⁵,D=2 则约为 5.28×10⁻²。浅深度版本漏掉非负的后续贡献,增加同一种截断估计器的样本只能减小随机波动,不能恢复被删掉的光路。

完整路径均值仍比两参考平均高约 0.00752,超过该低采样组标准误的三倍。不能隐藏这个差异,也不能把仅八次运行的标准误当确定误差界。参考自身有噪声,少量重复对尾部估计不稳定;本实验报告观测值,不作“所有均值都落在置信区间内”的断言。

若随机参考 R 与被测 X 独立且无偏,平方差的期望还包含 Var(R)。两份同分布独立参考的差平方期望等于两倍参考方差,但两个批次不足以稳定估计该量。更关键的是,它们都调用同一个 trace_diffuse;独立种子只能减少随机相关,不能排除共同的求交、材料或权重错误。

把错误放回发生的层

统计趋势之后仍需小型解析检查。否则,两个共享错误的实现可能彼此一致。

正确控制 本次拒绝的错误候选
几何 单位球,射线 (0,0,3) 沿 −z,首次 t=2 在正确 t 上加 0.1,解析残差失败
材质 Lambert ρ=0.6,恒定单位入射,积分结果 0.6 漏除 π 后得到 0.6π,能量检查失败
采样 小灯直接光面积积分约 0.184301 两策略无权相加约 0.357793,偏离超过参考的 50%
输出 线性 0.5 编码为八位 sRGB 188 直接乘 255 四舍五入得到 128

采样行确实执行错误的 double_count 路径:种子 17,262,144 次。其他三行是局部候选值的反例检查,没有把整条渲染器改坏再自动诊断。因此,实验能证明这些断言拒绝指定错误,不能宣称已经建立通用故障定位系统。

定位实际故障时,先用第 17 篇解析求交和第 18 篇暴力/BVH 对照检查几何,再检查第 19、23 篇的材料积分,随后检查估计器,最后检查编码后的图。几何错会改变可见性和法线;此时调采样数不会修好物体边缘。线性结果正确而 PNG 偏暗,则应沿输出转换检查,不能重新调材质让错误抵消。

材料检查也必须服从所选模型。Lambert 在恒定单位入射下应返回 ρ;第 23 篇采用单次散射 GGX,微表面间的多次反射没有计入,即使 Fresnel 恒为 1,也允许积分小于 1。强制归一化成 1 会改变模型,不能称为修复数值误差。

复跑与自检

累计代码位于仓库 examples/computer-graphics/,本篇入口是 validation_check.cppsummarize_validation.py。先编译运行 C++,再从线性文件重算统计:

1
2
3
make -C examples/computer-graphics all
examples/computer-graphics/build/validation_check examples/computer-graphics/build
python3 examples/computer-graphics/summarize_validation.py examples/computer-graphics/build

完整累计检查使用 make -C examples/computer-graphics check,还包含命令帮助与缺参数拒绝。随文保留 逐次误差汇总统计两档参考完整路径探针原始线性像素。这些文件先于 PNG 编码生成,读者可独立检查表格。

练习一:曝光改变会怎样影响指标? 将全部 X 与 R 乘 3,再计算 MSE、均方根误差和图像误差均值的标准误。

解题要点:平方差与 MSE 都乘 9;均方根误差乘 3;八次 MSE 的标准差与标准误都乘 9。若只把显示曝光改成三倍,原始线性指标应保持不变。必须先说明改变发生在哪一层。

练习二:为什么有限样本恒等式有 7/8? 用两个标量运行值 1、3,参考 1,手算两边,再将分母误写成 M 检查差异。

答案:平均逐次平方误差为 2,均值为 2,均值到参考的平方误差为 1,样本方差为 2。因此 2=1+(1/2)×2。若用总体形式方差得到 1,前面的系数应变为 1;不能混用两种分母。

练习三:两份高采样图完全相同,能证明正确吗? 设两份实现都漏了 sRGB 编码,或者都将 Lambert BRDF 写成 ρ。

解题要点:彼此比较可能为零,却仍与目标不符。输出错误由线性 0.5→188 的独立已知值检查;BRDF 错误由恒定入射积分检查。独立随机种子不能替代独立的解析依据。

参考资料

系列导航:总目录 · 上一篇:材质模型 · 下一篇:一次绘制怎样交给 GPU