GPU Gems 3 · Chapter 20. GPU-Based Importance Sampling
从环境光照积分出发,解释如何用 BRDF 引导的 GPU 重要性采样、Hammersley 序列和 PDF 感知 mip 过滤实时渲染高光表面。
学习目标
- 能解释环境光照积分、BRDF 引导的 PDF 与 mip 过滤如何共同把数千个方向压缩成有限 GPU 样本
- 能修改 GPU Importance Sampling Lab 的采样分布、样本数、光泽度、过滤和环境映射,比较方差与纹理访问
- 能回答:为什么低差异序列还需要依据 PDF 的过滤,以及为什么 dual-paraboloid 能减轻环境图接缝
先问:为什么镜面反射不能把环境图只采几次
想象一块抛光金属:它看到的环境并不是一块固定颜色,而是半球上不同方向的光经过材质反射后共同贡献的结果。把环境图每个 texel 都乘一遍 BRDF,画面会很准,却远远超出实时 shader 的预算。
本章解决的是:怎样把有限的样本集中在真正重要的方向,同时让每个样本代表它附近合理大小的环境区域。没有这条路径,均匀采样会把工作浪费在暗处,少量确定性样本又会变成重复高光和明显条纹。
1. 把环境光照写成可估计的积分
↡用有限个方向样本的加权平均近似半球上的光照积分;样本越能代表高贡献区域,有限预算下的误差通常越小。对一个表面点和视线方向 v,目标是把每个入射方向 u 的环境光、材质响应和入射余弦相乘,再在可见半球上累积成出射光。环境图把方向 u 变成纹理查询,但一张高分辨率环境图可能包含成千上万的方向。
有限样本的估计是“样本贡献的平均”。样本少时,估计值会偏离真实积分;如果样本分布不均,误差会表现为噪声或重复高光。重要性采样的关键是让样本分布贴近被积函数中最有贡献的部分,而不是机械地均匀撒点。
2. 用 PDF 把样本集中到重要方向
↡描述每个方向被选中的相对概率,并且在整个采样域上的积分归一为 1;峰值表示更值得分配样本的区域。对光泽材质,镜面反射方向附近通常贡献更大,所以可以用归一化 BRDF 作为 probability density function。它告诉我们“哪些方向常被采到”,但也带来一个必须遵守的补偿:高概率区域中的一个样本只代表很小的一片,低概率区域中的一个样本代表更大的一片。
因此估计器要把每个样本乘以其 PDF 的倒数,再做平均。这样偏置分布不会改变积分的期望值。真正的最优 PDF 应该接近 BRDF 与环境光的乘积;那通常需要更多预计算,因此本章采用更容易实时改变材质和环境的 BRDF-only 近似,再配合后面的样本过滤。
第 1 / 3 步 · 用材质的 BRDF 形状定义哪些方向更重要
播放三个阶段:PDF 负责偏置,序列负责覆盖,mipmap 负责把有限样本变得可用。
3. 用 CDF 反解把均匀输入变成偏置方向
↡把 PDF 从起点累积到当前位置得到的函数;均匀随机输入通过它的反函数,就能按 PDF 的比例落到方向上。GPU 最方便得到的是 [0, 1] 范围内的均匀数对 ξ1, ξ2。要从它们生成 BRDF 方向,先把二维 PDF 拆成一个边缘分布和一个条件分布,再分别积分成 cumulative distribution function,最后用反函数得到球面角度。
直觉上,CDF 是把概率“堆起来”的尺子。PDF 高的区间在尺子上占更长,更多均匀输入就会落在那里;PDF 低的区间占更短,但一旦命中,就代表更大的积分区域。对 Phong glossy lobe,可以围绕镜面方向建立局部坐标,把生成的方向变回切线空间,再变到世界空间。
采样坐标系需要一条明确的基准:镜面方向定义局部 z 轴,切线、副切线和法线把它带回世界空间。围绕镜面方向的旋转存在一个自由轴,工程实现可以选一个不与 z 轴共线的辅助轴,再用正交化得到稳定的基。
4. 用低差异序列铺开有限样本
↡一种确定性的二维低差异序列;它用数字的二进制位反转生成第二维,使固定数量的点比独立伪随机数更均匀地覆盖输入域。独立伪随机数会偶尔成团,也会留下空洞。样本数量只有几十个时,这种覆盖不均会直接转化为估计误差。Hammersley sequence 的第二维使用 radical inverse:把样本索引的二进制位从小数点两侧反射,得到一条稳定、均匀的低差异序列。
低差异不是“不会出错的随机数”。它把噪声变成更有规律的覆盖,固定样本数下通常收敛更快,但规律性也可能显出别名,像多出几块重复的高光。因此本章不把序列当成最后一步,而是让它与 PDF 引导和 mipmap 过滤一起使用。
5. 让每个样本按 PDF 选择环境图 mip
↡纹理金字塔中代表某个采样分辨率的层级;在本章中,它根据样本代表的立体角选择,而不是固定使用同一层。如果一个方向的 PDF 很低,附近很少有其他样本会落在那里,那么这个样本应该从环境图较大的邻域取平均;如果 PDF 很高,许多样本已经会共同平均那片区域,这个样本只需读取较细的邻域。样本代表的立体角与 1 / (PDF × N) 成正比,N 是样本数。
环境图 mip 是天然的 GPU 平均结构:层级越高,覆盖的 texel 区域越大。实现时先根据样本立体角估算它覆盖的零级 texel 数,再取对数得到 mipmap level of detail。实践中可加入小幅偏移,让相邻样本有轻微重叠,减少锐利边界。
6. 用 dual-paraboloid 保住过滤邻域
↡把上半球和下半球分别投影到两张纹理上的环境图布局;它让每张纹理包含一部分对侧信息,减少按立方体面独立生成 mip 时的接缝。cube map 的几何失真很小,但硬件通常按每个面独立生成 mip。跨面采样时,一个样本周围本应相邻的环境信息可能落在另一面,平均区域就会被切断。dual-paraboloid mapping 用上下两张纹理承载两个半球,每张半球纹理都带进一部分对侧信息,因此过滤时更少出现接缝。
原书还对通常的抛物面映射加入约 1.2 的缩放,让投影圆周向外扩展一点,进一步增加重叠。这个选择牺牲少量纹理空间,却让低 PDF 样本的宽区域平均更接近真实环境。环境布局因此不是采样函数之外的细节,而是过滤算法的一部分。
7. 把采样、过滤和着色合并成一个短循环
float3 GPUImportanceSample(float3 viewing, Texture2D environment) {
float3 accumulated = 0.0;
for (int k = 0; k < SAMPLE_COUNT; ++k) {
float2 xi = hammersleySequence(k, SAMPLE_COUNT);
float3 direction = sampleMaterial(xi, viewing);
float pdf = materialPdf(direction, viewing);
float lod = computePdfAwareLod(direction, pdf, SAMPLE_COUNT);
float2 uv = dualParaboloid(direction);
float3 light = environment.SampleLevel(linearSampler, uv, lod).rgb;
accumulated += light * materialWeight(direction, viewing) / pdf;
}
return accumulated / float(SAMPLE_COUNT);
}实际实现可以四个方向并行生成,预计算三角函数和低差异序列,并在代数上消掉 BRDF 与 PDF 中会相互抵消的项。重点仍然是状态依赖的顺序:生成方向、得到 PDF、计算 LOD、采环境图、累积并除以样本数。
先用材质函数定义方向分布
把观察方向、法线和材质光泽度转换成镜面局部坐标;用归一化 BRDF 作为近似 PDF,让有限预算集中到真正有贡献的方向。
GPU Importance Sampling Lab
调整采样分布、样本数、材质光泽、过滤策略和环境图布局,观察方差、覆盖、LOD 与纹理访问的取舍。
本章小结
- 环境光照积分可以用有限方向样本近似
- BRDF PDF 把样本集中到高贡献方向,但必须用倒数补偿
- CDF 反解把均匀输入变成可控的偏置方向
- Hammersley sequence 改善低样本数下的覆盖,过滤抑制规律性别名
- PDF 感知 mip 与 dual-paraboloid 共同把样本区域变成可用的环境平均
练习
问题 1|修改 Demo 代码。 把 Lab 的 sampling distribution 切换到 uniform,再保持相同的 samples 和 filter;你预计哪些指标会变化?为什么?
问题 2|诊断重复高光。 你使用 Hammersley、32 个样本和高对比度环境图,画面出现规则亮斑。请按“序列、过滤、映射”列出三个检查点。
问题 3|场景选型。 动态材质编辑器、低光泽大面积墙面和非常锐利的金属球,分别如何选择样本数与过滤策略?
名词解释
本章出现的专业名词,用大白话再讲一遍。
- Monte Carlo quadrature
- probability density function
- cumulative distribution function
- Hammersley sequence
- mipmap level of detail
- dual-paraboloid mapping