光线模拟器

上一章节我们最终提到光线追踪在模拟着色和灯光效果(例如反射、柔和阴影等)上比栅格化更好。没有这些效果,会使图像缺乏真实感。在深入此话题前,先来看看一些真实世界中的图像,以便更好的理解这些效果。

反射

完美镜面

当光线和一个完美的镜面所接触时,所得到的反射光角度是可预知的。可以通过反射法则计算出新的方向。该法则类似从墙面弹回的网球,一条光线在接触到表面后会改变方向,光线的反射方向是入射方向在入射点相对于法线的反射。更普遍的说法是,反射光线总是射离材质表面,且反射角等于入射角。如下图所示,法线和入射向量所组成的角度,等于法线和出射向量所组成的角度。注意例图中以水面作为反射表面,而实际上水和玻璃比起金属在反射上的表现要差很多。

反射

透明

光线在碰到透明物体(比如玻璃橱柜)时会发生反射和折射。

透明物体

传输作为折射中常用的术语,与其字面意思大相径庭。在此传输所指的是,一小部分入射光线进入物体的一边,而从另一边离开(这也就是为什么我们能够透过窗户看到东西)。不管怎样,在光线接触到透明物体表面的那一瞬间,方向变了,所以我们称为折射。当光线从一个透明媒介比如空气,进入另一个比如水或玻璃时,会发生弯曲效果(不管是从空气到水,还是水到空气,光线都会发生弯曲)。连同反射,折射方向可以使用Snell法则进行计算。多少光被反射、多少被折射则由Fresnel等式给定。在渲染中这两个公式非常重要。下方的图,显示了一条光线进入一块玻璃产生了折射,在离开玻璃后再次产生折射,直到最后碰到下方的表面。如果表面是一个物体,我们就可以透过玻璃看到它。

折射

次表面散射

次表面散射

次表面散射是半透明在技术上的称谓。半透明表面是既不完全透明也不完全不透明的表面,但实际上,半透明物体和透明没什么关系。半透明效果在从背后观察蜡、或者由玉或大理石组成的小东西,或者一些比较薄的组织(比如皮肤,树叶)的时候特别明显。半透明就是光线在穿过材质的时候,方向发生了改变,以至于光线离开物体的点和入射点不在同一个方向上。次表面散射非常难以模拟。

间接漫反射

间接漫反射

如上图所示,一些装饰用的物体表面,不朝向任何光线。它们既不朝向太远,也不朝向天空(天空可以视作一个超大光源),但它们也不是全黑的。这是怎么回事?这是因为太阳光直接照射到地面后,反弹回环境中的一些光线最终照射到了这部分接受不到阳光的物体。因为表面接受的是间接来自光源的光线,所以称为间接光。术语中的漫反射,意味着反弹的光线是漫反射的。

间接光镜或焦散

间接光镜或焦散

漫反射物体的反射光会照射其周围部分,类似的反射物体也可以间接的改变环境中的光线照亮其它物体。透镜或水面的波纹可以将光线聚焦成一条直线或者某种样式,这我们称为焦散()。当光线在迪斯科的玻璃球中发生反射,在夏天的窗户上发生反射,或者强光射在玻璃上时,容易产生焦散。

软阴影

软阴影

迄今为止我们讲述的大多数效果都和物体本身材质有关。而软阴影只是一个几何问题,和物体以及光源的形状、大小以及所在空间的位置有关。

大家不用为此好奇,我们之后会持续学习这些。这篇教程的关键点,是观察一些真实世界的图片,分析它们的光影效果,之后我们会重建它们。

记住这篇文章所讲的,漫反射在所有视角方向上显示的亮度是相等的,而镜面反射在视角方向的亮度是最亮的(如果移动镜子,会发现到图像的改变)。我们说漫反射的交互和视角无关的,而镜面交互是依赖视角的

光线传输和着色:两个相关但又不同的问题

之前快速浏览这些效果的原因是需要了解两件事:

  • 物体怎样显示,只取决于光线和材质交互以及在空间中穿越的情况。

  • 所有这些效果可以大致分为两类:

    • 和显示物体的方式有关。

    • 和物体接收光线的多少有关。

      前者包括,反射、透明、镜面反射、漫反射和次表面散射。后者包括间接漫反射、间接光镜和软阴影。对于第一类称为*着色*(显示物体是什么),对于第二类称为*光线传输*(光线如何在不同的材质的表面间传输)。
      关于着色,将会学习光线和材质如何交互。换句话说,就是了解从光线接触到物体的那一刻开始,到离开物体的那一刻结束之间发生的所有事情。
      关于光线传输,将会学习光线在表面之间来回反弹时候发生的事情。反射于不同的表面间是什么情况?不同的反射间(漫反射、镜面反射等)又是什么情况?光线会去哪儿?是否任何几何体都能做遮挡?有遮挡物的情况下会产生什么效果?再透彻点,光线传输感兴趣的是光线从光源到眼睛的路径(称为光线路径)。

注意着色和光线传输之间没有太明显的界限。在真实世界中,它们没有区别,所有关于光的传播都取决于从光源到眼睛之间碰到的物体。但是,在图形学中是有区别的,因为这两件事没法通过一种方法来进行有效的模拟。让我们来解释一下。

假设把整个世界以原子级别复制到计算机程序中,代码就是定义了光线和所有原子的交互规则,为了产生一副完整的图片,只能等到光线弹来弹去直到碰到我们的眼睛。这样的程序创建起来很直观,但不幸的是,以当今的技术无法轻易实现。即使拥有足够的内存装下原子级别的世界模型,也没有足够的计算能力去模拟无数光子和无数物体之间的交互。因此,需要另一种方法,而所要替换的就是最花时间的那一部分。现在比较明确的是,光从一个表面到另一个表面是直线传播的,但接触到表面后发生了什么,就很复杂了(这需要大量时间来模拟)。

因此,在图形学中,我们人为的对着色和光线传输做了区别。着色的意义在于设计一个数学模型来近似模拟光要接触的物体,之后交互部分通过物理模拟只需要花少量时间。另一方面,我们就有条件模拟光线在表面间传播的路径。有了区别,我们就可以分别针对两类问题设计策略。

模拟光线传输比模拟光和物体交互简单一点,然而,我们不能说它就是简单的。一些内部反射显然要更难模拟(焦散就是例子,这将会在下一章解释)。设计一个好的数学模型用于模拟光和表面的交互是困难,设计一个好的光线传输算法也是有挑战的(下一章将会了解)。

全局光照

先让我们放慢脚步。你可能会认为(通常是错觉)大多数表面之所以可见是因为收到了来自光源的光,实际上很多情况是通过来自其它表面的间接光照亮的。环绕四周,大致观察一下有多少显示区域来自直接光源(太阳、灯光等),哪些来自间接光源。间接光在真实世界中扮演者至关重要的角色,如果忽略它,照片将很难显得真实。当渲染时同时模拟直接光和间接光的,我们称为全局光照。对于光照渲染,理想上尽可能模拟所有的光照情景。所谓一个情景是指包含在场景中的物体,物体的材质,场景中的光,光的类型(是不是太阳、灯光、火焰),它们的形状以及这些物体的散射情况(这会影响光在表面间的传播)。

在图形学中,直接光和间接光是有区别的。如果不模拟间接光,还是可以通过直接光看到物体,但是不模拟直接光,图像就会一片漆黑(在以前,直接光也被称为局域光,这是为了区别于表面互相影响的全局光)。那为何还要模拟间接光呢?

实质上,看不看见是很容易做到的。光在进入眼睛前会和表面做很多交互,这些细节会在下一章解释。如今我们考虑光线追踪,我们可以解释最耗费时间的是光线和几何体相交测试这一部分。越多相交,渲染越慢。对于直接光,只需要找出(从摄像机射出)光线和几何体的交点,然后再从这些交点投出光线(阴影线)。这就是产生一张图片最基本的步骤(我们似乎可以忽略阴影,但阴影其实是非常重要的视觉线索,可以帮助我们找出物体在空间的具体位置,也能帮助我们认识物体的形状,等等)。如果想模拟间接光,大量的光线会投射进场景中,它们在物体表面间弹来弹去产生大量的信息。在直接光之上模拟间接光,不是把光线计算两遍的事情,而是数量级上升。更糟的是,当计算间接光时,我们从一点P投射出的新的光线的信息来自,场景中其它朝向P的表面反射出的光。注意到这是一个递归过程,这也就是为什么模拟间接光的耗费相当昂贵。

为什么这么困难?实际上,使用光线追踪会非常直观(但非常耗费)。下一章解释的光线追踪是模拟真实世界中光线最自然的方法。因为它提供了一种简单的方法来收集场景中光线的信息。如果系统有能力计算光和几何体的相交,那么就可以解决可视化问题,模拟直接或者间接光照。那使用栅格化,怎么收集信息呢?常见的误解是认为模拟间接光就需要光线追踪。这是不对的。别的方法也是有的(基于海量点、光子图表、抽象点光、阴影图表等。光能传递就是另一种计算全局光照的方法。现在已经不太用了,不过在8、90年代很流行);这些方法在不同的场合下都有各自的优点,是光线追踪的一个不错(谈不上更好)的替代方案。不管怎样,如果系统支持光线追踪,它仍然可以算是“简单”的方法。

如上所述,光线追踪在模拟间接光上比其它方法慢。此外,光线追踪有好多种形式,都有着各自的问题(除了计算昂贵)。其中之一就是噪点。此外,在下一章讲光线传输时我们会了解到有些光照效果是非常难模拟的,还有一些方法,犹豫效率只能用于特殊情况下。比如,单纯的“反向”光线追踪,可以模拟直接光照和间接漫反射,但在模拟一些特殊光照效果,比如间接镜面反射时就不是很有效率。很快你就会认识到,单纯的光线追踪是满足不了要求的,需要发现别的替代方案。光子图表就是很好的例子,它的出现就是为了模拟焦散(一种在漫反射表面发生的镜面反射 —— 属于一种间接镜面反射),如果用光线追踪反而非常难以计算。

为什么光线追踪比栅格化好?好在哪里?

其实上一段落,我们已经给出了答案。但是,重说三。光线追踪相对于其它方法,比如栅格化,在真实世界的光线时更自然,更直观。并且不像其它用来解决可视化问题以及光照的方法,光线追踪可以一次性解决这两个问题。如果使用栅格化计算可视化,就需要其它方法来解决全局光照。

单纯的实现一个光线追踪是简单的,但考虑到效率,就需要很多复杂的工作。即使是现在光线追踪的计算还是昂贵的,复杂的场景会大幅增加渲染的时间。

Blinn’s Law

Blinn定律或者说效率增长悖论。“什么是Blinn定律?大家应该都熟悉摩尔定律。但对于图形学,Blinn定律的大致意思就是,一个动画工作室为动画的一帧投入10个小时的计算时间,那么十年之后,计算一帧仍然需要投入10个小时,不管处理器有大提升。(转自 http://www.boxtech.com/)

所以在实际工作中,优化代码也是非常必要的(特别是在产品环境中)。即使暂时撇开技术问题,噪点问题以及模拟焦散的问题仍然存在。解决这两个问题比较粗暴的方法是,直接使用更多的光线,但这会带来更多的消耗。所以,还是有很多研究找出解决这两个问题的渲染方法。光线追踪可以和其它技术混合使用,使得更有效率的去模拟一些很难模拟的光照效果。