一个着色点接收到的光,有一部分来自别的物体反射的光;而别的物体,又接收到它反射的光。 要算清这一点,只能在场景里采样 —— 而一旦靠采样,就永远受 1/√N 支配。
这条骨架把 GI 收成三件事:在哪采样(探针 / 像素 / 路径)、采几次(一次反弹 / 多次反弹)、 怎么排(随机 / 分层 / 蓝噪声)。本课先把"不采样"的那一头量清楚 —— 因为它是最便宜的一刀,也正好定义了后面所有采样法的靶子:这一刀错在哪,就必须在哪采样。
上一课(课题三第 7 课)我们把入射光从「一盏灯」换成了一整张环境图。 可那张图画的全是「外面」—— 天、地、远山。它对这个着色点近旁的东西一无所知: 椅子挡住的、墙角里藏着的、桌腿根部那一圈,在环境图里压根不存在。
而现实里最亮的地方常常正是那些地方:墙角、缝里、物体贴着地面的那一圈。
那些位置直接光最少,那里的光是从别的物体上跳过来的 —— 这就是全局光照。
可这一项是个积分,而且它递归:要算 A 收到多少间接光,得知道 B 反射了多少;而 B 反射多少,
又取决于 B 收到的间接光…… 于是第一刀不是"算准一点",而是把递归砍掉:
假设「别处反射来的光」在整个上半球上是同一个数 Lamb。
递归一断,问题就只剩一件纯几何的事:这一点平均能看见多少天。
本段只增加一样东西:把"别处反射来的光"当成一个各方向相同的常数。三件反直觉的事:
① AO 不是阴影:它没有光源、没有方向,只认几何 —— 所以把太阳拖到任何方位,它逐位不动
(判据①),而阴影会跟着跑。这一条也是它的说明书:它答的是"挡掉了多少方向",不是"挡掉的是哪些方向"。
② 它便宜的原因和它出错的原因是同一句话:正因为把那个积分换成了常数,
一个像素只需要一次乘法(判据③量的就是这个"乘法"的字面意思);
也正因为如此,它天生不知道邻居是什么颜色、有多亮。
③ 换来的画面会"看起来对了,但很平":阴影被填上了、缝里暗下去了,可是每一处暗下去的理由都一样 ——
没有一处被邻居染上色。那正是 1.2 要补的东西。
保真度如实标「示意 · 等价重现」:本页的场景是程序化的高度场,AO 按下面写明的算式逐像素重现,
件一框里那几行就是件二真正在跑的。
Lind = Lamb × AO。
α,
那条方位上"看得见"的仰角就是 θ ∈ (α, 90°];而余弦加权的权重是 cosθ sinθ dθ,
积出来是 (1 − sin²α)/2 = cos²α/2,除以平地那一份(1/2)正好是 cos²α。
所以仰角方向上是闭式、没有任何离散误差,唯一在离散的是方位 —— 判据⑤量的就是它。
① 先只看左半(只直接光):地上那块黑是盒子投下的硬阴影,边界锐利、有明确方向。 拖太阳方位,阴影跟着转 —— 记住它转到哪去了。
② 再看右半(加上这一刀):阴影被填亮了,缝里和盒子根部暗下去。 这时把太阳方位从 135° 一路拖到 300°:阴影跑到另一边去了,而右半那圈暗边一步没动 (判据①报的就是这个"逐位不动")。原因很简单 —— 这一刀里根本没有光源这一项,它只认几何。
③ 把「这一刀」关掉:右半逐字节变回左半(判据②),一个字节都不差。 所以它不是"另一个渲染风格",而是往同一个算式里加了一项 —— 关掉就是那一项为 0。
④ 拖「间接光强度」:填进阴影里的亮度按比例跟着走(判据③:加倍就是精确加倍)。 注意拖到很亮时,贴墙那两处依然最暗(盒 B 根部 0.4865 ≪ 空地 0.9560)—— 因为 AO 把同一份常数按可见度分配,它不区分"这束光是从哪来的",只区分"看得见多少"。
⑤ 换方位方向数(4 → 32):盒 A 根部那一点的 AO 从 0.504 一路走到 0.569, 相对 K = 512 的参考,误差从 9.2% 降到 2.4%(判据⑤)。这个移动不是"精度不够", 而是方位方向的离散误差 —— 仰角方向是闭式的,一分误差都没有。 也请注意它到了 32 个方位还差 2.4%:只要还在用有限条方位,它就永远差一点。
⑥ 看四个点的 AO,它拉成一条链:盒 A 顶面 1.0000(上面没有东西)> 空地 0.9560 (只被远处挡掉一点)> 盒 A 根部 0.5162 > 盒 B 根部 0.4865(它同时被两个盒子挡)。 四个值、四个理由,全部只由几何决定 —— 这正是"它只认几何"的另一面。 顺便说清一件容易想反的事:贴着一堵高墙时,挡住的是"半个方位扇区",所以 AO 约等于 0.5, 而不是接近 0;真正把它压到 0.35 的是几个方位同时被挡的地方(判据⑦报出全场最暗 0.3544)。
左:只直接光(阴影是黑的) | 右:加上这一刀
启动中…
五个控件里只有前两个是"调画面"的;方位方向数 / 场景 / 这一刀三个是对照组 —— 它们各自对应一条判据,把这一刀的边界一条条量出来。
定点观察(三步):① 把太阳方位从 135° 拖到 300°; ② 看右半那圈贴着盒子的暗边(不是阴影,是 AO); ③ 结论:阴影整个换了个位置,而那圈暗边一步没动 —— 因为这一刀里没有"光从哪来"这个量,它只知道"哪些方向被挡住了"。 再把「这一刀」关掉,右半会逐字节回到左半:它是一项,不是一个风格。
Lind = Lamb × AO。左半的阴影里是纯黑(直接光为 0),
右半把这一项填进去 —— 现实里的阴影正是被这部分光填亮的,而它便宜到只需要一次乘法。
α,取 cos²α 求平均。
这个量与环境图无关、与太阳无关、与颜色无关 —— 它只读几何。
| 点 | AO | E_ind = L_amb·π·AO | 字节(有直接光) | 字节(阴影里) |
|---|
| K | AO | 与 K=512 的相对差 |
|---|
AO → E_ind → L_o → 字节。
笔算只需三步:E_ind = 0.35 × π × AO、L_o = albedo/π × E、
字节 = clamp(L_o × 2.2) × 255。地面反照率 0.35、盒子顶面 0.62(画面与表里是同一个值);
"阴影里"那一列把直接光那一项取 0,其余不动 —— 所以它减掉的部分可以由上一列算出来。
② K 从 4 到 32:仰角方向是闭式(cos²α),所以唯一的误差来源是方位。
末列的相对差是拿 K = 512 当参考算的 —— 它随 K 单调变小,但不会归零:
只要还在用有限条方位,AO 就不是精确的那个积分。这条"永远差一点"的性质,正是后面采样法的入口。
①里那四个数取自 K = 16(默认档),它比"收敛值"低约 7% —— 两个表是对着同一份算式量的,
差别只在方位条数,这也正是这一段唯一在离散的那个东西。
这一段把 GI 的第一次近似做成了一次乘法,并且量清了它的边界:
Lamb。代价是它没有颜色、没有方向 —— 这是这一刀的定义,不是实现缺陷。AO = (1/K)·Σcos²αk。
这个式子可以笔算、可以逐位核对(平地 α = 0 ⇒ AO = 1),
唯一的离散误差落在方位上(判据⑤)。上一段那一刀把「别处反射来的光」压成了一个各方向相同的常数: 它答对了「这里被挡住多少」,却答不出「挡在对面的东西是什么、有多亮、是什么颜色」。
最容易看出这件事的是颜色:白墙旁边那块地面偏白、红地砖旁边泛红,连阴影里都带着邻居的色。 这在上一段那一刀里结构上不可能出现 —— 那个常数是个标量,它给三个通道乘的是同一个数, 所以无论邻居是什么颜色,画面都只能是一张灰度的明暗图。 本段只增加一样东西:把那个常数换成「按方向去看」—— 从每个方向向外走,撞到谁,就把谁反射出来的光带回来。 三件反直觉的事:① 它不是「更准的 AO」:一次反弹给出的三通道可以不同比, 而 AO 那一路三通道永远同比 —— 判据①把盒 B 单独换成灰色再算一遍,量出这一条路逐位不动、那一条路色度偏移; ② 光的「来路」变成了可以数出来的一份份:某点收到的间接光能按「撞到了地面 / 盒 A / 盒 B」分解, 三份占比之和恰好是 1(判据②,件三表②); ③ 两把刀的绝对量级本来就不一样:常数那把刀的常数是任意的, 所以这一段比的是颜色与来路,不是谁更亮(判据④把「比值」铺开给人看,它不是一个常数)。 保真度如实标「示意 · 等价重现」:场景仍是上一张程序化高度场,一次反弹按下面写明的算式逐像素重现, 件一框里那几行就是件二真正在跑的。
E_ind,以及那个能证明"染了色"的数 R−B。
albedo(q)/π · E_sun · max(0, n·l) · V_sun(q) ——
其中 albedo(q) 是它的反照率。红盒子把绿蓝吸收掉,只把红反出来,所以它旁边那块地面收到的就是偏红的光。
上一段那一刀没有"q"这个东西,自然没有这一维。
① 先看三块的分工:左 = 只直接光(阴影是纯黑),中 = 上一段那一刀(阴影被灰的常数填亮), 右 = 一次反弹(阴影里是邻居的颜色)。三块用的是同一几何、同一个太阳、同一个曝光。
② 盯住盒 B 旁边那一圈地面:右块那里明显泛红,而中块是同一种灰。 原因写在件一框里:中块给三通道乘的是同一个数,它连"邻居是什么颜色"这个概念都没有。
③ 把盒 B 换成灰(件二没有这个开关 —— 判据①在内部换了一次并报出数):右块那一圈的红会消失, 而中块逐位不动。同一处改动,一条路动、一条路不动,这就是"它不是更准的 AO"。
④ 拖太阳方位:右块的染色跟着亮面一起转(被太阳照到的那一面才反光), 而中块那圈暗边一步不动(上一段已经量过这条)。
⑤ 拖方位方向数(4 → 32):右块会粗糙地变化然后稳定;中块几乎不动(它的积分简单得多)。 两者收敛速度不同这件事本身也说明:它们算的不是同一样东西。
⑥ 换成两个盒子:盒 A 与盒 B 各自挡住对方的一部分方向,件三表②把每一趟的归属列全了。 这里有一个量出来才知道的结果:两盒之间那点地面看着被两个邻居夹着,它收到的间接光却恰好是 0 —— 夹着它的两面墙都在影子里(一面背对太阳、一面被挡住),撞上了 39 条方向,没有一条反光。 "有没有邻居"和"邻居反不反光"是两件事。
左:只直接光 | 中:上一段那一刀(常数 × 可见度)| 右:一次反弹(本段)
启动中…
控件与上一段逐字相同(只剩下两个滑块与两个开关):上一段那个「这一刀 开/关」被并排的三块取代了 —— 对照不再需要切来切去,三块永远同时在。
定点观察(三步):① 看盒 B 旁边那一圈地面(红盒子在地图偏右上); ② 对比中块同一条位置;③ 结论:中块那一圈是灰的,右块是红的 —— 同一几何、同一太阳、同一个曝光,差别只在于"间接光有没有去问对面是谁"。 再把太阳方位拖到让盒 B 背光,那一圈的红会明显变淡:反光也要它自己先被照到。
E_ind),
而中块累加的是同一个标量。所以中块永远染不上色,这不是精度问题,是结构问题。
| 点 | 中块(常数×可见度) | 右块 E_ind(R/G/B) | 色度 R−B |
|---|
| 点 | 撞上的方向 · 盒A亮面 / 盒A暗面 / 盒B亮面 / 盒B暗面 | 其中反光的 | E_ind(R/G/B) |
|---|
L_amb·π·AO(一个标量,三通道共用);
右块那一列是 Σ L_out(q)·Δω(三通道分别累加,笔算时要对每个采样方向找一次 q)。
「色度 R−B」那一列是右块三通道里红减蓝 —— 它非 0 就说明染了色,而中块那一列永远是 0。
E_ind 只有 0.0084 / 0.0016 / 0.0016 —— 小,但 R−B 占 81%,是红的。
这一段把 GI 里最容易被看见的那件事装上了:颜色会走。
E_ind 只有 0.0084 / 0.0016 / 0.0016,R−B 却占 81% —— 颜色跟着来路走,不跟着距离走。1.2 那一次"真的跳一次"能成立,全靠一件事:我们手上有整个场景 ——
盒子在哪、多高、哪一面是亮的,trace42 一条线出去就能精确地撞上它。
可这是本页的特权:场景是程序生成的,"全场景已知"在这里是免费的。
真实的实时渲染没有这份几何。它手上只有一样东西:眼前这一屏 —— 每个像素上"最先撞到的那个面离相机多远",一张深度缓冲。 屏幕空间的那些方法(SSAO、SSR)就是这么做的:不去问场景,只在这一屏里找遮挡。 好处是它不需要几何、也不需要加速结构;代价只有一句话:屏幕里没有的东西,它就当不存在。 本段只换一样东西:求交的依据 —— 从「全场景高度场 h(x,y)」换成「眼前这一屏的深度 z(u,v)」。 件一是这件事最省事的写法:两条路共用同一个函数,只有一行不同 —— 调哪个求地平线的函数。 量出来的是三件事(都不是靠猜的):① 屏幕外的东西不参与计算,被切在屏外的那份遮挡凭空消失 (判据①:同一个点 0.6507 → 0.8526);但这一笔有多大,全看你切掉了什么 —— 同一批格子(盒 B 西边那一小块):把这一屏放大到罩住整块场地是 0.0235、默认这一屏是 0.0411 (那 0.0176 就是"只切到空地"的代价)、把盒 B 也切在屏外立刻变成 0.1247(判据②,3.0 倍)。 ② 同一个点、同一份几何,只因为这一屏挪了位置,它的 AO 就变了 —— 1.1 那把刀是"与光无关",这一把刀是"与相机有关"(判据①里参考那一列逐位不动)。 ③ 误差只会偏亮、不会偏暗(判据④逐格验),而且它分成两笔:离散那一笔(走一步查一格、 走多远查多远)随步数与像素加细而收敛;信息缺口那一笔不收敛,加细之后反而更显眼(判据⑤、⑥)—— 屏幕空间的那些方法看上去总"发白",原因就在这两笔里。 保真度如实标「示意 · 等价重现」:本段的"这一屏"取顶视正交,缓冲里存的就是那一点的高度, 这样两条路用的是同一个算法,差别只来自信息源。
T_max = 1.5 就算到头(本场地的对角线约 1.41,够用);
④ 走一步查一格 ⇒ 只会漏掉峰、不会造出峰,所以屏幕空间这一路只会偏亮(判据④逐格验了这一条)。
① 先看左块(全场景):它就是 1.1 那张 AO 图 —— 盒子根部暗下去、空地接近 1。 这是"信息完整"的那一版,接下来所有的锅都要它来背。
② 看中块偏右上的那一圈(紧贴盒 B):它明显比左块同一位置亮 —— 那是本段最大的一笔误差(最多 0.19)。
原因是"一步有多长":沿方位往外走一步是 1.5 ÷ 步数,步数 32 时一步约 0.047,
而盒 B 的西面离那些格子只有 0.01–0.05 —— 一步就跨过去了,那半个天被当成了空的。
把步数走密这一笔就消退(判据⑤量了它):这是精度账,不是信息账。
③ 拖「这一屏的中心 x / y」:那块有数据的矩形跟着走,中块和右块(差)一起变。 而左块一步不动 —— 同一个点、同一份几何、同一个太阳,只有"这一屏在哪"变了。 把这一屏一直拖到盒 B 露在框外:中块立刻整体变亮一大截(判据①:同一个点 0.6507 → 0.8526)—— 盒 B 挡住的那半个天,在屏幕上凭空回来了。
④ 对比一下这两笔的"性格":精度那一笔(②)把步数拉满就会消退; 而③那一笔把步数拉满也不会消退,加细之后反而更容易看见(判据⑤、⑥:同一批格子、步数 64, 盒 B 在屏内 0.0202 / 在屏外 0.1157,差 5.7 倍)。一个是格子不够细,一个是屏外那些东西根本没算 —— 件三表②把它们排在同一张表里,各自的走法一眼可辨。
⑤ 拖「方位方向数」:两条路一起变(它们共用同一张 az)——
这一层的离散误差和 1.1 是同一条,不是本段的新东西。
⑥ 拖「太阳方位」:阴影跟着转,而右块那块"差"的形状一步不动。 屏幕空间的缺口只跟相机有关,跟光无关 —— 它和 1.1 一样,是几何账。
左:有整个场景 | 中:只有眼前这一屏 | 右:两者之差(×10)
启动中…
控件与上一段只多不少:两个滑块与两个开关逐字相同(L_amb、太阳方位、方位数、盒子数),
另加摆这一屏的两个滑块与两个精度开关(步数、像素)—— 它们加起来只是"把这一屏放在哪、多细",
不是新概念:本段只换了一样东西,就是求交的依据。
定点观察(三步):① 看中块偏右上、紧贴盒 B 的那一圈,与左块同一位置比 —— 那边更亮:那是"一步跨过去"造成的(一步约 0.047,盒 B 的西面离它只有 0.01–0.05); ② 把步数从 32 拖到 64 再拖回 8:那一圈随之变淡 / 变浓 —— 它在收敛,这是精度账; ③ 把这一屏的中心 x一直往左拖,直到盒 B 露在框外:中块整体变亮一大截, 而且把步数拉满也消不掉(判据①:同一个点 0.6507 → 0.8526)—— 这一笔是"屏外那些东西根本没算"。
| 点 | 参考 AO(与这一屏无关) | 屏幕空间 AO | 差 | 在这一屏里吗 |
|---|
| 这一屏 | 步数 8 | 步数 16 | 步数 32 | 步数 64 |
|---|
这一段把 GI 里最后一块"免费的东西"拿走了:几何。
本段的活例由本页自己计算(示意 · 等价重现,非硬件产出):不依赖 WebGPU,任何设备都能跑。同一页的示意图与数值表照常可读。
页面版本 v6(v6 = 第 3 段 · 1.3「屏幕空间的边界」上线 —— 本课三段全部上线。
这一段只换一样东西:求交的依据 —— 从「全场景高度场 h(x,y)」换成「眼前这一屏的深度 z(u,v)」。
两条路共用同一个 aoAt43()、只有一行不同(调 ssH43 还是 horizonA),
所以差的每一分都只能记在"信息源"头上。
★ 量出来的东西与"想当然"不一样,两处都照实写进了页面:
① 误差不是挤在屏幕边缘的一圈亮边 —— 同一批格子上,把这一屏放大到罩住整块场地是 0.0235、
默认这一屏是 0.0411(那 0.0176 才是"只切到空地"的代价);而误差最大的是紧贴盒子的那一圈(最大 0.19),
来源是"一步跨过去"(步长 0.047 对盒 B 那面墙的 0.01–0.05);
② 把边界挪到切过盒 B,同一批格子的平均差立刻跳 3.0 倍(0.0411 → 0.1247),
而且步数越细跳得越明显(步数 64 时 5.7 倍)——
所以"边界"不是一圈固定的亮边,它等于你切在屏外的那份遮挡。
判据八条:① 屏幕外的东西不参与(同一个点 0.6507 → 0.8526,参考那一路逐位不动)/
② 边界这一笔全看切掉了什么(同一批格子,只挪 0.02 ⇒ ×3.0)/ ③ 屏外没有数据(中块与右块各只写 4736 格)/
④ 只会偏亮(逐格验:最小差 0.00e+0、最大 0.1917)/ ⑤ 精度那一笔会收敛(罩住整块场地:步数 8→64 一路降;
屏幕像素 64→16 更差)/ ⑥ 信息缺口那一笔不收敛(同一批格子,步数 64 时仍高 5.7 倍,且差距随加细变大)/
⑦ 画面(三块写入格子数、非黑占比、非法值 0)/ ⑧ 同源(件一那几行重算逐位对齐 float32;
参考那一路与 1.1 的 aoAt 逐位相同)。件二是三块并排:整个场景 / 只有这一屏 / 两者之差(×10)。
★ 顺带补上站内的「段链联动」(滚动时更新顶栏段号与轨道高亮)—— 这一页此前没有。
v5 = 第 2 段 · 1.2「让光真的跳一次:颜色是从哪来的」上线。
件三表②与判据②、⑥ 在这一版重做过,起因是一次量出来的可疑读数:
表格第一版按「盒 A 顶面 / 盒 A 墙面 / 盒 B」分三桶,结果顶面那一桶永远是 0。
追下去发现这不是"取样不够密",而是一条几何命题:从低于某个盒子顶面的位置看不到它的顶面 ——
射线要落到顶面得先越过侧墙上沿,可越过上沿那一刻它已经在盒子上面了。所以本段的间接光只可能来自侧墙。
表②因此改成四格「盒A亮面 / 盒A暗面 / 盒B亮面 / 盒B暗面」的计数 + 光的两份占比,并把两个"0"分成了两种暗:
盒 A 那一面背对太阳(n·l < 0,它自己不想接),盒 B 那一面朝着太阳、被盒 A 整面挡住(V_sun = 0,有人挡着)——
结果一模一样,原因完全不同。另加一行"一小片红":贴着盒 A 暗墙的那点地面从远处盒 B 的亮面捡到一点光,
E_ind 只有 0.0084 / 0.0016 / 0.0016,可 R−B 占 81% —— 颜色跟着来路走,不跟着距离走。
判据②换成"两份占比之和 = 1 + 四格计数自洽 + 一个亮面都没撞到的点必须逐位为 0";
判据⑥从"撞地面 0 条"(把分支删了之后的必然,等于没验)换成逐条验那条几何命题:
对每条"想落顶面"的方向,要求它进入底面的时刻 ≤ 升到顶面高度的时刻(即先撞侧墙),漏一条即失败,
并报出这条验法真的在开火(blocked > 0)。顺带把仰角带数 NM 从常量改成可调,
5 → 51 逐次加密复量:两个 0 一直是 0,所以它们是结构性的 0,不是"没算"。
★ 一并纠一处错:上一版描写的 ⑥「地面按无限延伸处理、画面边缘不会凭空变暗」是错的,已删。
本段只增加一样东西:把上一段那个「各方向相同的常数」换成按方向去看 —— 从每个方向向外走,撞到谁就取谁反射出来的光。
于是间接光多出两样上一段结构上做不到的东西:颜色(三通道可以不同比)与来路(可以按"撞到谁"分解)。
件二是三块并排:只直接光 / 上一段那一刀 / 一次反弹 —— 同一几何、同一个太阳、同一个曝光。
判据八条:① 染色(把盒 B 单独换成灰再真重建一遍:中块差 0 个像素、右块差几千个像素;
盒 B 根部 E_ind 的 R−B 在灰时逐位为 0)/ ② 来路可数(光按"撞到谁"分成两份、占比之和 = 1,
归属跟着撞到的面走;四格计数相加 = 撞上的条数)/
③ 线性(太阳强度加倍 ⇒ 间接光精确加倍)/ ④ 不是"更准的 AO"(右块÷中块逐点铺开不是一个常数)/
⑤ 收敛(方位 4→32 对比 K=96)/ ⑥ 两条模型边界(地面只当接收者 · 盒子的顶面根本看不见,逐条验)/
⑦ 画面(三块写入像素数、非黑占比、含色像素占比、非法值 0)/ ⑧ 同源(一次反弹那一路重算对齐 float32 逐位相同,
中块那一路与 1.1 的 aoAt 逐位相同)。
★ 与上一段共享同一张高度场 hgt、同一个 horizonA(判断撞到那点有没有被太阳照到)、
同一个 aoAt(中块)与同一个曝光 —— 三件同源不是口号,是同一份函数在三个地方显示。
★ 如实标:① 盒 B 默认就是红的(为了让你一眼看见染色;判据①在内部把它换成灰再算一遍并用数字报出结论);
② 只算一次反弹,多次反弹是第 3 课的题目;③ 采样是方位 × 仰角中点(默认 K × 5),所以方位条数是唯一在离散的那个量;
④ 两把刀的绝对量级不可比(上一段那个常数是任意的),比的只是颜色与来路;
⑤ 撞到的那一点自己有没有被太阳照到,是查它脚下的位置(一张 256 × 256 的可见性表)—— 对侧墙来说是近似:
矮墙的上沿会比它脚下更早见到太阳。
v3 = 把画面上的字全部移出去 —— 用户第二次报:「已逐像素写入还是遮挡效果」。
v2 只是把两行字拉开距离,可它们仍然压在画面上;而这张画布是一张铺满每一格的 AO 图,
没有留白,字一压就是压内容。现在:分屏说明放画布上方、绘制读数放画布下方,
两者都在正常流里(.hint,不再是 .pane-lbl / .status 叠加层),
画面上一个字都没有;读数顺带并成一行(绘制读数 | L_amb · K · 太阳)。
站内其它课页仍把标签叠在画面角上 —— 那些图的角上是"空天",本页没有这种地方,这是本页与站内基线的有意差异。
v2 = 修一处叠加层撞车(用户报「右边被文字挡住了」):
件二左上那行分屏说明原先 506 px 宽,在 744 px 宽的画布上与右上角读数(193 px、right:14px)
真实相交 8.4 px,把读数开头那两个字压住了。左上那行收成「左:只直接光(阴影是黑的)| 右:加上这一刀」(273 px),
两行之间留出 250 px;去掉的「同一几何、同一太阳」下面 figcaption 里本来就有。
★ 为什么门禁没抓住:check-overlay.mjs 把由 JS 写的那一格建模成 0 宽
(本页 module 在它的 DOM 打桩里要 getContext('2d'),跑不到写标签那一步)⇒ 算出来"不重叠"。
本轮给该门禁补了两条:① 那一格的代表串(SAMPLE 表里原先没有本页),
② 一条间距余量哨兵(同一行两个标签间距 <12 px 记 ⚠,因为它的字宽是估算的,不能信"刚好不重叠")。
负例自测:把旧的长标签放回去,门禁从「0 问题」变成「4 处硬失败」;换回来是 0。
同批还把右下角状态条收短(74 px 高 → 40 px,从 4 行变 2 行):它本来就压着画面右下角,
信息写长一倍就多挡一倍画面 —— 只留门禁要的那两句,其余从 62 字压到 44 字。
v1 = 课题四「全局光照 GI」第 1 课 · 第 1 段 · 1.1「把一个积分压成一次乘法」上线 —— 课题四开工。
这一段把 GI 的第一次近似讲成一次乘法:把"别处反射来的光"换成一个各方向相同的常数 L_amb,
递归就断在这一步;剩下的全是纯几何 —— 这一点平均能看见多少天。地平线角取 cos²α 是闭式
(∫α90°cosθ sinθ dθ ÷ ∫090°cosθ sinθ dθ = cos²α),
所以仰角方向一分离散误差都没有,唯一在离散的是方位。
判据八条:与光无关(太阳方位 0° → 300°,AO 场逐位不动,最大差 0)/ 可关(关掉这一刀 ⇒ 画面逐字节等于只直接光)/
乘法的账(L_amb 加倍 ⇒ 间接项精确加倍)/ 归一化(平地 AO 逐位 = 1)/ 收敛(K = 4/8/16/32 单调逼近 K=512 的参考)/
单调(盒高 0.10 → 0.40,盒根的 AO 单调不增)/ 画面(写入像素数、非背景占比、非法值 0)/
同源(件一读数、件三两张表、件二两块画面走的是同一个 aoAt())。
★ 与课题三 7.2 的关系如实写明:7.2 已经逐位推过 AO 的公式(那里它是环境积分的可见性项 V(ω))——
本段不复推,换的是问法:从"环境积分的可见性"换成"GI 的第一次近似"。
只读本课题也能懂;读过 7.2 的读者可以直接看本段的落点(这一刀结构上做不到 color bleeding)。
★ 如实标的四点:① 场景是程序化的高度场(地面 + 两个盒子),不是导入模型;
② 顶视 ⇒ 盒子侧面没有像素;③ 高度场是 2.5D,没有悬空与底切;
④ 本页不做色调映射(那是课题三 7.3),写像素前只有一次固定的曝光与夹取,并在件一末尾写明。
| 看不到新内容时请硬刷新(Ctrl+Shift+R),或给地址加 ?t=N —— 本站的 HTML 不带缓存指令。