前言
以前玩游戏的时候,经常会用到光线追踪技术来提升画面品质,每次开启光追之后游戏世界的画面就进入了一个新次元(帧数也是)。最近刚入门图形学,加上对光线追踪这项技术感兴趣,于是开始自己搓一个光线追踪。
正文
第一阶段:纯球体光追
我的光线追踪之旅始于一个纯球体的渲染。我参考了许多其他人的光追项目,最后得到了这个效果。
其他项目都会为物体手写一个材质脚本,但我希望我的光追可以与编辑器更加融合,所以还写了一个获取用户材质球上属性的脚本。
参考的最多的是这个项目:https://github.com/teamclouday/PathTracer/tree/tutorial
但这个项目有很多坑,感觉架构和命名上都十分混乱,有一些很迷惑的写法。这让我在下一阶段中吃了不少苦头。
第二阶段:实现AS加速结构
随着对光线追踪的深入理解,我意识到,如果想要渲染更复杂的场景,就必须解决效率问题。于是,我着手实现了加速结构——BVH(Bounding Volume Hierarchy,包围盒层次结构)。
通过BVH,场景中的物体被组织在一个树状结构中,每个节点都有一个包围盒,用于快速判断光线是否与物体相交。
为了一步到位,我还学习了AS加速结构。在学习过程中,我发现网上的教程和参考项目的写法非常不一样,他多出来一个TlasRawNode,而我并没有搞清楚这是什么。于是我花了一周的课余时间来深入学习AS加速结构,并且从参考项目的写法中反推过程,然后从过程推断结构,最终使用Gizmos正确地把包围盒画出来了。
ps:在实现过程中,我遇到了一个棘手的问题。当使用栈来实现光线与BVH的相交判断时,光线总是无法正确地与BVH相交,而使用循环时却可以。这个问题导致帧率极低,只能渲染出单一的信息。下图是单一信息图(分别是法线、BaseColor、阴影)
第三阶段:实现初步光线追踪
经过不懈的努力,我终于找到了问题所在。
这一个小小的问题花费了我一个星期,我不断地对比代码,查看逻辑,还是没能查出问题。最后是通过版本管理工具来对比diff,逐步缩小问题范围。
最终问题所在:
这里的bnodes.Count,我在重构的时候把它独立成一个变量,写在了while外面,但注意while内部的操作是 bnodes.Add,也就是说每次循环都会导致bnodes.Count的变化,而我却只是在外面记录了他的初始值。所以以后Copy重构其他人的代码的时候,要注意这些小细节
初步实现光线追踪之后再来复盘一下,我发现这里用到的数据结构和游戏引擎概论中提到的使用索引来记录材质等数据很相似,又是一种知识之间的互通。
未来打算
虽然我已经实现了初步的光线追踪,但我知道这只是一个开始。未来,我将进一步优化算法,提高渲染效率,解决色彩问题。
之后可能还会研究一些更深层的项目,这项目大概有5w+代码量(可能更多)。并且研究一下Wavefront,然后看一点前沿的东西。最终目标是实现Real-Time RayTracing!
附上Github链接:https://github.com/UriPomer/Unity-Path-Tracing