Vincent Chan 的巴士站 🚉

写一个光线追踪渲染器

最近都在做一件事情,做一个光线追踪渲染器,一直很想揭开光线追踪渲染器的大门,于是跟着 Milo Yip 的步伐开撸了

用 JavaScript 玩转计算机图形学(一)光线追踪入门

渲染结果图: renderer img

其实制作的过程是非常坎坷的,我首先用 C# 按照博文的思路重写了一边,渲染出结果(1024x1024),总共耗时6秒,结果令人很不满意,觉得有点慢,于是打算用 C++ 重新实现一遍,使用 MSVC 编译器,第一次做出来的结果是2.1s,比 C# 快一点,但是优势还不是很明显。但是我做了如下改动之后,性能得到了极大的提升:

本来的写法:

std::shared_ptr<Result> function()
{
    if (do_something()) return std::make_share<Result>();
    else return null;
}

改为:

bool function(Result& result)
{
    if (do_something()) 
    {
        result = xxx;
        return true;
    }
    else return false
}

经过这一改动之后,渲染实践从原来的 2.1 秒瞬间缩短到了 0.6s,有点令人不可思议,个人猜测是 shared_ptr 进行频繁的分配和释放空间导致的速度大幅度变慢。0.6s 的渲染时间让我觉得很满意,本来想继续做下一步实验,但是不知道怎么的,我总是觉得程序还能优化。于是我看了看 Profile,没发现什么问题,我觉得该改的都改了,再改可能也得不到大幅度的提升,后来我往另一个方面想:多线程

光线追踪算法每个像素的计算之间没有任何关系,这意味着,可以同时进行计算,然后最后把结果合并,pbrt 也讲了这种思想,于是我也试试。一开始我使用了 Windows 的 API,可是我没有什么 Windows 的编程经验,Win32 的 API 都是现查现用,于是出现了一个我解决不了的问题,就是我用WaitForMultipleObjects 函数去等待子线程结束,调度线程才结束,可是每次调度线程自己先结束了,WaitForMultipleObjects 函数没起到作用,我检查了结果,在正确范围内,也没发现问题,但是就是不行,没办法解决。

后来采用 boost 的 thread 框架,成功地使用了 join,调度程序等所有渲染都完成了才结束,由于我使用的电脑的 CPU 是 i5-5200U,双核四线程,所以我开了四线程,进行渲染,总共耗时 0.3s,速度可以说是加快了许多,我尝试开八线程进行渲染,也是 0.3s,速度没有得到提升,说明四线程在我的电脑上应该是最合适的。

多线程的问题解决了,然后就可以进行下一步的实验了。