Ray Tracing-The Rest of Your Life(3)
Ray Tracing-The Rest of Your Life
8. 直接对光源采样
- 在一块面积为 \(A\) 的区域上均匀采样
\[ p_q(q)\cdot\mathrm{d}A=\dfrac{1}{A}\cdot\mathrm{d}A \]
- 需要转化到单位球面上
\[ \dfrac{\mathrm{d}\omega}{1^2}=\dfrac{\mathrm{d}A\cdot \cos\alpha}{\text{distance}^2(p,q)} \]
- 转化为等价在单位球面上均匀采样
\[ p_q(q)\cdot\mathrm{d}A=p(dir)\cdot\mathrm{d}\omega \]
\[ p(dir)\;\mathrm{d}\omega=p(dir)\cdot\dfrac{\cos\alpha}{\text{distance}^2(p,q)}\;\mathrm{d}A=\dfrac{1}{A}\cdot\mathrm{d}A \]
\[ p(dir)=\dfrac{\text{distance}^2(p,q)}{A\cdot\cos\alpha} \]
对比图
- 常规采样:10spp,2s
- 直接对光源采样:10spp,1s
- 问题:只有直接光照(1-bounce)
- 光源边上的亮斑
- 代码中的光源是两面的(two-sided)
- 光源位于屋顶下面一点点(不是完全重合)
- 如果使用定向光,则不会出现这种情况
- 效果如下
- 默认的
rect_xz
法向向上,加入flip_face
包装类,需要修改法向方向
- 跑一个 1000 spp 看看
- 54s
- 那确实就变成了实时渲染中的直接光照了(其实也不是,这里的软阴影还是有的hh)
- 准确的来说,这种方法是有偏的,因为 pdf 的非零值的定义域没有覆盖到整个积分域上
- 下面这种混合 pdf 则是无偏的,因为其覆盖了整个积分域
9. 混合 pdf
重构 pdf 类
1 | class pdf { |
- 新的 pdf 采样都继承自这个类
- 例如构造一个朝着某个物体采样的 pdf(
hittable_pdf
)
混合 pdf
- 结合对光源直接采样、常规采样
- 简单使用平均两种 pdf
\[ \text{mixture}_\text{pdf}(dir) = \frac{1}{2} \text{reflection}_\text{pdf}(dir) + \frac{1}{2} \text{light}_\text{pdf}(dir) \]
- 实现
1 | if (random_double() < 0.5) |
1 | vec3 mixture_pdf::generate() const { |
效果比较
10 spp
- 混合 pdf,1s
- 常规采样:2s
- 直接对光源采样:1s
1000 spp
- 直接对光源采样:54s
- 常规采样:177s
- 混合采样:117s
10. 架构的建议
- 上面的混合采样方法,对光源方向给予更大的采样比例,能够让场景收敛的更快
- 一些问题
- pdf 采样现在是硬编码在
ray_color()
函数里面的,应该是要放到材质里面去 - 镜面材质
- 背景色
- 使用光谱代替 RGB
- pdf 采样现在是硬编码在
11. 管理 PDF
- 放到材质里面去
- 如何让一种物体有两种材质的效果
- varnished wood:漆木
- 部分 diffuse:木
- 部分 specular:漆
- 修改不同材质的
scatter()
函数即可 - 把左边的 box 材质替换为镜面
- 左上角应该是反射(1000 spp)
- 50000 spp
- 5339s
对球体采样
- 之前我们只写了对一个长方形采样,现在增加其他的部分
- 修改 object 的
random()
函数
- 修改 object 的
- 计算 pdf
- 采样一个单位长度的出射方向, 起点在 (0,0,0), 方向和球体有交点
- 在这个立体角内部均匀后采样
求 \(\theta_{\max}\)
- \(\theta_{\max}\) 如下图所示
\[ \sin(\theta_{\max})=\dfrac{R}{\Vert\mathbf{c}-\mathbf{p}\Vert_2} \]
\[ \cos(\theta_{\max})=\sqrt{1-\dfrac{R^2}{\Vert\mathbf{c}-\mathbf{p}\Vert_2^2}} \]
采样
- 最大张角为 \(\theta_{\max}\)
\[ f(\theta)=\dfrac{1}{\int_{0}^{2\pi}\int_{0}^{\theta_{\max}}\sin\theta\;\mathrm{d}\theta\mathrm{d}\phi}=\dfrac{1}{2\pi(1-\cos\theta_{\max})} \]
- 求出对应关系
\[ \phi=2\pi r_1 \]
\[ \begin{aligned} &\Pr(R_2\le r_2)=\Pr(\Theta\le\theta)\\ \Longrightarrow&\;r_2=\int_{0}^{\theta} 2\pi f(t)\sin t\;\mathrm{d}t=\dfrac{1-\cos\theta}{1-\cos\theta_{\max}}\\ \Longrightarrow&\;\cos\theta=1-r_2(1-\cos\theta_{\max})\\ \end{aligned} \]
- 因此 \(x,y,z\) 表达如下
\[ \begin{array}{c} z = \cos(\theta)=1+r_2(\cos\theta_{\max}-1)\\ x = \cos(2\pi r_1) \cdot \sqrt{1-z^2}\\ y = \sin(2\pi r_1) \cdot \sqrt{1-z^2}\\ \end{array} \]
效果展示
- 朝着光源采样
- 100spp,10s
- 朝着玻璃球采样
- 100spp,24s
- 效果并没有直接对光源采样好
对一组对象采样
- 可以使用这样的方式
\[ \text{mixture}_\text{pdf}(dir) = \frac{1}{2} \text{reflection}_\text{pdf}(dir) + \frac{1}{2} \text{hittable_list}_\text{pdf}(dir) \]
\[ \text{hittable_list}_\text{pdf}(dir)=\dfrac{1}{N}\sum_{\text{object}\;\in\;\text{hittable_list}}\text{object}_\text{pdf}(dir) \]
- 这样只需要修改
hittable_list
的random()
和pdf_value()
函数即可 - 此时把光源和玻璃球都加入到建议采样方向上
- 100spp,17s
outlier
- 每次得到颜色的时候,去除 NaN
12. 结果
中间是一个镜子
1spp,0s
- 10spp,1s
- 100spp,10s
- 1000spp,107s
- 10000spp,1108s
- 100000spp,10332s