2.3 材质的组合与混合
材质的线性混合只要满足不变量 w_A+w_B==ONE 就仍能量守恒(五组权重实测 65533/65479/65426/65373/65321 全 ≤ ONE,权重和 =2·ONE 时涨到 130854);清漆层朴素相加 78640 越界、按 (1-F) 缩放后 60946 守恒。并用混合材质渲染一帧,跨宿主 sha256 逐字节相同。
category
材质的线性混合只要满足不变量 w_A+w_B==ONE 就仍能量守恒(五组权重实测 65533/65479/65426/65373/65321 全 ≤ ONE,权重和 =2·ONE 时涨到 130854);清漆层朴素相加 78640 越界、按 (1-F) 缩放后 60946 守恒。并用混合材质渲染一帧,跨宿主 sha256 逐字节相同。
把 Lambert、Phong、Blinn-Phong 三种 BRDF 写成全整数:1/π=20861,Phong 归一化 9/π=187749,Blinn 归一化 3/π=62583,指数 (R·V)^16 用 4 次平方。实跑能量:Lambert 65533、归一化 Phong 65321、归一化 Blinn 69886(超过 ONE),未归一化 Phong 只 22800。
把 BRDF 的半球反射率写成固定的 512 方向整数估计:cosθ_k=(2k+1)/128 是精确有理数、方位只用 {0,±1,±√2/2},全程无浮点三角函数。∫cosθ dω 的估计逐位等于 π(残差 0),Lambert 能量 65533(999.9542‰),残差 3。
给定一张「错了的图」,按二分定位法逐级比对覆盖率、法线、albedo 与最终颜色四张缓冲,把偏差锁到管线的某一段。差异数字本身就是线索:等于覆盖像素数说明逐像素操作出问题,只有几十个说明舍入或常数出问题。五个负例各定位到对应阶段,并对「插值后漏归一化」做一次完整演练,从法线图差异 43731 一路定位到漏掉的那一行。
把逐像素着色器的四张中间缓冲各自单独导出并断言:法线模长落在 [65533, 65537]、albedo 通道在 [70,220]、深度沿单三角形单调、覆盖率与解析解逐像素相同(43731 像素、差异 0)。法线图与 albedo 图编码后的 sha256 由 TypeScript 侧逐字节复现。
同一份场景规格在 Python 与 TypeScript 两条 CPU 路径下产出逐字节相同的像素缓冲。把着色器写成可参数化形式,五个负例各只动一处口径——降精度改用除法、插值后不归一化、逐项钳制、1/π 取 20860、albedo 四舍五入——每个都让 sha256 分叉,七个摘要两两不同,退化档复现卷二基线。
把光照拆成环境 / 漫反射 / 镜面 / 衰减四张灰度图,再加一张合成图。故意把衰减写成 r²/(r²+d)(分母忘了平方),衰减通道 43731/43731 个像素全变、最大差 47042,而环境 / 漫反射 / 镜面三通道逐字节相同——缺陷被精确定位到衰减那一行。
点光源衰减改成有限支撑的 (r²−d²)/(r²+d²),才让「哪些光源影响哪个像素」成为一条整数谓词。两级剔除:逐像素距离阈值 + 16×16 网格分桶。N=64 时循环 3031360→380842、完整求值恒为 72576、两版逐字节相同;代价模型 25702400→4498256 ops(比例 0.1750)。
三种光源共用一套光照方向构造与衰减接口:方向光无衰减、点光源 r²/(r²+d²)、聚光再乘锥软化。同一场景下受光像素 959.8‰ / 953.3‰ / 70.1‰;衰减的两种整数写法在 178/1280 个距离上分叉、最大差 1 个 Q16.16,d=range 处恰好 0.5。
一份材质表 JSON 驱动三种宿主:Python 建材质对象、TypeScript 建同构对象、HTML 内联同一条材质。三处解析的六个字段逐字段相同(对账表 S/W/P 三列一致),规范 digest c456c8c1… 两侧相同;改一个字段后帧 digest 与内联值同步变化,四次扰动全部同步。
材质的每个开关都让着色器分叉:4 开关理论 16 组合、实际只用 9;8 开关理论 256、实际 23,爆炸比 11.13×。变体键用整数位编码去重,与 frozenset、关键词串去重同数;键漏掉 shadow 位则去重数从 9 塌缩到 7。逐个渲染实际变体,不同键必给不同帧。
材质是六个定点参数而非浮点结构体。继承用不动点松弛解析,与输入顺序无关:叶子 gold_trim_dark 逐字段来源确定,解析 digest 074b01f1… 在打乱输入后不变,自指父指针报错;叶子材质驱动一帧,改被继承字段帧变、改旁系帧不变。
把「哪个抗锯齿方案更好」写成一条可复算的判据:先用参考解的梯度阈值圈出边缘像素,只在边缘上算 MAE,再配上 PSNR。64×64 圆盘的 296 个边缘像素上,无抗锯齿 → 4 spp SSAA → 8 帧 TAA → 16 spp SSAA 三级判据全部成立,而把覆盖率乘 0.5 的错实现被同一条判据拒绝。
抖动不减少量化误差,它把误差从低频的「带状」搬到高频的「噪声」。本节把 0..255 的斜坡量化到 8 级,比较无抖动、Bayer 有序抖动、Floyd–Steinberg 误差扩散与 16×16 蓝噪声:总误差几乎不变,低频带状分量从 6.4844 压到 1.2 上下;蓝噪声更把阈值矩阵的低频功率占比压到同尺寸白噪声的 1/243。
时间抗锯齿的全部机制可以压成三个整数:帧间权重 w = ONE//(k+1)、确定性的 Halton 子像素抖动、历史帧的 3×3 邻域裁剪。本节在解析圆盘上实测——静止相机下 1→16 帧的 MAE 从 1.9163 收敛到 0.3881;每帧微动 0.25 px 时,裁剪把重影误差从 9.2405 压到 4.929。
同一份场景、同一套顶点变换、同一个 Lambert 公式,只把「插值颜色」换成「插值法线再逐像素求值」:覆盖掩码与深度缓冲逐像素相同(几何封版),颜色却有 41261 个像素不同(537.2526‰),MAE 3.5764、PSNR 37.06 dB、最大通道差 48。
Phong 高光要构造反射向量 R = 2(N·L)N − L 再算 R·V 的幂次,Blinn-Phong 改用半步向量 H。本节用 66 个观察方向实测两者的叶宽、最大差与运算量,把 x^32 的平方链(5 次 fmul)与 31 次逐次相乘逐位比对,并推翻「Blinn-Phong 不会照亮背面」这句流传很广的话。
卷一封版了几何到像素的骨架,卷二只换着色环节。本节从 N·L 的几何含义出发,把 Lambert 漫反射写成纯整数点积加一次算术右移:66 个方向实测受光 30、背光 36,去掉 max(0, N·L) 后出现 81 个负通道,而钳制版所有通道落在 [0, 200]。
《计算机图形学》卷二《着色、光照与纹理》附录 A:全卷共用的 Q16.16 定点常数表(1/π、9/π、3/π)、逐像素层的量级上界推导、六个着色公式的整数形式速查(Lambert、Phong、Blinn-Phong、GGX、Smith、Schlick)、材质参数表、能量守恒残差汇总,以及各章产物的数据集索引与复现命令。所有数字来自本机实跑。
《计算机图形学》卷二《着色、光照与纹理》目录:16 章 48 节,只替换卷一封版的着色环节——逐顶点 Lambert 改为插值法线后逐像素求值,把光照模型、BRDF 与能量守恒、法线贴图、阴影、环境光遮蔽、微表面 PBR、sRGB 与色调映射、程序化纹理与后处理全部写成可逐像素断言的整数。本页给出分工、六档可运行性口径、卷二新基线与全书 16 章 48 节完整清单。