Path Tracing学习笔记

看了Games101中关于Ray Tracing的内容后,自己其实从实现层面还是没理解的,因此找了网上的Path Tracing实现案例再巩固学习下。

代码来源:

smallpt: Global Illumination in 99 lines of C++

页面下方还有其他各种语言的实现,另外还有基于GPU的实现(这个有交互,很适合用来做Ray Tracing的演示)。

PS:这个代码是纯计算密集型的程序,很适合用来做性能测试。

渲染器特点

  • 使用蒙地卡罗路径追踪(Monte Carlo path-tracing)来产生全局照明效果
  • 支持三种双向反射分布函数(bidirectional reflectance distribution function, BRDF): 镜射(specular)、漫射(diffuse)和玻璃(即纯折射的介质)
  • 从漫射光源产生柔和阴影(soft shadow)
  • 使用2x2超采样(super-sampling)去实现反锯齿
  • 使用OpenMP作并行运算,充份利用多核性能

代码兼容性修改

原始代码距今已经10多年了,直接导入VS2019会报错,因此需要先修正一些问题。

导入代码

想要通过VS调试这部分代码,得先生成VS项目。注意不要直接基于当前代码创建项目,而是先创建一个Console类的C++项目,然后将代码复制进去。

这是因为基于当前代码直接在编辑器中创建项目,可能会弄成win类型的项目,导致后面编译报错。

运行按钮显示“附加”而不是“开始”

这是因为打开项目时,从包含它的文件夹中直接双击文件打开了项目,而不是从VS中打开它。

未定义标识符 “erand48”

这个函数应该是已经被移除了,需要自行实现该函数:

https://stackoverflow.com/questions/27198584/erand48x-not-working-in-c-visual-studio-12

注意函数的参数类型,要从int改为unsigned short*:

1
2
3
double erand48(unsigned short* X) {
return distr(generator);
}

未定义标识符 “M_PI”

https://qa.1r1g.com/sf/ask/1824575161/

1
2
3
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>

注意define必须放前面,放后面会报错。

无法解析的外部符号 _WinMain@16,函数 “int __cdecl invoke_main(void)” (?invoke_main@@YAHXZ) 中引用了该符号

这就是前面提到的,需要先创建一个console类型的项目,然后手动复制代码进去的原因:

https://blog.csdn.net/xiwan0902/article/details/71515038

‘fopen’: This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

https://zhuanlan.zhihu.com/p/386182672

为了简便,我是直接忽略了这个报警,即在文件顶部添加了:

1
#define _CRT_SECURE_NO_WARNINGS   

0x00007FF6FE5D4D37 处有未经处理的异常(在 smallpt-cpp.exe 中): 0xC00000FD: Stack overflow (参数: 0x0000000000000001, 0x0000004645EE3F90)。

https://www.codenong.com/cs105750005/

(TODO)性能

这段C++代码执行,性能非常差,比JS还慢得多。

运行期间CPU使用率才10-20%,怀疑是没有将多核利用起来。

还有就是可能写法不对。

JS的都比这个快得多。

100采样,JS大约在60s左右。

C++这个,4采样,就花了34.5s。