着色不是「给表面涂颜色」,而是解一个积分:对每个着色点,把所有入射方向的贡献按 BRDF 加权累加。 PBR 的全部内容就是——怎么把这一个积分算得既接近物理、又跑得动。 这个课题沿着一代代模型走:每一代都是对同一个积分更好的一次近似。
本节点在骨架的下一环 —— 前四课把「光从哪来、这一点怎么反射、怎么把被挡的光扣掉」一路算到了能出图。可这四课里有一件事从头到尾没被问过:表面朝各个方向反射得一样吗。
到上一课为止,那个积分里能调的只剩下一根滑块:粗糙度 σ。它有两个特点 ——
① 它是一个数;② 它不分方向:把 σ 调小,高光瓣就四面均匀地收紧成一个圆点。
于是四课下来,画出来的东西永远是「像塑料」:一颗球、一个圆亮点,翻来覆去都一样。
可真实的表面不是这样:拉丝金属的高光是一条横着的亮线、缎面是一道斜的光带、
唱片和 CD 的彩虹环、被拉的头发与兽毛 —— 它们的高光都不是圆的。
原因很朴素:这些表面的微观起伏有走向 —— 顺着一个方向划痕很长、横着很密。
所以「粗糙度」根本不该是一个数,它沿两个方向可以是两个数。
本段只增加一样东西:把粗糙度从一个数拆成沿两个正交方向的两个数(αT 与 αB)。
它要两档控件才说得完 —— 各向异性强度(两个数差多远)与拉丝方向 φ(这两根轴朝哪)——
但它们是同一个变量的两半,不是两个变量。
其余控件与第 3 课那一组完全相同:光照项、光源方向、粗糙度 σ、高光怎么算、高光瓣归一。
第 4 课那三档(可见性、半影角、深度图分辨率)本段整个收起来 —— 那是「挡不挡」的事,
与本段的正题(被积函数自己长什么样)无关;只把 4.1 那档硬射线的可见性原样留着,
让场景与上一课同框(球 + 地板 + 球投下的那块影),读者不必重新认路。
有一处必须说清楚,否则本段的数字会被误读:σ 一个数没变,它管的还是「瓣整体有多大」;
本段的 a 只管「瓣被拉成多扁」。做法是让两个方向上的指数乘起来恒等于 σ 那个指数
(几何平均分账,见件三 ②),于是把 a 从 0 拖到最大,瓣的总面积一点不变、只换形状 ——
峰值跟着下降,因为同一份能量摊到了更大的面积上。这条「面积不变」是本段的主判据。
n,而是 ne / m。
m 是这一点的方位角 cos²φ 在两个方向上的加权:
c2 = tt²/(tt²+bb²)(tt、bb 是半向量 h 在切线系里的两个分量),
于是 h 落在拉丝方向 T 上时 m = ax、落在垂直方向 B 上时 m = ay,
其余方位取两者的加权平均。因为 ax · ay ≡ 1(两个方向上的指数乘起来 = ne²),
把 a 拧大只是把 m 从一个 1 摊成一对倒数,指数在几何上一样大。
框外还有两行:fn tanDir(n)(把世界方向 X(φ) 投影到这一点的切平面上,得到 T;
n 与 X 平行时退化成 cross(n, 上))与 let wgt = select(1.0, u.anis.z, u.view.w > 0.5);
—— u.anis.z 就是这一档的归一因子 Cn(件三 ③ 给出它为什么不再等于各向同性那个 (ne+8)/(8π) 了)。
右列第三个「Cn」是这张图上真正的结果:瓣被拉长以后,同一个白炉口径要在更大的面积上摊开,
峰值只能降下去(不带权重的那条面积五档恒为一个常数,见件三 ③)。框里最后一行 let vis = shadowVis(wp, l); 是第 4 课那条可见性 ——
它在框里原样出现,就是为了让读者看见它一行都没动。
下面这张小图只说一件事:瓣被拉成什么样。
它把瓣本身画出来(不是画面上的光斑):极角 = 偏离中心多少度,极径方向 = 方位角,
那两条曲线是「亮度掉到峰值一半」的等值线 —— 也就是把 cos θ½ = 0.5m/ne
对每个方位角解一遍得到的轮廓(与件三 ② 同一份算式)。
虚线圆是各向同性档(a = 0):它的半径处处等于 14.93°(只随 σ 变)。
实线是本档(a = 0.85):沿 T 半角涨到 27.91°、沿 B 缩到 7.90° ——
两条半轴的比值 3.54(1/aspect = 3.60)。
图上的面积别去比:极径画的是半角、不是瓣的密度,这两条曲线围出来的极坐标面积本来就不该相等;
「形状换了、总量没换」那本账在件三 ③ 的 ∫lobe dωh 那一列(五档恒为同一个常数 0.3326)。
图上那两个小方块就是 T 与 B 上的半角刻度 —— 拖着 a 或 σ 动,它们会一起动。
右列三个数是同一件事的三段:沿 T 的指数、沿 B 的指数、归一因子 Cn。
前两个就是形状因子 m 取两个极端值时的指数(m = ax ⇒ ne/ax;m = ay ⇒ ne/ay),
中间那几行 tt、bb 是半向量 h 在切线系里的两个分量(平方和 = 1 − (n·h)²),
c2 把它们的方位角压成一个数,mm 再按 ax / ay 加权 —— 指数就是 ne/mm。
默认档(σ = 0.30、a = 0.85、φ = 30°)三个数是:5.605 / 72.784 / Cn = 0.6222,
而 m 本身随 h 的方位在 0.278 ~ 3.604 之间连续滑动;
把「各向异性」切回关:两个指数立刻并成同一个 20.1976(= ne)、Cn 回到 1.1219(= (ne+8)/(8π),
与第 3 课那个常数逐位相同)。同一个 a,Cn 从 1.1219 掉到 0.6222,就是「瓣更宽了、峰值只能更低」。
而它的账是平的:各向异性只把瓣摊开 —— 不带权重的面积五档恒为 0.3326,
带权重的白炉口径只降不升(各向同性 1.0604 → 各向异性 0.8159,见 ① 表那一行)。
先切到「各向同性」。整颗球与你第 3 课看到的逐像素相同:球面上一个圆高光点,
右下读数给出「指数 20.2 · Cn 1.1219 · 比值 1.00」。
再切回「各向异性」(a = 0.85):那个圆点被拉成一条短亮线 ——
这不是换了一种颜色,是同一份能量换了形状:读数的「比值」跳到 3.54、
Cn 从 1.1219 掉到 0.6222(降 45%),
球上高光像素从 10423 涨到 17074;唯一一动不动的是件三 ③ 那一列 ∫lobe dω_h ——
五档都是 0.3326。面积守恒、峰值下降、斑变大 —— 三件事是同一件事。
读数里那个「长宽比」要留意量在哪儿。件三 ① 的那一行把它量了两次:
曲面角坐标(把斑摊回球面自己)与屏幕坐标。默认档两个数是
各向同性 1.022 / 1.385、各向异性 2.216 / 2.372。
各向同性档的真值明明是 1.000 —— 曲面那个只差 2.2%,屏幕那个差了 38%:
那 0.363 全是球面投影与透视的账,换到曲面坐标就被抵掉了。
剩下的一截(2.216 对瓣本身的 3.535)来自两件球上躲不掉的事 ——
球面切线场在斑内会转、n·l 在斑内不恒定。要瓣本身那个数,看件三 ②③。
再拖两个角度。强度 a 只管「扁到什么程度」:从 0 拖到 0.95, θ½(T) 从 14.93° 涨到 33.21°、θ½(B) 从 14.93° 缩到 6.58°,比值从 1.0000 一路到 5.0475; 但 σ 一个数没动 —— 所以「瓣整体多大」没变,只有形状在变。 拉丝方向 φ 只让那条线转方向:φ 从 0° 转到 90°, 量到的主轴角从 7.10° 转到 74.16°(单调跟着转;但屏幕上量到的角度 不等于 φ 本身 —— 球面切线场与透视一起把它挪了,见件三 ① 那一行)。 把 a 拖回 0,或切到「各向同性」,画面与第 3 课逐像素相同 —— 这是本段的还原性判据。
最后拖「粗糙度 σ」。它会同时改变两个方向上的粗糙度(两个指数一起变大)—— 所以 σ 管的是瓣整体多大,a 管的是瓣多扁。两件事分开, 这正是本段把粗糙度从一个数拆成两个数要换来的东西。
先在「本段新增」那一档来回切:注意看球面上那个高光点 —— 各向同性时是圆的(读数「瓣比值 1.00 · Cn 1.1219 · ∫lobe dω_h 0.3326」), 各向异性时被拉成一条短亮线(比值 3.54 · Cn 0.6222 · ∫lobe dω_h还是 0.3326)。 再把「各向异性强度 a」从 0 慢慢拖到 0.95:线越来越扁,而 Cn 一直往下掉 —— 掉多少,斑就摊开多少。最后拖「拉丝方向 φ」走一圈:线转方向,长短不变。 还要看件三 ① 的那一行:同一个斑的长宽比被量了两次(曲面角坐标 / 屏幕坐标), 各向同性档是 1.022 / 1.385 而真值是 1.000 —— 差的那些全是"量在哪儿量"的账。 想核数的话,件三 ② 是沿 T 与沿 B 两条剖面的逐格扫描,件三 ③ 是五档 a 的正交对照。
| 项 | 值 | |
|---|---|---|
| β | 沿 T:m / lobe | 沿 B:m / lobe |
|---|
| a | aspect | Cn | θ½(T) | θ½(B) | 比值 | ∫lobe dωh |
|---|
base = cos β,
沿 T 时 m = ax、沿 B 时 m = ay,于是
lobe = Cn · basene/m。这个指数是要命的地方:
本档 σ = 0.30 ⇒ ne = 2/(σ²+1e-4) − 2 = 20.1976;
a = 0.85 ⇒ aspect = 1 − 0.85·a = 0.2775、ax = 1/aspect = 3.6036、ay = aspect = 0.2775。
于是沿 T 的指数是 ne/ax = 5.605(很平、亮得远),沿 B 是 ne/ay = 72.79(很陡、掉得快)——
同样偏离 12°,沿 T 还剩峰值的 88.3%、沿 B 只剩 20.0%(差 4.4 倍);偏离 24° 时是
60.2% 对 0.14%(差 430 倍)—— 两条曲线越往外差得越离谱,「一条线」这件事就没有别的解释了。
表尾那一行给出半角:把 cos θ½ = 0.5m/ne
解出来就是 θ½(T) = 27.912°、θ½(B) = 7.895°,比值 3.5354。∫lobe dωh 那一列五档恒等,都是 0.3326 ——
瓣被拉扁以后,面积一分没变(构造出来的:ax·ay ≡ 1,加上归一因子按面积闭式的比值等比压低:
Cn = (ne+8)/(8π) · Jiso/J,其中 J = 1 − ne/√((ne+ax)(ne+ay))、
Jiso = 1/(ne+1) 是各向同性档那个值,见下)。
于是 Cn 那一列只能往下走(1.1219 → 0.4711):面积守恒的意思就是峰值必须让路。
有两条容易被读错的地方,说清楚:
① 不带权重那条面积恒等的常数不再是 1,而是 (ne+8)/(4(ne+1)) = 0.3326 ——
因为归一因子已经挂在白炉口径上(a = 0 时逐位等于第 3 课那个 (ne+8)/(8π)),
第 3 课那个常数也含在这个乘积里;恒等的是「五档同一个数」,这才叫「只换形状」。
② 带权重的白炉那条口径随 a 只降不升(默认档 各向同性 1.0604 / 各向异性 0.8159)——
权重把靠近峰值的部分看得更重,而各向异性正好把峰值摊低了。方向是变小:
各向异性不会凭空多发能量(验收判据 ① 把这一条也钉住了)。
比值那一列与 1/aspect 的偏差随 a 增大(−0.21% → −2.84%)——
因为 θ½ 与瓣宽不是严格成正比的(θ½ ≈ √(2ln2·m/ne) 只是小角度近似),
偏差本身也是这个近似带来的,不是算式写错了。sp ≥ ½ 峰值 的像素取出来算二阶矩,
而且量两次 —— 屏幕坐标与曲面角坐标(以瓣心 h* 为极点,把斑摊回球面自己)。
各向同性档给出一对最有说服力的数:曲面 1.022 / 屏幕 1.385 —— 真值明明是 1.000,
曲面那个只差 2.2%,屏幕那个多了 38%:那 0.363 全是球面投影与透视的账,
换坐标系就抵掉了。各向异性档是 曲面 2.216 / 屏幕 2.372,
与瓣本身的 3.535 还差一截 —— 那一截来自两件在球上躲不掉的事:
① 球面切线场在斑内会旋转(hairy ball:球面上不存在处处非零的连续切向量场),
② n·l 在斑内不恒定,把斑在背光一侧压小。
所以「球上量到的比值」只能当相对读数用,与瓣本身不声称相等(验收判据 ⑤ 就是这么钉的);
要瓣本身那个数,看 ② ③。贴边像素(落在球面轮廓上、会让二阶矩偏一点的那些)也在读数里如实报出。n·l 与 n·v 同时取到极值、两个余弦梯度都为零,投影也退化成各向同性 ——
屏幕坐标那个读数从 1.385 掉回 1.002。同一个斑、同一份算式,只是把光挪了个位置:
那 0.363 当场兑现成「投影与余弦梯度的账」。反过来,把 φ 从 0° 扫到 160°,
各向同性档一动不动恒为 1.023(φ 不该有影响),而各向异性档在 1.61~2.18 之间摆 ——
这就说明那个读数被切线场的几何主导,不是被瓣主导。m ≡ 1、Cn = (ne+8)/(8π) = 1.1219,
与第 3 课那条算式逐位相同(离线复算:两式的逐点最大差为 0,Cn 完全相同)。
知道「各向异性」在这条链上可以落成一个很克制的改动:把高光指数从一个数换成一个随方位角变的数
(ne → ne/m,m = cos²φ·ax + sin²φ·ay),别的什么都不用动。
默认档(σ = 0.30、a = 0.85、φ = 30°)球面上那个圆高光点被拉成一条短亮线:
沿 T 半角 27.91°、沿 B 7.90°、比值 3.54。
最值钱的一条其实不在各向异性本身,而在「量在哪儿量」:把同一个斑量两次 ——
屏幕坐标与曲面角坐标(摊回球面自己)—— 各向同性档得到 1.385 / 1.022,
而真值是 1.000:曲面那个只差 2.2%,屏幕那个多了 38%。同一个斑,换个坐标系,
多出来的那 0.363 就没了 —— 那是球面投影与透视的账,不是材质的账。
各向异性档是 2.216 / 2.372,与瓣本身的 3.535 还差一截,那一截来自
球面切线场在斑内会转(hairy ball)与 n·l 在斑内不恒定 ——
球这个载体的固有代价,本段如实报出、不声称相等。
还看到最有用的那条账:把 a 从 0 拖到 0.95,∫lobe dωh 五档恒为同一个常数 0.3326,
而 Cn 从 1.1219 掉到 0.4711、θ½ 的比值从 1.0000 涨到 5.0475 ——
形状换、总量不换,代价全记在峰值上(降 45% 那一步就在默认档)。
这里的「总量不换」说准一点:恒等的是不带权重的那条面积(∫lobe dωh),
它的常数不再是 1 —— 因为归一因子已经挂在白炉口径上(a = 0 时逐位等于第 3 课那个
(ne+8)/(8π))。而带权重的白炉那条口径随 a 只降不升
(只测高光那一项:各向同性 1.0604、各向异性 0.8159),方向是变小 ——
各向异性不会凭空多发能量。这条也被验收判据 ① 钉住了。
也才知道 σ 与 a 必须分家:σ 是一个数、管瓣整体多大;a 是一对倒数、管瓣多扁。
本段把这两件事分开的做法是让两个方向的指数乘起来恒等于 ne²(几何平均分账)——
这样 σ 一根滑块的行为与第 3 课完全一样,a 才有资格单独说「我只改形状」。
还看到一个边界:本段只把粗糙度拆成了两个正交方向上的两个数,
两个方向之间还没有任何耦合 —— 真实拉丝金属顺着划痕方向还会有一道反向的拖尾
(「顺着光看更亮」的那种),本段答不了。
那件事要等叠第二层:表面之上再来一层薄薄的、自己带高光的膜 —— 清漆。
那是下一段的事。
本节点在骨架的下一环 —— 这一段是全书唯一一次把两个被积函数摞在一起:上一段的瓣算的是「一个表面怎么反光」,可最亮的那类漆面(汽车、钢琴、手机背板)根本不是一个表面。
到上一段为止,「表面」始终被当成一样东西:一个法线、一份粗糙度、一枚高光。
可你只要摸过一次车漆就知道不是这样:它有两层性格 —— 正面看是沉闷的深色(光透进颜料层,
被底层的粗糙反射糊成一片),换个角度掠着看,边缘却突然变成一面镜子(光来不及进去,
先被最上面那层光滑的膜弹回来)。同一个表面、同一个光源,两枚高光在打架。
本段只增加一样东西:在表面之上再叠一层薄而光滑的膜(清漆),两层各自反射、菲涅尔各算一次。
控件与上一段完全相同(光照项、光源方向、σ、高光模型、归一、a、φ),
只多一档「清漆强度 c」。膜的粗糙度 σc 固定成常量 0.10 ——
那不是一个变量,是这一层膜的「材质」:它就是薄而光的。
账要一笔一笔走,否则会被误读:光先过膜 —— 膜这次反射掉 Fc,
剩下的 (1 − Fc) 才透进底层;底层照旧算自己的漫反射 + 自己的高光,
但要乘 (1 − Fc);膜自己那枚高光按膜自己的粗糙度铺开,所以它又紧又亮。
因为 Fc + (1 − Fc) ≡ 1,这条分法逐方向不超预算 —— 白炉门禁钉的就是这一条。
把 c 拖回 0,这一页必须逐像素回到上一段:这是本段的还原性判据。
WGSL52 并不是另抄一份,而是把这段插进 WGSL51 的高光收尾那一行之后拼出来的 ——
公共部分(几何、可见性、漫反射、菲涅尔)永远只有一份,改一处两段同时生效
(lesson-04 当年整份拷贝,改一处要改三遍,是踩过的坑)。所以「框里与件二逐字一致」这件事
在这里不是靠人盯,而是构造上就不可能不一致:框里这 7 行就是拼出 WGSL52 的那个数组
COAT52LINES 本身(有 3 行太长,为放进框里按显示宽度折了行)。
逐行的账:hc 是半向量(和 5.1 里那个 h 是同一个东西,这里再算一遍是为了让框里这段能独立看懂);
odc = 1 − l·hc 就是 1 − cosθd;Fc 是膜的菲涅尔
(0.04 + 0.96·(1−cosθd)⁵,介质膜:与波长无关,所以它那枚高光是白的);
c = c * (1.0 - Fc) 这一行把已有的全部颜色(环境光 + 漫反射 + 底层高光)
乘上透射率 —— 光要先过膜;最后一行叠上膜自己那枚:u.coat.z 是膜的 Cn、
u.coat.y 是膜的指数(由 σc = 0.10 定,与本档的 σ 无关)。
右列三个数与件三、与画面同源。
先把「清漆强度 c」从 0 拖到 1,来回两遍:注意看球面上那枚高光 —— c = 0 时它是上一段那条被拉长的亮线(拉丝金属);c = 1 时它并没有变宽,反而收紧成一个又小又白的圆点, 而且颜色从底层的暖色变成无色。原因是膜那枚比底层亮 13.1 倍(件三 ① 的「膜峰值」), 而且膜是各向同性的(σc 是一个数,不分方向)—— 所以它把上一段辛苦拉出来的那条线盖回成一个圆点。 这就是真实车漆上「清漆盖过拉丝」的样子。
再盯球的边缘与远处的地板:c = 1 时它们会泛起一层镜面反射。 这是膜的菲涅尔在掠射角上冲向 1 —— 件三 ② 那张表就是它的手算版: 正面 Fc = 0.04000(96% 透进底层)、60° 0.07000、75° 0.25473、85° 0.64849、89° 0.91910 (只剩 8% 进底层)。正面是漆、侧面是镜,两件事同一个公式。
n·v > 0 的占比与上一段同口径,同样必须是 100.00%。
| 项 | 值 | |
|---|---|---|
| θd | cosθd | Fc | 底层还剩 |
|---|
| c | Fc | 底层峰值 | 膜峰值 | 底层还剩 |
|---|
θ_d(半向量与光的夹角),cosθ_d 是它的余弦,
F_c = c·(0.04 + 0.96(1−cosθ_d)⁵),最后一列是 1 − F_c。
注意 0° → 85° 之间它才涨了 16 倍(0.04000 → 0.64849),
而 85° → 89° 这 4° 又涨了 42%(0.64849 → 0.91910)—— 掠射那一小段才是膜真正接管的地方。
③ 是把 c 摆成五档看分层账:两列都随 c 线性走(底层峰值乘 (1 − Fc)、膜峰值乘 Fc),
所以拿笔按比例一算就能核。① 里那一行「还原性」是本节最要紧的一条:
c = 0 时必须与上一段逐像素相同(最大差 = 0.000e+0)。
本段只加了一层膜,就把「一个表面」变成了两层:
本节点在骨架的收束环上 —— 上一段给「一个表面」叠上了第二层(膜),可到此为止,这一路的旋钮是按物理量各起各的名字的:σ、a、φ、c、F0。没有一个做材质的人会这么配参。
把前面三段连起来看就发现问题了:1.1 里调的是「光源形状」,2.x 调的是「漫反射/高光模型」,3.x 调的是「预算怎么分」,
5.1 加了「沿两个方向的粗糙度 a 与拉丝方向 φ」,5.2 加了「清漆强度 c」。
这些量都对,可它们的名字是物理学家起的——量纲各不相同(角度、比例、无量纲强度),
而且谁也说不清「把皮肤调得更像皮肤」要动哪几个。工业界的答案是把它们收进一张表:
每个格子一个名字、一个范围、一个直觉含义,而表里每个数最终都落到你已经见过的那一项上。
本段只增加一样东西:一张命名参数表(Disney 的 Principled 那一套),把前面的旋钮改名收编,并补上表里前面没有的三个。
控件与上一段相同的两处(光照项、光源方向)一字不动;上一段那些「按物理量命名」的旋钮(σ、各向异性 a、清漆强度 c)
不是消失,而是换了名字落进这张表:roughness / anisotropy / clearcoat。
表里真正新的只有三个:metallic(把漫反射那一份搬进高光,并让高光带上底色)、
specular(绝缘体高光的绝对大小)、sheen(掠射的边缘光晕)。
判据只有一条,但它最要紧:把表摆回上一段的档,这一页必须逐像素回到 5.2 ——
这张表是同一份被积函数的重新参数化,不是新的物理。而它不守恒这件事也照实写在下面(件三 ②)。
WGSL53 的那个数组
(COAT53LINES)本身 —— WGSL53 不是另抄一份:它拿 WGSL52 把两行换掉、
再在膜那几行之后插一行得到,所以「框里与件二逐字一致」在这里同样是构造上成立的。
逐行的账:第一行给漫反射乘 (1 − m) —— 金属没有透进内部的漫反射,那一份要退场;
第二行把高光的色调从「高光专用的冷色」stint 混向底色 dtint ——
所以 m = 1 时高光自己带上底色(这就是金与塑料最直观的差别);
第三行是新加的一枚 sheen:(1 − cosθd)⁵ 只在掠射角上抬起,只加不减 ——
这一行就是件三 ② 里「账被往上推」的那一笔。
表里另外四个名字(roughness / specular / clearcoat / clearcoatGloss / anisotropy)
不在这里出现,因为它们只是改名:它们映射到 5.1/5.2 已经有的 uniform 槽位,一个像素都不用改。
把 metallic 从 0 拖到 1,来回两遍:注意看球面正对光源那一片 —— 它整体暗下去(漫反射按 (1 − m) 退场),同时高光那一枚换了颜色: 从 5.2 里那种偏冷的白变成底色的暖。这就是「金属与塑料」最直观的差别 —— 金属没有透进内部的漫反射可用,它能反射的只有自己的底色。件三 ① 里「漫反射份额」与「F0」两行 会随这个滑杆反向走(加起来恒等于 1)。但别把这句读成「总量没变」:搬走的那一份并没有被高光接管 —— 件三 ② 的白炉会因此往下掉,而下面那个 sheen 又会把它往上推,两个方向都没人补。
再把 sheen 从 0 拖到 1,看球的边缘:一圈很薄的灰白晕从轮廓上浮起来, 球心几乎不动 —— 因为它按 (1 − cosθd)⁵ 走,正面是 0、掠射才抬。这是织物(天鹅绒、麂皮)的观感来源。 然后看件三 ② 的白炉那一行:它会往上走一小截(0.3080 → 0.3416,+10.9%)。 这不是本页算错 —— 它是这一段的结论: 这张表的 2012 版并没有把多次散射补回来(Disney 自己在 2015 年补、Imageworks 在 2019 年给出了闭式的补偿项), 所以「参数表是艺术接口,不是物理接口」这句话是可以量出来的 —— 两个新旋钮把账往相反方向拉: 一个搬走 97.7%、另一个只补 10.9%,而 2012 版谁都不补。
metallic = 0 · sheen = 0 · clearcoatGloss = 0 ·
specular = 0.5 · roughness = 0.30 · clearcoat = 1 · anisotropy = 0.85 时,
本页的着色算式与 5.2 的逐方向相同(最大差 = 0.000e+0),画面也必须逐像素一致(件三 ① 的最后一行在报这个数)。
| 参数 | 它改的是哪一项 | |
|---|---|---|
| 档 | 白炉 ∫ρ·cos θ dω | 结论 |
|---|
roughness 就是 5.1 那根 σ、anisotropy 就是那根 a、
clearcoat 就是 5.2 那根 c;只有前三行是表里新的。
最后一行的「与 5.2 的逐方向最大差」是这一段的还原性判据 —— 它必须是 0.000e+0。
② 白炉是第 3 课那条账:这一列是本页自己做的半球积分(θ 走半球、φ 走满圈、测度
cosθ·sinθ dθ dφ),算的是同一份着色算式的出射量,所以三行之间可以直接比 ——
但它的取样比 5.1/5.2 那条 rho0 口径粗(16×16),所以看方向与比值,不必对绝对值较真。
要点在这里:metallic 把漫反射那一份搬走,
而高光那项并不会接管它 → 账往下掉(0.3080 → 0.0072,掉 97.7%);
sheen 是只加不减的一项 → 账往上走(0.3080 → 0.3416,补回 10.9%)。
两个新旋钮把账往相反方向拉,2012 版里谁都不负责补回来(Disney 2015、Imageworks 2019 才给出补偿项)——
所以「参数表是艺术接口,不是物理接口」不是一句态度,而是一个可以量出来的缺口:
搬走的那一头补得少近十倍(97.7% 对 10.9%),账是往漏的那一边倒的。
本段没有加任何新物理,只把前面四段学到的旋钮收进了一张有名字的表:
roughness / anisotropy / clearcoat / clearcoatGloss
分别就是 5.1 的 σ、a、5.2 的 c 与膜粗糙度;摆回上一段的档,画面逐像素回到 5.2。metallic 把漫反射那一份搬走(高光不接管它)、
specular 决定绝缘体高光的绝对大小、sheen 在掠射角上加一枚只加不减的光晕。跑不起来先看设备要求:活例由真 GPU 出画面 —— 手机需 Android 12+ 且 Chrome 121+,或 iOS / iPadOS 26+;电脑需 Chrome / Edge 113+ 或 Safari 26+。Android 上取不到适配器多是设备不支持 Vulkan 1.1+,会自动改走兼容模式(需 Chrome 146+)。不满足时画面区会写出原因与自查步骤,同一页的示意图与数值表照常可读。