一个着色点接收到的光,有一部分来自别的物体反射的光;而别的物体,又接收到它反射的光。 要算清这一点,只能在场景里采样 —— 而一旦靠采样,就永远受 1/√N 支配。
这条骨架把 GI 收成三件事:在哪采样(探针 / 像素 / 路径)、采几次(一次反弹 / 多次反弹)、 怎么排(随机 / 分层 / 蓝噪声)。第 1 课量清了"不采样"的那一头, 第 2 课回答了第一件:在哪采样,第 3 课回答了第二件的前半步:采几次(一次)。 本课把"采几次"推到像素上 —— 再也不预先把场景切好,让光路自己走; 而一旦沿光路抽,就立刻要面对第三件事:怎么排。
3.3 把整个场景切成面片、把"互相问"的方程解了一遍,于是"多走一步多带回多少"第一次有了数。 可它的两笔账都押在前提上:每个面片只有一个数(所以窄缝里的渐变是分段的), 而那张"谁看得见谁"的形状因子表,只对漫反射成立 —— 换成金属、换成任意形状,那张表就得重做。
换一条完全不同的路:不预先切场景、也不解方程,而是从像素出发,让光路自己走 —— 每一步按材质的分布随机挑一个新方向,撞到东西就继续走,撞到天就把那一份光带回来。 这条路什么形状、什么材质都能走;可它的代价在第一步就露出来了: 一条光路只是无数种走法里的一种 —— 它给出的答案是抽出来的,不是解出来的。 所以本段唯一要装的东西就是这个:每条像素抽几条光路 M。M = 1 时画面是"麻"的, M 一大就干净起来 —— 而 3.3 那本"多走一步多带回多少"的账,搬到光路上照样能算(件三表①)。 三件量出来的事见下:判据②给"抽得越多越接近答案",判据④⑤给"被挡住的地方,间接那一份涨了一个量级", 判据⑥给"两种抽法是同一个积分",判据⑧给"一条光路绝不会凭空发光", 判据⑨给"两条带格数悬殊,那条带的均值自己带多少不确定度"。 保真度如实标「示意 · 等价重现」:整页是一台逐像素自算的 CPU 路径追踪器,不依赖 WebGPU; 件一框里那几行就是件二真正在跑的那份源码。
walk41 的正文,逐字未改):
它抽一条光路——从相机出发,每一"步"先问一句"这里晒得到太阳吗",
再按余弦分布随机拐个弯,直到撞到天、把那一份光带回来。
右列是它交出来的三个数:一条光路离答案有多远、抽 M 条之后还剩多少、
以及影子里的光有多少是"间接"来的。
hmax 从 1 调到 4 就是件三表①)。
direct41:只取第一个可见点自己收到的太阳与天),
再与总账相减。★ 它不能拿 walk41(hmax = 1) 冒充 —— 那一条走完 h=1 还会在邻居身上
再问一次太阳,带回来的其实是"弹过一次"的光(本页第一版正是这么写的,判据④把它抓了出来);
③ 太阳用"每步打一条阴影线"的显式抽样(sun41),所以太阳那一份不带噪声,
噪声全部来自"下一步往哪拐";④ 白墙的 ρ 取 0.85(与 3.3 同一个数),
所以"多走一步"的账能在两个装置之间对上;⑤ 两条带按"第一个可见点晒不晒得到太阳"分,
本页相机朝下看、地面又敞着,所以影带只占 153 格、亮带 2007 格(表②把两带的格数都印了出来)——
两条带这么悬殊,"影带的平均亮度"这个数就比亮带飘得多,所以表② 底下把这笔不确定度如实算了出来
(影带 ±0.0028、亮带 ±0.0005,判据⑨);
⑥ 每条光路最多走 4 步,再深的部分在画面上已经看不出来。
① 先看左块(M = 1,只抽了一条光路):场景的形状是对的,但整块满是麻点 —— 相邻两个像素可能差好几倍。这就是"一条光路 = 一个样本"的样子。
② 把「每条像素抽几条光路」从 1 拖到 32:中块一点点干净起来, 右块(与左块的差)也跟着淡下去 —— 右列那个"均方差"就是它的读数。
③ 盯住右块最亮的地方:麻点不是均匀撒的 —— 越暗的地方麻得越厉害 (M = 1 时,影带里样本的相对散布是 29.9%,亮带只有 10.7%,差 2.8 倍)。
④ 看件三表②:它把画面按"第一个可见点晒不晒得到太阳"分成两条带。
影带收到的光里间接占 45.6%(0.4568 里有 0.2085 是弹出来的),而亮带里只有 3.9% ——
相差 11.6 倍。这就是这一课真正要说的那句:被挡住的地方,光几乎全是"走出来的"。
如实标一句:影带只有 153 格,这个 0.4568 自己带着 ±0.0028 的不确定度(亮带 ±0.0005)——
"相差 11.6 倍"这句不受影响,但影带那串小数只该读到第 3 位。表② 底下写着这笔账是怎么算出来的。
⑤ 把「天光强度」拖到 0(只剩太阳):影带几乎全黑(平均亮度从 0.457 掉到 0.053), 可它还亮着一点 —— 而那一点100% 是间接来的(判据④实测:直接那一份正好是 0)。 太阳被盒子挡住了,它能拿到的每一份光,都得先在墙上弹一次。
左:只抽一条光路(M = 1)| 中:抽 M 条求平均 | 右:两者之差(灰阶)
启动中…
M = 1 是只抽一条(画面会麻); M 越大越接近答案,但每加一倍只是把麻点压小一点 —— 这条曲线的形状是 4.2 的事。
控件与上一段只多不少:天光、太阳方位、眼位、盒子数逐字相同。 上一段那三个开关(粗糙度 α、层号、间接反弹次数 N)在本段不再出现 —— 因为装置换成了"抽光路":3.3 那个 N 是解方程的遍数,本段的 M 是抽样的条数, 前者决定"算多深",后者决定"算多准"。本段唯一的新旋钮就是 M。
定点观察(三步):① 看左块(M = 1)那一脸麻点; ② 把 M 拖到 32,看中块怎么一点点变干净; ③ 再看右块最亮处 —— 麻点在暗处最厉害。 结论:一条光路是一个样本,不是一个答案;答案只能靠"多抽几条"去逼近。
| 最多走几步 | 全场 | 影带(晒不到太阳) | 亮带(晒得到) | 影带相对 1 步涨了 |
|---|
| 带 | 平均亮度 | 直接那一份 | 间接那一份 | 间接占 |
|---|
| 配置 | 画面最大 / 最小 | 恰好 = 1 的格子 | 判 |
|---|
两条带的均值有多少是噪声:建表后填在这里
th 一直是 1)——
所以画面每一格只能落在 {0, 1} 上,绝不可能超过 1。空地上(没有盒子)每一条都会一步出界,
于是整块画面逐位恒等于 1。这可以拿笔算。
这一段把"采几次"从解方程推到了抽光路:装置换了,代价也换了。
∫(ρ/π)·L·cosθ dω 与 (ρ/π)L·cos/(1/2π) 是同一件事的两种写法)。
工程上选前者,因为它把 cos 抽掉了,方差小。4.1 量出了一条曲线:M 从 1 涨到 32,"离答案还差的距离"掉到 1/8.26。 可那条曲线是拿什么量出来的?—— 拿"与参考解的差"。而参考解是上帝视角: 它由同一台程序另跑一遍、只为了给你当靶子。真机上你手上没有它。
这就让 4.1 那条曲线能看、不能用来做决定:画面还是麻的,你不知道是"再抽一倍就够"还是"再抽一千倍"。 出路其实就在同一个像素里:那 M 条光路彼此之间就差着,而这个"自己之间的差"恰好就是对 "均值离真值多远"的估计 —— 标准差除以 √M(标准误)。有了它,"还要抽多少"第一次变成一个能算的问题。 本段只加一样东西:一个不用参考解就能读出来的误差。 于是 4.1 那条曲线终于变成一条律:判据②量出"误差 × √M 是个常数"(也就是 误差 ∝ 1/√M), 判据④量出"自估的误差与上帝视角算出来的对得上",判据⑤量出那句最反直觉的话 —— 噪声减半要抽 4 倍,因为半是 √4 的一半,不是 2 的一半。 保真度如实标「示意 · 等价重现」:整页仍是那台逐像素自算的 CPU 路径追踪器,件一框里那几行就是本段真正在跑的。
se41 的正文,逐字未改):它不碰参考解,
只用这个像素自己那 M 条样本的和与平方和,把标准差反解出来、再除以 √M。
右列是它交出来的三个数:自己估的误差、拿参考解算出来的真误差、以及两者的比。
d2 那一行就是样本方差)。
于是"这个像素的答案有多不准"变成一件就地可算的事 —— 不需要知道答案。
RSQ41)——
这是本段唯一的实现改动;
③ M = 1 时估不出来(一条样本没有"彼此之间的差"),本页那一格按 0 画并注明;
④ "真误差"要一个参考解,本页用另一套种子另跑 M = 256(在样本网格上)——
参考解自己也在收敛,所以它给的真误差在最大那几档会略微偏高(表①的"误差 × √M"那一列照实列出来);
⑤ 表里的数不随画面上的滑块变(整张表按页首那套配置算一遍;判据另在固定的那套配置上评估)。
① 先看右块(自估误差):它是一张亮度图 —— 亮的地方 = "这个像素的误差大"。 它不需要任何参考解,只用像素自己那 M 条样本。
② 把「每条像素抽几条光路」从 4 拖到 32:中块越来越干净, 而右块整块一起变暗 —— 自估误差从 0.0397 掉到 0.0142,暗了 2.79 倍 (条数翻了 8 倍,而 √8 = 2.83 —— 这就是 1/√M 的指纹)。
③ 把 M 拖回 1:右块整块黑掉 —— 不是"误差是 0",是估不出来: 一条样本没有"彼此之间的差"。要看误差,至少得两条。
④ 看件三表②:它把"要几条"直接摊开 —— 想让噪声减半,M 要乘 4; 想减到 1/4,要乘 16。这可以拿笔算:误差 ∝ 1/√M。
⑤ 看件三表①的最后一列:把每一档的误差都乘上 √M,得到的几乎是一条水平线 —— 这就是"1/√M 这条律"的样子。而表②告诉你同一件事的另一面:M 只翻一倍,误差只掉 29%。
左:只抽一条光路(M = 1)| 中:抽 M 条求平均 | 右:这个像素自己估的误差(灰阶)
启动中…
同一个滑块,本段盯的不再是"画面干净不干净", 而是右边那块有多亮:它 = 这个像素自己估出来的误差。M = 1 时估不出来(一条样本没有散布)。
控件与上一段完全相同(一个不多、一个不少):光路数 M、天光、太阳方位、眼位、盒子数。 本段真正加的不是一个旋钮,而是一个读数 —— 右块那个不用参考解就能读出来的误差, 以及由它反推出来的"要几条"(件三表②)。
定点观察(三步):① 把 M 从 4 拖到 32,盯右块; ② 看它整块变暗了 2.79 倍(条数翻了 8 倍,而 √8 = 2.83); ③ 再拖回 M = 1 —— 右块全黑,但那是"估不出来"而不是"没有误差"。 结论:误差 ∝ 1/√M,而这条律只用像素自己的样本就能读出来。
| M | 真误差 | 自估误差 | 自估 ÷ 真 | 误差 × √M | 比上一档掉了 |
|---|
| 目标噪声(相对 M = 1) | 要几条(= 目标²) | 滑块到得了吗 | 实测误差比 |
|---|
| M | 用 M = 256 的参考解 | 用 M = 64 的参考解 | 相对差 |
|---|
误差 ∝ 1/√M 直接反解:
目标 = 1/2 ⇒ M ×4;目标 = 1/4 ⇒ M ×16;目标 = 1/8 ⇒ M ×64。这张表可以拿笔验:
把"要几条"开平方再取倒数,正好等于第一列那个目标。末列是扫描里真能用滑块走到的那些档的实测比值。
这一段把 4.1 那条"抽得越多越接近答案"的曲线,量成了一条能用来做决定的律。
4.2 把"抽多少"这条路量到了底:误差 ∝ 1/√M —— M 翻一倍只掉 29%, 想让噪声减半得把采样数乘 4。也就是说,靠"再多抽一点"这条路,回报是平方级地差。
那就换一条:不增加条数,只改"往哪儿抽"。同一笔预算 M,如果把这 M 条光路的第一步方向 在半球上铺开(仰角分层 + 方位低差异),而不是随便撒,它们就"覆盖得更均匀", 答案也就更准。可这里立刻冒出一个新问题:如果每个像素都用同一套铺法, 相邻像素就会一起错 —— 噪声变成块状的,而块状噪声在人眼里比细颗粒噪声难看得多。 工程上的解法是给每个像素整体转一个角度(用像素号当种子),铺法不变、但像素之间不再相关 —— 这就是蓝噪声。本段只加一样东西:采样怎么排(三档并排,同一个 M)。 三件量出来的事见下:判据②给"铺开比随便撒准多少",判据④给"分层准但成块、蓝噪声准且不成块", 判据⑧给一件更值得记的事 —— 3.3 那个"分层能快到 1/M"在光路上拿不到, 因为光路积分是十几维的,把第一步铺开只买到一部分。 保真度如实标「示意 · 等价重现」:整页仍是那台逐像素自算的 CPU 路径追踪器,件一框里那几行就是本段真正在跑的。
sch43 的正文,逐字未改):
它不改光路本身,只把"这一步往哪拐"的头两个随机数换成排开的那一份。
右列是它交出来的三个数:随机档的误差、同一 M 下分层档的误差、
以及三档的相邻像素相关系数。
① 先看三块画面(同一个 M):三块的明暗分布是一样的 —— 它们要算的是同一个积分。 不同的只是"麻"的样子。
② 把 M 从 4 拖到 32:三块一起变干净,但左边(随机)始终比中间和右边差一点 —— 右列那两个误差读数就是它的量。
③ 凑近看噪声的"颗粒":左块(随机)是细沙;中块(分层)看起来有一片一片的块; 右块(蓝噪声)又回到细沙 —— 而中块与右块的误差读数几乎一样。 也就是说:蓝噪声换的不是"误差多大",而是"误差长什么样"(判据④)。
④ 看件三表③:它把上面那句话变成一个数 —— 相邻像素误差的相关系数: 分层档明显为正(一起错),随机档与蓝噪声档接近 0。
⑤ 看件三表②:三档的拟合斜率几乎一样(−0.498 / −0.487 / −0.482,都压在 −0.5 上)—— 铺开买到的是常数折扣(误差压到 0.61 倍,等效省下约 2.7 倍采样数), 而不是更快的收敛速度。3.3 在面片上量到的那条 1/M,在光路上拿不到 —— 原因写在判据⑧里。
左:随机 | 中:分层(每像素同一套铺法)| 右:蓝噪声(每像素转一个角度)
启动中…
同一个滑块,三块画面一起动。本段不增加条数 —— 换的是"往哪儿抽",所以请凑近看颗粒,而不只是看干净不干净。 拖的时候三块会一条一条地铺开:先看到的是前几条的均值,越铺越干净,不用等它铺完。
控件与上一段完全相同(一个不多、一个不少)。本段的"唯一新东西"是三档排法 —— 它不是旋钮,而是三块并排:随机 / 分层 / 蓝噪声,同一个 M 下同时看。
定点观察(三步):① 把 M 拖到 16,凑近看三块的颗粒; ② 注意中块有片状的块,而左块与右块是细沙; ③ 再看右列的误差读数 —— 中块与右块几乎一样准。 结论:分层让人更准,蓝噪声让噪声"看起来"更细;两者误差一样,只是颗粒不同。
M 条的第一步方向在半球上排成网格,
每一个小格恰好落一条 —— 于是"哪里挤、哪里空"这种起伏被压掉了。
而随机撒下的 M 个点,总有些格子挤、有些空着,这份起伏就是误差的来源之一。
sqrt),所以可以直接比明暗;
② 三档各自用独立随机流,保证"排法"是唯一变量。
| M | 随机 | 分层 | 蓝噪声 | 分层 ÷ 随机 |
|---|
| 档 | 误差 ∝ Mk 的 k | M = 32 时相对随机的误差比 | 等效省下的采样数 |
|---|
| 档 | 相关系数(水平相邻) | 读作 |
|---|
k 就是"误差 ∝ Mk"里的指数:
k = −0.5 就是 1/√M(4.2 量到的那条),k = −1 才是 1/M(3.3 在面片上量到的那条)。
★ 实测结果是三条几乎都压在 −0.5 上(−0.498 / −0.487 / −0.482)——
也就是说铺开第一步没有换来更陡的收敛曲线,只换来一个常数折扣(误差压到 0.61 / 0.55 倍)。
末列把这份折扣折成采样数:按随机档自己的 1/√M 算,
要抹平这 0.61 倍,随机档得再多抽 ×1/0.61² ≈ ×2.7 条 —— 这一列可以拿笔验。
这一段把"采几次"之外的另一半也量了:同一笔预算,排法本身就是一种预算。
本段的活例由本页自己计算(示意 · 等价重现,非硬件产出):不依赖 WebGPU,任何设备都能跑。同一页的示意图与数值表照常可读。
页面版本 v3(课题四第 4 课「反弹多次」:三段全部上线 ——
4.1 路径追踪:随机走一条光路 / 4.2 收敛:1/√N 又出现了 / 4.3 采样怎么排:随机 / 分层 / 蓝噪声)。
4.1 这一段只加一样东西:每条像素抽几条光路 M。装置换了(如实声明):3.3 是"把场景切成面片、
把'互相问'的方程解一遍"(确定、无噪声,但每个面片只能存一个数、那张形状因子表只对漫反射成立);
本段是"从像素出发、让光路自己走"——每一步按余弦分布随机拐弯,撞到天就把那一份带回来。
量出来的五件事:
① 一条光路是一个样本,不是一个答案:M = 1 时离参考解的均方差是 0.0816,
抽到 32 条掉成 0.0099(1/8.26,且单调降);而同一套配置跑两遍逐位相同(判据①②)——
所以"麻"不是随机报错,是抽样本身;
② "多走一步"的账两个装置都能算:把每条光路最多走几步从 1 扫到 4,
影带 0.2865 → 0.4522(涨 1.58×),亮带 0.6792 → 0.7030(只涨 1.04×)——
涨起来的几乎全在晒不到太阳的那条带上(判据⑤ + 件三表①);
③ ★ 被挡住的地方,间接那一份涨了一个量级:按"第一个可见点晒不晒得到太阳"分带,
影带收到的光里间接占 45.6%,亮带里只有 3.9%(相差 11.6 倍);
再把天光整个关掉(只剩太阳),影带里那一点光100% 是间接来的(直接那一份正好是 0)——
太阳被盒子挡住之后,它能拿到的每一份光都得先在墙上弹一次(判据④,本段主判据);
④ 两种抽法是同一个积分:按余弦分布抽(只乘 ρ)与按均匀分布抽(乘 2ρcosθ)给出同一个期望
(判据⑥:整块画面平均 0.68584 对 0.68498,相对差 0.13%,可笔算);而白炉
(ρ = 1、环境处处 L = 1、关掉太阳)下,一条光路只能带回 0 或 1 ——
空地上一整块画面逐位恒等于 1(2160/2160 格),两个盒子时最大也正好是 1.000000000(判据⑧ + 件三表③);
⑤ ★ 那两条带悬殊,这笔账要如实标:影带只有 153 格、亮带 2007 格(相机朝下看、地面敞着),
于是"影带的平均亮度"这个数自己带着 ±0.0028(±0.61%),亮带只带 ±0.0005(±0.07%)——
相差 9.2 倍。表② 底下把这笔不确定度算了出来(判据⑨),影带那串小数因此只读到第 3 位。
判据九条:① 可复现(同种子两遍逐字节相同)/ ② 抽得越多越接近答案(单调降)/
③ 画面(写入格子数、非黑比例、非法值 0、命中面法线朝向来光的哨兵)/ ④ ★ 直接 vs 间接(主判据)/
⑤ 多走一步涨在影带(hmax 扫描)/ ⑥ 两种抽法同答案(可笔算)/
⑦ 同源(件一框里那几行 = walk41 的正文,重算逐位相同)/ ⑧ 白炉(不创造能量)/
⑨ 两条带的均值按格子数如实标出不确定度(格间起伏 + 每格抽样)。
4.2 这一段只加一样东西:一个不用参考解就能读出的误差。4.1 那条"抽得越多越接近答案"的曲线
是拿"与参考解的差"量的 —— 而参考解是上帝视角,真机上没有。本段把它换成像素自己那 M 条样本的散布:
每像素多记一个平方和(Σx²),就能把标准差反解出来、再除以 √M 得到标准误。
件一框里那几行 = se41 的正文(逐字,含 m < 2 那句守卫)。量出来的四件事:
① ★ 误差 ∝ 1/√M(判据②,主判据):M = 1/2/4/8/16/32 的真误差依次
0.07979 / 0.05766 / 0.04111 / 0.02963 / 0.02111 / 0.01524;把它们各乘上 √M 得到
0.07979 / 0.08154 / 0.08221 / 0.08380 / 0.08445 / 0.08620 —— 最大/最小 = 1.080,
近乎一条水平线。M 每翻一倍,误差只掉到 71~72%(理论 70.7%);
② ★ 自估的误差与上帝视角算出来的对得上(判据④):M = 2/4/8/16/32 上两者的比依次
0.971 / 0.965 / 0.961 / 0.951 / 0.932(理想 1)—— 所以"我还差多少"在真机上当场就能回答;
③ ★ 噪声减半要抽 4 倍(判据⑤):M 1→4 掉 1.941 倍、M 4→16 掉 1.947 倍、
M 1→16 一共掉 3.779 倍(比理想的 4 略小,因为真误差里混着参考解自己那份);
④ 同一条律在明处暗处都成立,只是常数不同(判据⑥):M = 32 时自估误差
亮带 0.01330、影带 0.02293(影带高 1.72 倍)—— 4.1 那句"越暗越麻"在误差上的样子。
判据八条:① 可复现(同种子两遍逐位相同)/ ② ★ 误差 ∝ 1/√M(主判据)/
③ 画面(写入格子数、非黑、非法值 0、命中面法线朝向来光的哨兵)/ ④ ★ 自估误差可信(主判据)/
⑤ ★ 噪声减半要 ×4/ ⑥ 明暗两带同律、暗带更高/ ⑦ 同源(件一框里那几行 = se41 的正文,重算逐位相同)/
⑧ 参考解够不够(换一份更粗的独立参考解:M = 1 处差 0.5%、M = 32 处差 15.1%,随 M 单调变大)。
★ 如实标:① 4.2 的表在步长 2 的样本网格(与画面同一批像素)上算;
② 两份参考解都是独立的(种子 7777 / 8888,M = 256 / 64)—— 用采样链自己的前缀当参考解会与采样档相关,
那样量出来的曲线是假的;③ 右块灰阶满量程 0.30;④ M = 1 时自估误差估不出来(一条样本没有散布),
本页那一格按 0 画并注明。
4.1 与 4.2 的关系:4.1 的"唯一变量"是 M(滑块),4.2 的"唯一新东西"是一个读数 ——
所以两段的控件逐字相同,读者做同样的动作(拖 M),看到的是新的现象(右块按 1/√M 变暗)。
4.3 这一段只加一样东西:采样怎么排(三档并排,同一个 M)。4.2 把"抽多少"这条路的回报量到了底
(1/√M,翻一倍只掉 29%),于是换一条:不增加条数,只改"往哪儿抽"。
光路本身一字不改(还是 walk41),只换"头两个随机数"从哪来 —— 也就是第一步的方向怎么排:
① 随机(伪随机流,基准)② 分层(第 s 条仰角取 (s + 0.5)/M、方位取 van der Corput 序列)
③ 蓝噪声(同一套铺法,把方位按像素号整体转一个角度)。
件一框里那几行 = sch43 的正文(逐字)。量出来的四件事:
① ★ 铺开比随便撒准(判据②):三档的误差(随机 / 分层 / 蓝噪声)在 M = 2/4/8/16/32 上是
0.05885/0.03661/0.03179 · 0.04119/0.02292/0.02168 · 0.02827/0.01634/0.01639 · 0.02063/0.01292/0.01149 · 0.01483/0.00903/0.00822 ——
每一档分层与蓝噪声都低于随机,到 M = 32 压到 0.61 / 0.55 倍;
② ★ 分层"准但成块",蓝噪声"准且不成块"(判据④⑤,主判据):相邻像素误差的相关系数
随机 0.016 · 分层 0.392 · 蓝噪声 −0.032 —— 而分层与蓝噪声的误差五档平均只差 6.3%。
也就是说蓝噪声换的不是"误差多大",而是"误差长什么样":颗粒从"块"变成"粒";
③ ★ 排法买到的是"常数",不是"指数"(判据⑧):三档的 log-log 拟合斜率
−0.498 / −0.487 / −0.482 —— 都压在 4.2 量到的那条 1/√M 上。铺开第一步给的是一个
常数折扣(0.61 倍 ≈ 省下 2.7 倍采样数),不是更陡的收敛曲线;
④ 换排法不动答案(判据⑥):三档在 M = 32 时的平均亮度 0.68561 / 0.68563 / 0.68633,
最大相对差 0.10% —— 排法只改"误差多大、长什么样",不改"期望是多少"。
判据八条:① 可复现(三档各跑两遍逐位相同)/ ② ★ 铺开比随便撒准/
③ 画面(写入格子数、非黑、非法值 0、命中面法线朝向来光的哨兵)/ ④ ★ 分层成块、蓝噪声不成块(主判据)/
⑤ 分层与蓝噪声误差一样(同一套点集,只差一个方位旋转)/ ⑥ 换排法不动答案/
⑦ 同源(件一框里那几行 = sch43 的正文,重算逐位相同)/ ⑧ ★ 买到的是常数不是指数。
★ 如实标:① 本段只把头两个随机数换成排开的版本,光路后面十几维仍然随机 —— 这正是判据⑧的原因;
② 三档各自用独立的随机流(种子按档号与样本号派生),保证"排法"是唯一变量;
③ 相邻像素相关系数在样本网格上算,"相邻"= 相距 2 像素,用 M = 16 那一档;
④ 三档共用同一个靶子(4.2 那份参考解,M = 256、另一套种子)。
4.1 / 4.2 / 4.3 的关系:4.1 的唯一变量是 M(滑块);4.2 的唯一新东西是一个读数(自己估的误差);
4.3 的唯一新东西是三档排法(三块并排)—— 三段控件逐字相同,读者做同样的动作(拖 M),
看到的是三件新事情:一条光路只是样本、误差按 1/√M 落、排法只买常数不买指数。
★ 与前几课共享同一个场景(同一组盒子坐标与高度、同一个太阳高度角与方位约定、同一套天色)——
所以"这是同一个世界,只是第一次让光自己走"这句话是能对上的。
★ 如实标:① 本页是 CPU 路径追踪器(逐像素自算),不依赖 WebGPU;
② "直接光"那一份单独写成了 direct41(只取第一个可见点自己收到的太阳与天)再与总账相减 ——
它不能拿 walk41(hmax = 1) 冒充:那一条还会在邻居身上再问一次太阳,
带回来的是"弹过一次"的光(本页第一版正是这么写的,判据④把它抓了出来);
③ 太阳用显式阴影线抽样,所以太阳那一份不带噪声,噪声全部来自"下一步往哪拐";
④ 白墙 ρ = 0.85(与 3.3 同一个数);⑤ 每条光路最多走 4 步;
⑥ 两条带按"第一个可见点晒不晒得到太阳"分,本页影带 153 格 / 亮带 2007 格(相机朝下看、地面敞着)。
| 看不到新内容时请硬刷新(Ctrl+Shift+R),或给地址加 ?t=N —— 本站的 HTML 不带缓存指令。