焦散(Caustics)在现实生活中随处可见,但在渲染图中却很稀有。阅读本文以了解为什么省略焦散 – 以及如何以 Corona 轻松渲染焦散。
首先,让我们复习一下什么是焦散。对于任何做过 3D 渲染的人——尤其是光线追踪渲染器——可能对焦散有一些了解。大多数人认为焦散是来自穿过玻璃杯或液体的光线,产生焦散这种有趣的亮点。
大部分的 CG 艺术家都知道焦散需要花费大量的时间和精力渲染,所以通常会省略焦散——而大家还是能在没有焦散的情况下渲染出写实的图像。
有些人则会做额外的操作,用作弊的方式产生焦散使图像更逼真。事实上,焦散对真实世界照明贡献很大。那为什么要忽略焦散呢?
在 Corona 4 中,程序开发人员决定将真正的焦散照明引入到渲染图中。有了焦散,我们可以创建更精确的图像光照。我们目标是让焦散更容易设置,更重要的是,使之对渲染时间有最小影响。
到处都有焦散——让我们来定义什么是焦散
我们先从定义焦散开始,观察为何在现实中,焦散占了图像照明的绝大部分。如前面提到的:大多数艺术家认为焦散是通过玻璃或液体聚焦的光。但计算机图形学的定义是: 焦散是任何从光源到高光(反射或折射)、到漫反射表面、再到眼睛(或摄影机)的光照贡献。
记住,即使是一片玻璃,比如窗户,也会折射光线。从技术上讲,所有透过窗户的光线都具有焦散性。
基本上,如果光线以高光反射的方式从某表面反射,然后光线照亮到另一个漫射表面时,这样的过程就是焦散。这表示在真实世界,焦散占了场景光照很大部分。
你可能会想:如果我们已经忽略焦散这么久了,何以渲染图还能看起来真实?简而言之:焦散多年来一直是靠作弊的方式产生。但在讨论如何造假之前,让我们先解释一下为什么要造假。
焦散是很难计算的
事实上,多年来我们用来计算焦散的算法是非常复杂的。有一些暴力计算法又称蛮力法(brute-force method)能做出些效果,但是通常来讲它们都会花费过多的时间或者做了过多的省略,那最终结果就是:它只能给你提供实际焦散贡献中的很小的一部分。
许多渲染器使用一种叫做“光子映射(photon mapping)”的技术,但传统上,这些方法用起来非常复杂——如果没有正确地设置,渲染会非常慢或者产生很糟糕的结果(甚至又慢又糟糕!) 但之所以有人发明像光子图这样的技术,是因为从纯光线追踪计算焦散是很大的挑战。以下详细说明:
焦散是如何整合进光线追踪流程中的?
探索光线追踪的最好方法是从观察自然开始。在现实生活中,光线是自光源发出的。光线从物体表面反射。这种反弹可以是通过反射或折射改变方向的镜面反射,也可以是朝四面八方扩散的漫反射。
假设我们根据这个模型来编写光线追踪渲染器——即从光源一直追踪到摄影机——我们将需要发射大量的光线来得到一张完整的图像。这是因为绝大多数来自光源的光线都没有投射到摄影机中。
因此,虽然这种方法最接近真实物理,最终会找到场景的所有照明贡献,但这个光照模型效率极低,甚至用超级计算机也需要几天才能得到简单场景的可用渲染。因此我们必须想出更有效的方法。
如果我们反向追踪光线,从摄影机开始追踪呢?
最好的解决办法是改变射线(rays)的走向。与其浪费大量的时间来计算无法到达摄影机的光线,不如从摄影机开始反向追踪直到找到光源?
这种方法被称为“反向路径跟踪(reverse path tracing)”——简称“路径跟踪(path tracing)”——今日,几乎所有光线追踪渲染器(ray tracers)都使用这种方法。事实证明,使用反向追踪,可以更有效地找到可用的光线 – 以更快的速度得到可用的渲染图。到底有多快呢,由原本需要几天的时间降到几秒钟就完成。
问题1:大光源 vs 小光源
但在应用过程中,我们开始发现反向路径跟踪的局限性。当射线离开摄影机寻找光源时,如果这些光源很大,例如环境光或区域光源,就很容易找到光源。但许多光源很小,例如一盏灯泡。因此,许多从摄影机追踪到的光线可能会完全错过光源。而那些随机找到的光源,最终会在渲染中产生白色的小高光——称为“萤火虫效应(fireflies)”。
解决方案1:使用光源采样(light sampling)来寻找微小光源
但是有个解决方案可以帮助渲染器确保不会错过光源——即使是非常小的光源。这种方法叫做“光源采样”。作法是随机地在光源上的选取采样点,并将采样点连接到渲染路径。这种方法确保射线追踪到光源上。对于小且直接光源非常有效。
问题2:间接光源,比如焦散,不能使用光源采样
请注意,上述解决方案谈的是 “小的直接光源“。问题是这种方法不适用于间接光源。其中一个原因是,虽然知道光源在哪里,但我们不知道间接光源的位置——说到间接光源,主要指的是焦散。一旦光线通过表面反射或折射,我们就不知道光源在哪里,直到追踪到光源。
所以当光源采样解决掉了直接光源的萤火虫效应时,我们仍然会从焦散高亮点产生很多萤火虫效应。与增加光源采样技术之前遇到的问题是类似的,随机光线可能遇到焦散的高亮点,并产生萤火虫效应。那么我们该如何应对呢?
作弊的技巧1:箝制(Clamp)一切!
许多渲染器都使用这个解决方案——箝制所有东西——讲白了就是用漂亮的话术来宣告认输。如果偶然遇到一束来自焦散的非常明亮的光线,“那么就箝制掉”。(或者干脆忽略之。)
到目前为止,穿过玻璃物体的光线没有产生焦散,我们只得到了影子。在有些情况下,箝制一切可以得到一张有点可信的渲染图。
但如果你回过头来考虑,即使是一片玻璃,技术上来说也是焦散性的,那么使用这种方法,我们会得到这样的图像:
作弊的技巧2:忽略玻璃
接下来讲另一个作弊方式。既然问题出在射线要么穿过高光表面,要么是在高光表面反弹,如果我们直接忽略玻璃,直接穿过它追踪射线呢?那我们就回到了光源采样那一步,回到了最简单的情形。
这个解决方案对建筑室内非常有效,例如:
但不幸的是,此时玻璃物体本身的效果就不太好了:
作弊的技巧3:混合玻璃/假玻璃/建筑玻璃
第三招,我们让一些光线穿过玻璃窗,但不是全部光线,这取决于玻璃的厚度、角度或颜色。这种方法可产生稍微可信的阴影形态:
这是大多数渲染解决方案在过去十年所用的技巧。有时被称为“混合玻璃”,“假玻璃”——还有个很时髦的名词:“建筑玻璃”。然而,以上这些作弊技巧没有一个是真正的焦散,因此没有一个是正确的。
如果我们不用作弊的技巧,那如果从双向追踪呢?
考虑到要得到正确渲染焦散图多么复杂且耗时,那么传统的作弊方法——比如“建筑玻璃”——可以算作是很好的折衷方案。直到 Corona Renderer 4 的出现。
如果我们告诉你,你可以很容易地渲染焦散,且只会对你的渲染时间产生很小的影响,会怎么样呢?这就是 Corona Renderer 4 的威力了——之所以达到这个效果,Corona 开发团队用的方法只是回归到基础罢了。
我们已经知道,如果追踪来自摄影机的光线(反向路径),在几乎所有的情况下,除了焦散以外,其他效果都非常好。而从光源开始追踪(正向路径),焦散效果会更好。但是,如果根据我们的需要,根据不同的情况,同时结合正向追踪和反向追踪两者的优点呢?注意这可并不是全新的概念——事实上,这项技术从 90 年代就已经存在了。1993年,Lafortune 和 Willems 共同发表了一篇关于双向路径跟踪的论文,里面提到了这个概念。.
想法1:使用双向路径跟踪
第一种想法是所谓的“双向路径跟踪”(Bi-Directional Path Tracing ,简称BDPT)。这个解决方案是相当快的,但当涉及到焦散时,最终会丢失了太多的焦散射线,而最终解算的结果,在很多情况下,几乎看不到焦散。
VCM 结合了太多的策略(而且速度很慢)
另一种作法是在 2012 年有人提出的,称为“顶点连接和合并(Vertex Connection and Merging)”,简称 VCM。该方法结合了光子映射和 BDPT。虽然这种方法更容易,可得到良好的结果,但会过度采样太多的射线,才能获得良好的结果,大幅增加渲染时间。
Corona 使用反向路径追踪和光子映射
新版 Corona 渲染器的策略,是更有效地利用反向路径跟踪和光子映射。但是与其让用户费力地建立有效的光子映射,Corona 渲染器会替您找到有效的光子映射,为您最高效率地得到最正确的结果。
这意味着,现在,我们能够使用不过于少的光线(如 BDPT 技术)或者不过于多的光线(如 VCM 技术)来渲染焦散。Corona 使用了恰到好处的光线,并产生了正确的焦散效果,最小程度地增加渲染时间。
这不代表焦散对 Corona 渲染器来说是个简单任务。撰写程序代码时,需要解决非常复杂的问题,比如:何时用正向射线,何时用反向射线?如何将这两种方法的结果结合起来?诸如此类。
但对用户来说,使用起来非常容易。产生焦散只是 Corona 4 中的一个勾取的选项方块。想渲染焦散吗?你将得到一个更接近现实的图像——焦散选项只会增加渲染时间约 50%。
“如果某张图具有焦散,那张可能是照片或是用 Corona 渲染出来的。”
— Vladimir Koylazov
在与 Vlado 的谈话中,他说他喜欢玩那种“猜猜看是CG或是照片”的小游戏。他总是会在图片中寻找焦散的痕迹——也就是说,如果图像中有焦散,那就应该是真的照片。但是现在 Corona 4 已经使得在渲染中添加焦散变得如此简单,那么 CG 或照片的测验将变得更加困难!
还有一件事……
值得注意的是,因为 Corona 现在能以非常精确的方式表现所有的光线——包括适当的焦散贡献——还有许多其他渲染软件包中看似微不足道的功能,包括:
- 正确的焦散动态模糊。举例,如果在街上看到一辆车的车轮发出的焦散,那辆车正在向前移动,而摄像机正以同样的速度跟踪那辆车。街道应该有相对于摄影机的运动模糊,但是焦散——街道上的焦散——不应该出现动态模糊。虽然理应如此,但您可能不会察觉到,其他的渲染引擎无法正确地做到这一点。
- Corona 4 的一大知名功能是光线混合器(Light Mixer)。由于焦散可以从任何不同的光源产生,所以焦散也可独立出来,可在光混合器中正确地混合。
- 如果你正在用不同的渲染引擎做焦散的实验,请试着创建一座有涟漪的游泳池;游泳池旁放一面墙——墙上照理来说应该出现泳池的焦散效果。使用 Corona 渲染器,您将同时在泳池底部和墙上看到焦散。
尽管这合乎逻辑,但对于其他渲染解决方案不见得做得到。原因是:透过高光反射元素实际上很难看到焦散。而池底的焦散,是透过光线的折射才观察到焦散的。
读到这里,你完全了解了焦散是多么重要,理解了为何长久以来一直被忽视,以及为什么众多渲染器要作弊这么多年。
你现在可以测试 CORONA 中的焦散特效,看看这么多年渲染图中漏掉了什么。
下载免费试用欲知详情: 请收听 CG Garage 第 237 集。Corona 的创始合伙人及主要开发人员 Ondřej Karlik,和研发伙伴 Jaroslav Křivánek 谈论为什么焦散很难计算。专访中还讨论了他们所采取的策略,他们对焦散未来的愿景,以及新的解决方案是否会应用到 V-Ray 中。现在就收听:
另外,也可查看 Ondřej Karlik 在洛杉矶举行 Total Chaos @ SIGGRAPH 2019,关于 Corona 渲染器的渲染焦散演讲录像: