当我们谈Raytracing时我们在谈些什么

当我们谈Raytracing时我们在谈些什么

【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!


科普性的介绍一下光追。不讲蒙特卡洛和分层抖动采样,不讲PBRT,不讲BRDF,不讲渲染方程,降噪方法,不讲SDF的细节概念。简而言之,复杂的一概不讲,麻绳专挑细处断,柿子专拣软的捏。

什么是Raytracing?

一、Raytracing算法框架

Raytracing首先是一种算法框架。在这个框架下,其实包含了非常多种算法,他们也不是并列的关系,可以用于Raytracing的不同阶段,也可以组合使用。

Ray Marching光线步进
在Raytracing计算过程中,最复杂的一步往往是计算光线和场景的交点。如果场景是用几个简单的几何体组成,那么用解析表达式求准确的交点也很简单。但场景往往有非常多的复杂模型,那么用解析表达准确求交就比较难了。假如有一种方法可以方便地判断某个点p是不是在场景模型内部,那么沿着光线方向一步一步的向前走,逐个点判断是否到达了模型内部,就可以求到场景和模型的交点了。

这也是SDF在Raytracing中的最重要的应用。基于SDF可以知道每步前进多少步长从而保证不会和场景相交,那么就可以大大减少没用的步数。

Ray Marching在实时渲染中的应用很多,例如体积云、体积雾;SSGI、SSR等各种屏幕空间效果。

Path Tracing 路径追踪
Path Tracing应该算是最正统的Raytracing算法了,甚至在很多情况下,我们说某些离线渲染工具实现了Raytracing算法往往就是指实现了Path Tracing。

Path Tracing就是从相机往每个像素方向发射一条射线,然后计算射线在场景物体之间的多次散射、折射、反射,最终Trace到光源,作为一次有效的Path。累加所有可能的情况之后,就得到了非常正确的场景渲染结果。如果材质复杂,有各种粗糙漫反射需要往多个方向分别Trace的情况,需要的计算量是非常大的。

Path Tracing又可以细分为单向路径追踪和双向路径追踪(Bidirectional),双向路径追踪是指,从相机出发发射射线和场景求交,并从光源发射射线和场景求交,然后把这两个交点连起来,如果这个连线中间没有遮挡,那么就找到了一条有效的Path。通过这种方式,就可以避免很多Path Tracing的射线最后超出了反射限制次数却Hit不到光源的无效遍历。

Photon Mapping 光子映射

Photon Mapping是从光源出发发射射线,射线和场景求交后,在交点位置放置光子。然后在Relighting场景时,收集场景中的光子用来照亮场景。

Cone Tracing

Cone Tracing顾名思义,就是在Trace的时候不再发射射线,而是使用圆锥求交。这种方式可以大大减少需要Trace的射线的数量。Cone Tracing往往和场景的体素化表达结合在一起使用。也有一些别的应用,例如Cone Tracing结合SDF来估算软阴影。

这几种算法特别是Path Tracing、Photon Mapping一般用在Global Illuminatioin全局光照计算比较多。但Raytracing算法框架还可以用来做很多别的事情,除了前面提到的体积云体积雾等应用,还可以应用在遮挡剔除算法中等等。

二、Render Pipeline 渲染管线

Raytracing也是一种渲染管线。当我们说Raytracing管线的时候,他是一种和光栅化管线相对的概念。


光栅化管线和Raytracing管线对比

两种管线的思路完全不一致。光栅化管线是把三角形离散到屏幕上,然后基于深度排序做一些光照计算。而Raytracing管线则是对每个像素发射一条射线,记录射线和三角形的求交结果,然后计算重心坐标、uv,再去做光照计算。当然,一般Raytracing管线不会只发一次射线就完,会基于Primary Ray的求交结果继续下一次Secondary Ray的求交。Raytracing管线可以用多次射线求交的结果接管GI、阴影计算、反射计算等等,例如光栅化管线常用的Shadowmap,就可以通过向光源发射射线判断是否在阴影中来代替。

Raytracing管线的效果是不是一定比光栅化管线好?我很喜欢下面这个对比,哪个是光栅化的结果?哪个是Raytracing管线的结果?


http://www.realtimerendering.com/erich/AnIntroductoryTourOfInteractiveRendering.pdf
http://web.cs.wpi.edu/~emmanuel/courses/cs563/S10/talks/wk10_p1_steve_Mirror_Reflection.pdf

一般大家会觉得左边这个是光栅化管线的结果,右边这个是Raytracing管线的结果。但其实左边这个才是Raytracing的结果,因为里面有一个镜子和镜子之间的无限反射效果,这在光栅化管线中比较难实现。

笼统来说,游戏等需要实时渲染的场景目前一般用光栅化管线,而允许比较慢的速度离线渲染的场景才会使用光追管线。

那么光栅化管线是不是一定比Raytracing管线快?一般都认为实时渲染只能跑光栅化管线。不过我在测试中发现,如果不考虑Secondary Ray,只考虑Primary Ray,即每个像素只做一次求交,得到交点后采样贴图,和光栅化的PBR Shader一样计算,帧率居然还有略微提升。这是因为Raytracing管线完全不需要考虑遮挡剔除、DrawCall提交的消耗;如果连Raytracing最复杂的多次反射Secondary Ray的消耗都没开,那谁的性能好还真不好说。

但我的测试环境过于理想了,场景简单,没有考虑任何的半透明的渲染、以及TAA等后处理。如果这么简单的用光线求交结果+光照计算作为最后的Screen Buffer结果,没有深度信息,那么很多其它效果就很难处理了。所以,如今我们说Hybrid管线,往往是用Raytracing来生成Gbuffer,然后再基于Gbuffer来做其他的效果。

三、HWRT硬件光追

现如今,随着硬件的发展,我们说某某3A大作里面有Raytracing,一般是指用了硬件光追。

NVIDIA的Pascal架构GTX 10系列其实就能跑光追,但是他并没有设计专门的RT Core用于光追计算的加速。从Turing架构的20系列开始,显卡就加入了RT Core,因此也改叫RTX系列,包括Ampera架构的RTX 30系列和Ada Lovelace架构的40系列。其他厂商也有对硬件光追的支持,那么支持的怎么样呢?

不妨看看Imagination发布的这张图。忽略Imagination自我评价的Level4和Level5,光看前几个Level,大致可以看到各家厂商做到了什么程度。

Imagination认为,Level1就是基于软件实现硬件光追,一般没有设计专门针对Raytracing计算加速的硬件,例如苹果和Mali就是Level1。假如你在硬件设计上针对光线和Box以及光线和三角形求交有专门的加速,那么你就达到了Level2,例如AMD。假如你对BVH的管理和遍历过程有硬件加速,那么你就达到了Level3,例如RTX 30系列。假如你对BVH的遍历和线程一致性排序解决的比较好,那么你就达到了Level3.5,例如RTX 40系列。

  • 苹果发布会提到A17已经有了Hardware-accelerated Raytracing。

什么是线程一致性问题?

平行的光线在经过真实材质的反射、折射后,往往会朝向完全不同的方向。或者一束平行的光线,A和某个模型相交了,而B没有相交,那么A和B后续的Trace计算就是完全不一致的。这种不一致性对GPU的并行架构其实是很不友好的。

Raytracing API
需要使用硬件光追,就需要使用支持的Raytracing API。比如DX12的Raytracing API(DXR),还有Metal Raytracing和Vulkan Raytracing等等。

我做了一个小调查,周围人中好多同学都写过光追Demo。不过大家往往都是从C++或者别的语言的CPU版本实现开始的。比如最著名的教程Ray Tracing In One Weekend系列。

一般教程都是从基础几何定义开始讲,如何定义光线、如何定义几何体,然后讲讲如何做场景管理,如何加速射线和几何体的求交,如何随机采样,如何处理相交后的光线,如何处理材质,等等。出一个很漂亮很有成就感的图片往往也是需要几分钟起。

写过硬件光追的同学就少得多了。但其实,用Raytracing API来写光追更简单,不需要自己处理场景管理、光线求交等流程。以Unity的DXR的Demo为例,把大象放进冰箱只需要三步:

  1. 把所有需要Trace的Renderer放进AccelerationStructure(加速结构)。

  2. 写一个Shader发射光线。

  3. 在模型Shader中处理光线相交后做什么,例如做一些光照计算,或者继续发射下一次光线。

就完工了!是不是超简单?下图是Unity的HDRP给出的应用了HWRT后的对比图:

当然,也离不开各式各样的Bug和Crash:

四、Raytracing和GI

GI(Global Illumination,全局光照)考虑的是光线在场景中多次折射反射造成的直接光结果和间接光结果。只看文字,和Raytracing的概念很像。

Raytracing和Global Illumination全局光照是什么关系呢?有的同学不太区分,会认为这两个是同一件事。比如有的同学会说:我们的PC版本在4090不用考虑GI方案,大不了上Raytracing(这里指的是硬件光追)。

前面介绍了这么多,可以了解到Raytracing和GI其实是不一样的概念。Raytracing除了是算法框架也可以指渲染管线,不仅仅只用来做GI方案。而在GI方案设计和优化时,往往会用Path Tracing来先做一个Ground Truth,来指导算法的优化。GI方案中也往往包含Raytracing的过程,比如VXGI方案就使用了Cone Tracing。利用HWRT来加速也是常见的思路。

最近最火的UE5的GI方案Lumen,整个算法流程很多步骤就是使用SDF来加速Ray Marching过程来Trace的。

Lumen支持用HWRT来优化镜面反射等效果,也支持不开HWRT。

那么GI是不是一定要有Raytracing算法?也不一定,例如经典的Radiosity算法,就是把场景分成多个Patch,然后根据Patch之间的距离和角度预计算一个Patch之间的间接光漫反射的影响关系,然后列一个巨大的方程,通过解这个方程,来计算整个场景的GI结果。

五、Hogwarts Legacy的HWRT

《Raytracing on AMD's RDNA 2/3, and Nvidia's Turing and Pascal(译)》里有Hogwarts Legacy的AccelerationStructure抓帧分析,可以看到Hogwarts基本是把整个场景包括动态物体都非常粗暴地丢进了AS里来做HWRT。

效果上引用一些效果对比截图:

反射和阴影部分相对提升比较明显。AO部分似乎使柜子内的过渡也变得更自然了一些。

六、写在最后

Raytracing不是银弹,如果想提升画面,Raytracing并不是一切问题的答案。事实上,Raytracing在项目中的落地会遇到各种各样的问题,需要大量的时间和精力才能解决。而且还容易沦为噱头,被用户喷:开了不如不开。革命尚未成功,同志任需努力!毕竟,Unity是需要代价的!


这是侑虎科技第1473篇文章,感谢作者浦夜供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)

作者主页:https://www.zhihu.com/people/pu-ye-4

再次感谢浦夜的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)