本文使用Zhihu on VSCode 插件发布。(这里吐槽一下知乎写markdown和latex的难用) 本文来自我的2020计算机图形学课程作业报告。原报告中为了对结果进行对比分析,有一些表格,但是知乎不支持表格,只好单独放图。 本次作业使用的是助教 @Ubp.a 提供的框架,膜一波助教。
仿照SIGGRAPH论文,在介绍之前放部分结果。
目录
- 路径追踪
- 原理介绍
- 基于物理的光线渲染基础知识
- 光线追踪算法
- 蒙特卡洛采样方法
- 路径追踪算法
- 实现中的关键问题与解决方法
- 测试结果
2. 环境贴图重要性采样
-
- 原理介绍
- 实现中的关键问题与解决方法
- 测试结果
3. 参考文献
强烈推荐闫令琪老师的Game101-tracing4课程,路径追踪讲得非常清楚!
GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com一. 路径追踪
- 原理介绍
- 基于物理的光线渲染基础知识(PBR: Physics Based Rendering)
为了能够使用计算机绘制出接近真实世界光影效果的图片,我们需要考虑物理上,光线是如何与物体相互作用然后进入人眼、造就色彩斑斓的美丽世界的。这里由于篇幅的限制,略去对几何光学、波动光学知识的介绍,仅介绍一些光线渲染技术中的物理概念。
-
- 辐照率Radiance
光线的Radiance被定义为光线单位面积单位立体角上的功率。空间位置上沿着方向的Radiance可以用符号表示。
- 辐照率Radiance
-
- BRDF函数
现实世界中不同材质的物体对于光的反射模式千变万化。为了描述材质在空间位置对入射光线的反射情况,我们使用BRDF函数。BRDF函数的本质是描述漫反射物体在反射光线时,出射光线在不同出射方向上的能量分布。这里不对BRDF函数做具体的介绍,有一篇讲得很详细的文章链接在此:基于物理着色:BRDF
- BRDF函数
-
- 渲染方程
渲染方程是光线渲染的核心,它给出了对光线渲染物理模型的准确描述,满足渲染方程的光线渲染算法可以保证结果的物理正确性。
其中代表着物体接收到来自光源的直接光照的辐照率,代表着物体接收到的来自别的非自发光物体的反射光(间接光照)的辐照度,其公式如下:
某一点的光照是来自直接光照与间接光照的叠加,如下图所示。可以看到在仅有直接光照的情况下,画面较暗,很多没有被光源直接照射到的物体的细节被隐藏在黑暗之中。而在有直接光照+间接光照的情况下,画面整体变亮,并且能够照亮左图并不能看到的物体细节。
- 渲染方程
-
- 光线追踪算法
光线追踪算法是光线渲染早期的一种重要的渲染方法。正如其名,其核心思想是让光线从相机出发寻找光源。准确地说,从相机平面上每一个像素点发射出一条光线,该光线在场景中将经过一系列反射/折射,最终到达光源或者背景。最终到达背景的光在该像素点处呈现背景相应位置的颜色(乘以路径上的一系列因子),而到达光源的光在该处呈现光源颜色(同样地,乘以路径上的一系列因子)。
- 光线追踪算法
其原始算法(Whitted-style)主要过程如下。
color trace(point p, vector d, int step)
{
color local, reflected, transmitted;
point q;
normal n;
if(step > max) return(background_color);
q = intersect(p,d,status);
if(status == light_source)
return(light_source_color);
if(status == no_intersection)
return(background_color);
n = normal(q);
r = reflect(q,n);
t = transmit(q,n);
local = phong(q,n,r);
reflected = trace(q,r,step+1);
transmitted = trace(q,t,step+1);
return(local+reflected+transmitted);
}
但光线追踪算法主要存在的缺陷有:
- 当光源面积较小时,从相机发射出的光线最终到达光源的概率随之变小,导致很多光线因为无法到达光源被浪费,形成大量噪点。如下图所示。
2. 光线追踪算法实际上并不是在求解渲染方程,没有使用BRDF函数而是基于简单的光线反射/折射原理,因此结果的物理正确性不能得到保证。
为了解决这些问题,研究者提出了下面将介绍的基于蒙特卡洛采样方法的路径追踪算法。
- 蒙特卡洛采样方法
蒙特卡洛采样方法是利用概率统计知识求解数值积分的一种方法。
问题描述如下:
我们需要求解如下所示的数值积分。
可以使用计算机通过采样的方法对该积分的值进行估计:
我们的目标是构造随机变量
如果我们已经知道了
则可以令
这样,我们就得到了
但问题是:实际中,我们往往不知道
假设我们共采样
该估计满足:
根据不同采样点的重要性,我们还可以引入参数
则:
以上就是使用蒙特卡洛采样算法求解数值积分的核心思想。
- 路径追踪算法
路径追踪算法是基于蒙特卡洛采样算法的光线渲染方法,其核心思想与光线追踪算法一致,也是让光线从相机出发寻找光源,但具体做法是:
从相机平面的每一个像素点发射出多条光线寻找光源,光线在与场景中物体相交,发生反射时,按照预先设定的概率分布函数从半球面选择一个方向出射,并按照BRDF函数分配出射光线的能量分布。其余部分与光线追踪一致。
路径追踪算法的本质是将多条光路对光照效果的贡献按照它们出现的概率结合在了一起,实现了渲染方程。
如下图所示。
值得一提的是,为了能够让算法中的光线反射的迭代能够终止,我们可以引入Russian Roulette的技巧:通过每次迭代时生成一个随机数来决定是否进行下一次光线的反射,阻止了无限迭代的可能。
其算法过程如下所示。
shade(p, wo)
Test Russian Roulette with p_rr, if fail then return 0.0;
Randomly choose one direction wi with pdf(wi);
Trace a ray r(p, wi);
if ray r hit the light:
return L_i * f_r * cos / pdf(wi) / p_rr;
else if ray r hit an obj at position q:
return shade(q, -wi) * f_r * cos / pdf(wi) / p_rr;
ray_generation(camPos, pixel)
Uniformly choose N sample postitions within pixel;
pixel_radience = 0.0;
for each sample in the pixel:
Shoot a ray r(camPos, cam_to_sample_direction);
If ray r hit the scene at p:
pixel_radience += 1/N * shade(p, cam_to_sample_direction);
return pixel_radience;
但值得注意的是,路径追踪算法并没有解决当光源面积很小时,发射出的光线很难寻找到光源的问题。
解决这一问题的一个很自然的思路是:既然从相机出发发射光无法到达光源,那么能否直接从光源出发发射光到达物体,直接计算直接光照?根据这一思路,我们可以使用对光源采样的策略提高路径追踪算法的效率。
此时由上图中的几何关系,将在BRDF半球上的积分转换到面光源所在的平面A上:
这一步的本质是改变蒙特卡洛积分中的采样概率函数,在光源方向的立体角上采样,其余部分不采样。我们将之前的路径追踪划分为:采样直接光照(对光源采样)与采样间接光照(均匀采样)两部分。
改进后的路径追踪算法中shade
的主要过程为:
shade(p, wo)
// direct light, sampling the light
Uniformly sample the light at x with pdf_light = 1/A;
Check visibility,
if invisible
L_dir = 0;
else L_dir = L_i * f_r * cos(theta1) * cos(theta2) / |x - p|^2 / pdf_light;
// indirect light, BRDF sampling
L_indir = 0.0;
Test Russian Roulette with p_rr
Randomly choose one direction wi with pdf(wi);
Trace a ray r(p, wi);
if ray r hit an non-emitting obj at position q:
return shade(q, -wi) * f_r * cos / pdf(wi) / p_rr;
return L_dir + L_indir;
2. 实现中的关键问题与解决方法
原理部分已经把路径追踪算法的过程讲得比较清楚了,实现中其实没太大问题。这里可以提的一个问题是当前点是否在面光源背面的判断方法:可以通过判断cos的正负号可以判断点是否在面光源的背面,结果如下所示。
对这样一个图中的光源:
检查前(上图)后(下图)对比:
其他测试结果
康奈尔盒
从上到下依次是:1. 只有环境光的结果 2. 只有面光源的结果 3. 面光源+环境光 4. 面光源+环境光+间接光(最终结果)
星空下的球
皇家超跑(个人作业中最满意的图)
街头超跑
斯矛革和它的宝物
另一只镜面龙斯矛革
不同材质(铜,金,银)的M4A1(模仿CSGO反恐精英中沙漠小城的场景)
二. 环境贴图重要性采样
- 原理介绍
环境贴图中,环境光源的分布往往是不均匀的。因此在直接光照中计算环境光的部分,我们可以对环境贴图按照像素的亮度进行重要性采样,如下图所示。
构建抽样表可以使用别名法(这个参考资料讲得很好)使得采样的时间复杂度为
在别名法中我们将构建环境贴图中每个像素点的采样概率表
其中
(你若问我上面的式子为什么是这样的,请见文章深入理解 PBR/基于图像照明 (IBL)(助教写的2333)
2. 实现中的关键问题与解决方法
- 使用别名法构建抽样表
我使用了vector<pair<std::pair<int, int>, pair<int, int>> > env_light_alias_table_idx
存放别名法中的像素点的下标,使用vector<pair<float, float>> env_light_alias_table_p
存放别名法中的概率表。
采样时只需要生成两个随机数,为时间。
auto rand_n = int(rand01<float>() * (env_h * env_w - 1));
auto rand_p = rand01<float>();
std::pair<int, int> sample_idx;
if (rand_p <= std::get<0>(env_light_alias_table_p[rand_n]))
{
sample_idx = std::get<0>(env_light_alias_table_idx[rand_n]);
}
else sample_idx = std::get<1>(env_light_alias_table_idx[rand_n]);
- 环境贴图像素坐标与入射光线向量之间的转换
转换过程:环境贴图像素坐标环境贴图纹理坐标球面角坐标入射光线向量。
关系为: (也是来自深入理解 PBR/基于图像照明 (IBL)这篇文章)
3. 测试结果
为验证环境贴图重要性采样的效果,进行了两组对比实验。
没有进行环境光重要性采样(对照组)
进行了环境光重要性采样(实验组)
夜晚环境中,去掉顶光源的环境:
没有进行环境光重要性采样(对照组)
进行了环境光重要性采样(实验组)
可以看到,相比于对环境光进行均匀采样,进行了环境光重要性采样后的画面某些地方比原来更暗(个人对原因的解释:由于环境光源分布的不均,这些地方确实应该更暗一些。但是可能这个解释是不对的,存疑)。
补充:对面光源进行重要性采样 & 多重重要性采样
实际中仅使用BRDF采样或仅使用对光源的重要性采样结果都不能达到完美的效果,如下图所示。(图片来自文章浅谈PBR:从光学原理到基于物理的渲染)
通过多重重要性采样可以解决上面的问题,如下图所示。本次作业由于时间关系没有进行相关的对比实验。
四. 参考文献
- 基于物理着色:BRDF https://zhuanlan.zhihu.com/p/21376124
- 《Real-Time Rendering 3rd》 提炼总结 第九章 · 全局光照:光线追踪、路径追踪与GI技术进化编年史 https://zhuanlan.zhihu.com/p/29418992
- 详解球面环境映射 - Spherical Environment Mapping https://zhuanlan.zhihu.com/p/84494845
- 深入理解 PBR/基于图像照明 (IBL) https://zhuanlan.zhihu.com/p/66518450
- 金属,塑料,傻傻分不清楚 https://zhuanlan.zhihu.com/p/21961722
- 一篇光线追踪的入门 https://zhuanlan.zhihu.com/p/41269520
- 时间复杂度O(1)的离散采样算法—— Alias method/别名采样方法 https://blog.csdn.net/haolexiao/article/details/65157026
- 多重重要性采样(很好的blog) https://airguanz.github.io/2018/10/15/multiple-importance-sampling.html
- 光线追踪器Ray Tracer:进阶篇(很好的图形学博主) https://yangwc.com/2019/05/23/RayTracer-Advance/
- 浅谈PBR:从光学原理到基于物理的渲染
因初学图形学,才疏学浅,文章中的任何问题还请大家指出,谢谢。
最后感谢助教 @Ubp.a 和课程老师刘利刚老师的倾情指导与课程同学们的帮助。