几种几何表面上的采样
这篇专栏算是接下来光追专栏的预热, 因为光追算法使用的是蒙特卡洛积分渲染的, 而蒙特卡洛积分里需要进行大量的几何表面面采样, 所以这里就直接单独拿出来讲了.

单位正方形上的均匀采样
为了专栏的减少篇幅和使结构更加清晰, 这里假设有一种算法可以在单位正方形上进行均匀采样, 最简单的当然就是使用编程语言里内置的随机浮点数生成方法:
但是实际上这种采样会造成巨大的标准差 (即在少量样本里不足够均匀), 所以在光追算法里为了提高在一定计算时间内图像的质量, 提出了很多种生成在单位正方形上均匀采样的方法. 但是采样生成方法还是留到之后再说吧.
接下来的所有几何表面采样都不是直接在表面上进行采样, 而是在单位正方形上采样后再投射到几何表面上, 这可以提高方法的复用度, 比如说有多种单位正方形上采样的方法, 那么相应的半球采样只需要定义单位正方形到半球的投射, 而不是重新定义多种直接在半球上的采样方法. 另外需要声明, 整篇专栏都不会对区间边界进行讨论, 因为区间边界对采样的贡献永远都是 0 (数学上, 编程里还是需要稍微注意一下的), 所以区间的开闭性都是乱来的.
下图是两个在单位正方形上均匀的采样集, 分别是256个采样点和2048个, 之后展示投射方法的正确性就使用这两个采样集.


单位圆面上的均匀采样
单位圆面定义为 . 描述与圆相关的东西时, 极坐标是一个非常方便的坐标系, 极坐标与笛卡尔坐标有转换公式:
和
, 其中 atan2 是一个编程上常用的方法, 而不是严格的数学函数, 但是用这个函数会省下计算 tan⁻¹ 的麻烦 (比如象限讨论和除以≈0造成的数值不稳定).
为了确保采样的均匀性, 需要计算面积元 在对应的坐标系里的形式. 把上面的转换公式代入不难得出在极坐标下面积元为
, 稍加变换得到
, 结合单位面积在笛卡尔坐标下的定义, 可以定义单位正方形到单位圆面上的均匀投射为
, 在单位正方形内, x和y定义在 [0,1] 上, 而单位圆面定义 r 在 [0,1] 上, φ 在 [0,2π] 上, 于是得到投射公式
, 下面是使用上面展示过的采样集进行投射的结果

另外 Shirley 提出了一个同心投射的方法: 把正方形 [-1,1]² 分割为4个三角形, 然后将三角形投射到单位圆的扇形上, 即下图所示

相应的从单位正方形到单位圆的投射方法为:
使用这种投射方法的结果为:

Shirley 的方法与上面推导的少了算一个 sqrt, 所以在性能上有优势. 但在实际光追算法里, 是初始化时生成一大个样本集提供给光追里使用, 所以这点性能差距也不算太重要了.

单位球面上的均匀采样
单位球面定义为 , 与极坐标类似, 三维空间有相应的球极坐标 (r 距离,
θ 天顶角, φ 方位角), 其中天顶角是从z轴到目标向量之间的夹角. 球极坐标和笛卡尔坐标的转换公式为 和
. 对于单位球面, r 固定为1, 于是自由变量只有 θ 和 φ, 这两个变量合在一起成为立体角, 用符号 Ω 表示.
立体角的微元 dΩ 可以看作单位球面上的面积元 dA, 为了避免符号冲突, 这里使用 u 和 v 代替单位正方形上的 x 和 y, 那么有 . 并且由球极坐标的定义可以得到立体角的微元为
, 稍加变换得到
. 即得到单位正方形到单位球面的均匀投射为
, 在立体角里 θ 取值为 [0, π], φ 取值为 [0, 2π], 于是最后得到
. 在实际计算里不需要把 θ 算出来, 因为 1-2u 已经给出了 cosθ 的值, 则有
, 并且平方根的计算速度比 sin, cos 快很多.
下图为投射的结果, 左边为 x,z 分量, 右边为 x,y 分量

在这里真的很难看出来样本的均匀分布, 非常推荐自己去用 plot 的3d显示看一下.

半球面上的不均匀采样
半球定义为单位球面里 z>0 的部分, 即 θ<π/2. 半球的不均匀采样在光追里常用来计算高光和优化反射采样. 半球的不均匀采样里有一个常数 c 用于表示采样点在半球上的集中度, 样本在立体角上的分布正比于 , 下面为 c=10 和 c=100 时的样本分布

特殊地, 当 c=0 时则为半球的均匀采样.
因为半球上的采样不是均匀的, 采样分布与立体角有关系 , 于是可以假设
, 可以看到 dφ 与球面采样里 dφ 是一致的, 那么 φ 分量的投射与球面的相同. 类比于圆面和球面采样, 不难知道这里需要找到一个关于 θ 的表达式 Θ 使得
, 也就是求积分. 经过一番头脑风暴* 之后可以求得
. 因为半球里 θ 取值为 [0, π/2], 所以 Θ 取值为 [0, 1/(c+1)]. 最后求得相应的 θ 分量的投射为
.
*: 凑微分法, 又称东凑西凑总之不知道为什么就拼对了法 (

三角形上的均匀采样
以三角形其中一个点为局部坐标系的原点, 那么三角形的另外两个点在局部坐标系里可以表示为两个向量: A, B. 然后对单位正方形上的采样点进行处理: 把 1-x>y 的点重新投射到 1-x<y 里, 于是得到处于 (0,0)-(0,1)-(1,0) 里的均匀采样. 那么三角形上的均匀投射为 x*A+y*B.
这是容易证明的 (线性变换), 但是由于有点难展示 (懒得再写程序了), 所以这里提一下就算了.

有了这几个几何面的采样方法, 足以应对简单场景的光追渲染了. 下一篇专栏大概就是来讨论一下如何生成单位正方形上的均匀采样了, 之后的话应该就是光追的主专栏了.
展示一下一个极简场景的渲染图 (只有一次光线反射).

最后宣传一下涩弔图群: 274767696