计算机图形学 19:表面颜色从哪里来
把材质反射率设为 0.6,像素就应该写成 0.6 吗?同一块表面放在不同照明下,显然不会保持相同的显示颜色。问题在于材质参数、到达表面的光、离开表面的光和屏幕码值分别代表不同的量。
本篇选择一个能手算的场景:不发光、不透射的漫反射平面,法线上方一个圆锥内有恒定入射辐亮度,其余方向为零。先算物理量,再用确定性求积核对,最后才把结果压缩到灰度图。它是已知入射条件下的局部积分,不是通用间接光照求解器。
功率落到面积上,还缺一个方向
辐射通量 Φ 表示单位时间传递的辐射能量,单位 W。把入射通量按表面积分配,得到辐照度 E=dΦ/dA,单位 W/m²。它回答一小块表面总共收到多少功率,没有保留这些光分别来自哪些方向。
方向分布由辐亮度 L 描述。通过面积 dA、沿某个小立体角 dω 传播的功率满足:
θ 是该方向与表面法线的夹角,面积投影为 cosθ dA。L 的单位为 W/(m²·sr),sr 是立体角单位球面度。一个方向范围在单位球面上覆盖的面积就是其立体角,完整球面为 4π sr,半球为 2π sr。
同样一块表面,从倾斜方向看见的投影面积较小,因此通量表达式含余弦。这不是材质凭空变暗的经验参数,而是面积投影产生的几何因素。
将入射方向上的辐亮度积分,得到辐照度:
这里 n 和 ωᵢ 都是单位向量,Ω⁺ 为 n 所在的正面半球。沿用表面散射中的方向约定,ωᵢ 指向光来自的方向,也就是从表面向外;真实入射传播方向与它相反。ωₒ 也从表面向观察方向,不把两者写成一入一出的向量再直接套同一符号。
辐亮度保留方向,辐照度累加方向。即使单位中都有 W/m²,也不能互换它们,更不能把法线点积直接称为辐亮度。第 09 篇将光强常量折入经验系数的做法,在这里需要展开量纲。
BRDF 是响应函数,不是最终颜色
双向反射分布函数 BRDF 定义微小入射辐照度对某个出射方向辐亮度的贡献:
因此 fᵣ 的单位是 sr⁻¹。它描述材质如何把不同入射方向的光分配到出射方向,不是无量纲的“像素颜色”。把所有入射贡献相加,就得到反射积分。
Lambert 模型选择 fᵣ=ρ/π,其中 ρ∈[0,1] 是无量纲反射率。为什么要除 π?固定入射方向后,对出射半球积分 fᵣ cosθₒ dωₒ,总反射份额应为 ρ,而余弦加权半球积分等于 π。
如果漏掉这个归一化,使用 fᵣ=ρ,即使 ρ=0.6 仍可能让积分反射份额大于 1。单看材质参数落在 [0,1] 并不能证明反射模型守恒。另一方面,一般 BRDF 在很窄的方向峰值可以大于 1 sr⁻¹,守恒约束针对积分,不是简单逐点裁剪。
Lambert 出射辐亮度不随正面观察方向改变。这不表示等立体角方向携带相同通量;通量还乘出射面积的余弦投影。也不表示所有真实哑光材料都精确遵循这个模型,尤其掠射等情况可能偏离。
当前 lambert_brdf 只实现正面反射:入射和出射余弦都大于零时返回 ρ/π,否则返回零。掠射边界按零处理,不影响普通积分的测度。反射率、余弦都要求有限且在合法范围内,它们仍是普通 double,没有静态单位类型系统。
BSDF 与渲染方程各自增加了什么
BRDF 只讨论反射。BSDF 统称表面散射分布,还可以包含透射。对于不透射的单面表面,积分在正面半球上即可;玻璃会把光带到另一侧,需要不同的散射项、介质与折射约定,不能把同一个 Lambert 半球积分直接称为玻璃模型。
对本篇的不透射表面,出射辐亮度由自身发射和反射贡献组成:
量纲依次为 sr⁻¹、W/(m²·sr)、无量纲余弦、sr,乘积积分后仍是 W/(m²·sr),与左边相同。漏掉余弦或重复乘余弦不会被量纲检查全部识别,还需要几何推导和数值例子。
式子的难点在 Lᵢ。真实场景中,它可能来自其他物体反射,而那里的出射又依赖更多位置的入射。第 17、18 篇提供沿方向找到最近表面的能力,并没有自动算出那个表面向这里发出多少光。
在无遮挡、无参与介质且折射率不变的自由传播段,辐亮度沿射线保持不变。距离改变会影响有限光源在接收点张开的立体角,不能因此给每条辐亮度射线再随意乘一次距离平方衰减。点光源强度到辐照度的关系与此采用不同的量和几何表达。
本篇直接指定 Lᵢ,把未知的全场景耦合变成可解的小问题。后续路径积分才求多次反射,当前结果不能作为颜色渗透或全局光照的验证。
一个圆锥照亮平面,积分是多少
令法线沿 +Z,入射辐亮度在 θ∈[0,α] 内恒为 L,所有方位角 φ∈[0,2π) 都有光,圆锥外为零。α 在 0 到 π/2 之间。球面坐标的立体角微元为 dω=sinθ dθ dφ,因此:
不发光 Lambert 表面于是得到 Lₒ=(ρ/π)E=ρL sin²α。这里的 sinθ 来自积分测度,cosθ 来自投影,它们不能互相替换。
取 L=2 W/(m²·sr)、ρ=0.6。α=90° 时整个半球入射,E=2π W/m²,Lₒ=1.2 W/(m²·sr)。α=30° 时 sin²α=1/4,Lₒ=0.3;α=60° 时为 3/4,Lₒ=0.9。
半球不是简单把 L 乘 2π。方向越接近地平线,投影余弦越小,所以余弦加权立体角为 π。忽略这点会把入射总量算大一倍。
同一个半球例子若漏掉 BRDF 中的 π,错误结果为 0.6×2π≈3.769911。若余弦重复乘一次,积分变成 2πL/3,错误 Lₒ 为 0.8。检查器打印这两个解析反例值;它们是手算表达式的数值展示,没有冒充两套错误渲染器的运行比较。
数值求积怎样验证解析值
cone_irradiance 在 θ 与 φ 方向均匀划分区间,用每个 θ 小格中心的 cosθ sinθ 乘 ΔθΔφ 后累加。当前被积函数与 φ 无关,方位角循环只是重复相同权重;程序另检查 1 份和 32 份方位角结果一致。
对每个 α,固定方位角份数 32,把极角份数依次设为 4、16、64、256。没有随机数、种子或俄罗斯轮盘,终止由固定网格规模决定。这是中点求积收敛检查,不是蒙特卡洛误差统计。
| α | 4 份绝对误差 | 16 份绝对误差 | 64 份绝对误差 | 256 份绝对误差 |
|---|---|---|---|---|
| 30° | 0.00449485 | 0.000280401 | 0.0000175230 | 0.00000109518 |
| 60° | 0.0542639 | 0.00336608 | 0.000210281 | 0.0000131422 |
| 90° | 0.164444 | 0.0101046 | 0.000630869 | 0.0000394267 |
表中误差是 E 的误差,单位 W/m²;不是 PNG 灰度差。每次将极角份数扩大四倍,误差约缩小十六倍,与光滑函数上中点公式的二阶行为相符。这个特定结果不能保证含遮挡跳变的积分也有相同误差规律。
在 256×32 网格上,半球 E=6.28322473387245,对应 Lₒ=1.20000752994367。程序要求三种角度的 E 最终绝对误差小于 4×10⁻⁵ W/m²,并核对六种材质/入射配置的 Lₒ 误差小于 2×10⁻⁵ W/(m²·sr)。阈值针对本次有界数值实验,不当作任意场景的精度承诺。
从物理量到屏幕码值
反射率为 0.6 并不妨碍 Lₒ 大于 1。前者是份额,后者是带单位的辐亮度;当半球 L 从 2 增到 4,Lₒ 从 1.2 增到 2.4,仍然只反射入射能量的 60%。把 Lₒ 裁成 1 会破坏这个关系。
显示阶段先选择参考辐亮度 Lref=1 W/(m²·sr),得到无量纲 u=Lₒ/Lref,再沿用第 04 篇的 T(u)=u/(1+u),最后执行 sRGB 编码和 8 位量化。参考值是本次曝光尺度的选择,不代表显示器已完成辐射标定。
每块为 128×128,按从左到右、从上到下编号。它们是实际积分输出的均匀平面样本,不是三维场景截图。标量结果复制到三个 RGB 通道形成灰阶,不把这三个相同数字称为完整光谱。
| 位置 | Lᵢ | ρ | α | 解析 Lₒ | 实际 Lₒ | 8 位码值 |
|---|---|---|---|---|---|---|
| 上左 | 2 | 0.6 | 90° | 1.2 | 1.20000753 | 195 |
| 上中 | 2 | 0.6 | 30° | 0.3 | 0.30000021 | 132 |
| 上右 | 2 | 0.6 | 60° | 0.9 | 0.90000251 | 183 |
| 下左 | 2 | 0 | 90° | 0 | 0 | 0 |
| 下中 | 2 | 1 | 90° | 2 | 2.00001255 | 213 |
| 下右 | 4 | 0.6 | 90° | 2.4 | 2.40001506 | 219 |
Lᵢ、Lₒ 两列单位均为 W/(m²·sr)。同样的 ρ=0.6 在前三块显示为不同灰阶;下右还说明入射翻倍后,物理 Lₒ 翻倍,经过压缩的码值却不会翻倍。
原始数值 CSV 保存 Lᵢ、ρ、圆锥角、E、未截断 Lₒ、解析值、显示线性值和码值。换显示曲线可以重新处理 CSV,无需重算积分;只有最终 PNG 则无法恢复被量化的信息。
复跑与练习
1 | |
代码是 radiometry.hpp 与 radiometry_check.cpp。writing-plans/computer-graphics/evidence/19-cpu.txt 保存全部网格结果和拒绝样本计数。方向正反面、掠射边界、方位划分一致性、零圆锥及非法输入均有检查;单位由接口约定、推导与 CSV 表头表达,没有虚构编译器的量纲验证能力。
练习一:L=3 W/(m²·sr),ρ=0.4,入射覆盖整个正面半球。E 与 Lₒ 各是多少?若把反射率改成 1,Lₒ 应是多少?
答案:E=3π W/m²,Lₒ=1.2 W/(m²·sr)。ρ=1 时 Lₒ=3,而不是被裁成 1。反射率限制总反射份额,不限制带单位的辐亮度数值。
练习二:圆锥半角从 30° 改为 60°,保持 L 和 ρ 不变,Lₒ 增加几倍?为什么不能只按角度翻倍计算?
答案:sin²60°/sin²30°=3,因此增加三倍。积分同时包含球面测度和投影余弦,面积与角度不是线性关系。
练习三:若把 BRDF 改成 ρ,量纲表仍给它标 sr⁻¹,量纲核对能发现漏 π 吗?
答案:不能,π 不改变单位。还需要反射半球积分与解析场景核对。量纲是必要检查,不能代替归一化和数值验收。
系列导航与资料
前篇:18:怎样减少求交次数。系列入口。下一篇:20 随机样本怎样估计积分,尚未完成。
PBRT 第四版 §4.1 核对通量、辐照度和辐亮度;§4.3 核对反射函数及方向约定;§9.2 核对 Lambert 归一化;§13.1 核对发射、散射与场景耦合。实际读取于 2026-09-20,后两页写作时再次打开;独立推导的圆锥输入与本地结果见本篇代码和记录。






