A practice of Physically Based Rendering 3rd Edition.

相机变换在光栅化和光线追踪当中的不同

在光栅化中,我们通常使用MVP矩阵把顶点变换到裁剪空间,然后送给片段着色器进行着色。这时候我们最终要操作的步骤回到了片段上。然而对于光线追送, 我们的出发点是屏幕上的采样点,然后根据给定的摄像机(观察矩阵)需要生成一个这个采样点对应的光线,最终是得到一个在世界空间当中的射线。可以发现, 这两个过程是相反的。所以在观察变换这一块需要相反的变换。

对于一般光栅化的过程比较简单,只需经过$MVP$这种常规的变换就可以了。因为接触的比较多,所以很熟悉。

对于光线追踪,我们需要给定屏幕上的一个点,生成一条在世界坐标系中的射线。首先需要把屏幕上的点变换到观察空间,然后用这个点和相机原点得到在相机空间中的射线, 最后通过V矩阵的逆矩阵变换到世界坐标系中。把屏幕上的点变换到观察空间首先需要变换到屏幕–(缩放)–> NDC–(透视除法)–>裁剪空间–(P的逆矩阵)–>观察空间。与光纤追踪不同的是,使用光栅化时,硬件 帮我们完成了裁剪空间到屏幕空间的转换。在这里,我们需要把屏幕空间变换到裁剪空间中,这一步比较直白。因为我们假设屏幕就是裁剪空间中的前平面,z值为0。然后直接变换到相机空间。

真实感相机

在图形学中所使用的MVP矩阵定量的描述了物体到投影平面的空间变换关系。从真实感绘制的角度来讲,还需要从光学的角度去模拟相机拍摄的成像过程。一般在真实感绘制中,我们需要在几何光学的层次上去模拟光线的传输,其中就包括光线在镜头中的传播以及成像的过程。 下面就简单的介绍一些光学模型。

如果不用任何成像系统,直接让把传感器对准场景,那么在传感器上成像的效果是什么?当然是模糊一片,在没有任何过滤的情况下,场景中任何一点发出的光源都会对传感器上任何一点造成影响。呈现清晰的像的前提就是场景中任何一点发出的光线只对传感器上的一点造成影响。也就是一对多一对一的过程。最简单的滤镜就是小孔成像。这是一种最理想化的成像模型,只有一条光线能经过小孔。这种成像系统没有焦距,也就是可以在小孔后的任意距离上呈现清晰的像,考虑到光线的衰减,只会有明暗的不同。根绝小孔成像的原理,如果我们把小孔尺寸调节到一个合适的位置,那么应该是可以呈现质量非常好的像的。但是由于衍射,在我们缩小小孔的过程中,成像会失真。这也就是为什么小孔成像的质量不高的原因。

然后就是透镜成像。透镜的作用就是在规避小孔成像的缺点的情况下,产生一对一的影响。这里又可以分为两种,第一种是单透镜,可以实现虚化(景深)效果。这里涉及到一些概念,包括光圈(aperture),景深(depth of filed),弥散圈(circle of confusion)。 景深的程度其实由弥散圈,传感器性质以及人眼的分辨率共同决定的。

给定一个成像平面位于$z_f^{’}$(一般位于焦点内),有其所对应的一个能够对焦在这个成像平面上的物体的距离$z_f$。对焦的过程就是调节$z_f^{’}$的过程,当把成像平面调整到焦点的位置上时,就对焦在了无限远处,实际上就是能看清很远的地方。在$z_f$的前后范围内,有一个能够成人眼能够分辨的清晰度的像的范围。这个范围就是景深(Depth of Field)在这个范围的前后的边界的位置上所成的像不能在成像平面上会聚成一点,而是一个有一定直径的光斑。这个圆圈就是弥散圈。只需要简单的几何推导,弥散圈为$$\begin{align}d_c=conf(z)=\vert \frac{d_{1}f(z-z_f)}{z(f+z_f)} \vert,其中d_{1}为光圈大小\end{align}$$。如果我们把这个弥散圈当作一个衡量成像分辨率的指标,即当这个光斑大到一定程度,使得相机的传感器和人眼都不能识别出清晰的图像。那么给定一个弥散圈,就能确定在某位置物体的景深范围。这样的话,我们会有两个相同的解释方式:其他条件相同的情况下,相机的弥散圈越大(无论以怎样的方式实现,比如更高分辨率的成像传感器,或者是其他什么黑科技)景深越大,则成像清晰的范围就越大,越不容易产生模糊效果。与此等价的说法是:其他条件相同的情况下,景深越小,弥散圈越小。 公式$(1)$ 的曲线形状类似于$\vert log(x) \vert$,$conf(z) = 0$的零点是 $z = z_f$。给定一个相机的$d_c$,在这个曲线上画一条横线,对应的两个$z_1$,$z_2$就是对焦在$z_f$处物体的景深范围,可见前景深与后景深的变化不是对称的。$d_1$对于这条曲线的影响就是在其他条件相同的情况下如果$d_1$越大,那么这个曲线越收紧,对应的景深就越小,越容易产生虚化效果。

单个凸透镜头的成像系统可以摄影当中基本的概念。然而实际的单反相机的镜头是由多个透镜组成的。原因之一是可以实现变焦,同时多个透镜可以修正一个透镜引入的像差(这又是另外一个复杂的光学话题了),达到更好的成像效果。在真实感绘制中引入了多这种多透镜的相机模拟,这样我们需要为每个透镜建模,为了简单我们假设每个透镜都是球面镜,这样我们只需要一个半径参数就能描述透镜的几何特征。实际的相机镜头中为了获得更好的成像效果,都会加入非球面透镜,这已经是比较现代的技术了。因为在理论上,球面透镜不能把光汇聚在一点,产生了球差。在真实感绘制中,我们只模拟球面镜。 一个透镜由四个参数决定: 曲率半径 厚度 折射系数 直径 厚度是到下一个镜片的距离。

模拟景深

模拟景深需要两个额外的参数,即光圈(Aperture)焦距(focus distance),还有一个对焦距离,对焦距离就是能够清晰的成像的物体的距离。 。景深所产生的模糊效果粗浅的解释为焦平面前后的物体在像平面上不能聚为一个点而是一个光斑。 这里需要在光圈范围内进行圆盘均匀采样,然后以这个采样点到对焦距离的点(这个点是原始像素与透镜中心的连线与对焦平面的交点)的方向代替这个采样点的方向。 进行多次采样最后取平均。

所以,最后景深的效果和光圈,也就是采样范围有关。但是从之前的公式看还应该与焦距有关。这个焦距已经暗含在了P矩阵的fov里了。因为焦距越大,镜头里像平面的距离越远,这也会对景深产生影响。 具体体现在相对采样面积减小。

光学系统

如果不用任何光学系统,直接成像最终结果是模糊一片。因为物体的任意一点发出的光都对传感器上的任意一点有贡献。

小孔成像

小孔成像是最简单的一个光学系统。

成像特点:锐利,每个像素只被物体的唯一一点影响。(不考虑衍射的理想情况下)

透镜系统

一个理想的成像系统,应该一对一的映射,并且具有高信噪比。这就是透镜组的作用

一个光学系统的组成

这个表和图说明了光学系统的描述方式。表中的每一行代表一个镜面的属性。(一个镜子有两个镜面)。

  • 第一列是半径。其中正值为凸面镜,负值为凹面镜。凹凸是相对于镜头从外往里的。
  • 第二列厚度代表当前表面到下一个表面的距离。中间的孔径光阑(光圈)是一个实实在在的孔,但也归为一个镜面。
  • 第三列是折射系数。这里有个约定,当折射系数为0时,这个界面是出射界面。
  • 下一列这个参数代表了镜面的材质,与波长相关。
  • 最后一列是这个镜面的有效直径。

需要说明的是,镜片的组成有的概念。当两片镜子合在一起的时候可以作为一组。比如下图:

这个镜头1896年蔡司设计的Zeiss Planar镜头。组成为6片/4组。l2,l3这两个镜子为一组,同时也被称作高斯结构 这里的双高斯结构为经典的镜头结构,适合设计35mm-90mm焦段的镜头。

理想薄透镜模型

根据我们想要的成像效果,在物理(几何)上,我们可以抽象出一个理想的薄透镜模型,这个模型有两个假设:

  1. 穿过透镜中心的光线方向不变。

  1. 平行的光束通过透镜时汇聚为一点,并且所有的平行光束组所汇聚成的一点在一个垂直于光轴的平面上。

其中这个平面到透镜的距离叫做焦距(Focal Length)

根据这两个假设,可以推出一个结论:

  • 薄透镜一边的一点,发出来的光线,经过透镜的汇聚,一定在另一边汇聚成一点。(可以证明一下,用相似三角形, 目前我只知道反正法)

  • 薄透镜一边垂直于光轴的一个平面(物平面)发出的所有光线,经过透镜汇聚,一定在薄透镜另一边汇聚成一个平面(像平面)。

其中这个像平面到透镜的距离叫做对焦距离(Focal Distance)

焦距和对焦距离一定要分清楚,不要弄混。

当然第二条时第一条的一个非常自然的结论。

从第一条可以看出,这个理想的薄透镜实现了我们一开始想要的目标,能够形成一对一的光源映射,使得成像锐利,信噪比高。

高斯公式

通过简单的相似三角形,可以得到高斯公式(薄透镜下适用)

$$ \frac{1}{z^{\prime}} - \frac{1}{z} = \frac{1}{f} $$

(实际上我们能够如此简单地得到薄透镜的高斯公式,是因为我们预先给定了薄透镜的性质,因此这些结论都是显然的。其实我们之间给出的薄透镜的两个假设也都是结论。)

代码实现

坐标系约定

我们约定,相机空间和透镜空间 $z$ 轴方向相反,相机朝向 $+z$ 方向, 透镜空间朝向 $-z$ 方向。 即从镜头外往传感器的方向是透镜空间的正方向。也就是从底片像外看去,是透镜空间的 $-z$ 方向。从场景向透镜看去,是透镜空间的 $+z$ 方向。 这样约定方便透镜组的描述。如前一张图。

核心函数

真实感相机的实现两个核心的函数是

  • 给定场景外入射到镜头中的一条射线,判断是否有这条入射射线对应的从透镜组最后一个镜片出射到底片方向的射线。如果有,则返回。
TraceRayFromFilm(rayFromFilm) -> exist, rayToScene
  • 给定从底片到透镜组最后一个镜片方向的一条射线,判断是否有这条射线对应的从透镜组第一个(镜头)镜片出射到场景中的射线。如果有,则返回。
TraceRayFromScene(rayFromScene) -> exist, rayToFilm

这两个函数的差别仅仅是追踪的方向相反。用这两个的函数的目的在于计算透镜组的厚度然后通过厚透镜的高斯公式用于对焦。

中间的大体过程就是,遍历透镜组,对每一个镜面应用球面求交,反射定理,判断是否是有效折射,如果不是,直接结束。重复以上步骤直到遍历完所有的镜面。得到最后结果。

对焦

给定一个成像平面位于$z_f^{’}$(一般位于焦点内),有其所对应的一个能够对焦在这个成像平面上的物体的距离$z_f$。对焦的过程就是调节$z_f^{’}$的过程,当把成像平面调整到焦点的位置上时,就对焦在了无限远处,实际上就是能看清很远的地方。在$z_f$的前后范围内,有一个能够成人眼能够分辨的清晰度的像的范围。这个范围就是景深(Depth of Field)在这个范围的前后的边界的位置上所成的像不能在成像平面上会聚成一点,而是一个有一定直径的光斑。这个圆圈就是弥散圈。只需要简单的几何推导,弥散圈为$$\begin{align}d_c=conf(z)=\vert \frac{d_{1}f(z-z_f)}{z(f+z_f)} \vert,其中d_{1}为透镜的直径 (f/n)\end{align}$$。如果我们把这个弥散圈当作一个衡量成像分辨率的指标,即当这个光斑大到一定程度,使得相机的传感器和人眼都不能识别出清晰的图像。那么给定一个弥散圈,就能确定在某位置物体的景深范围。这样的话,我们会有两个相同的解释方式:其他条件相同的情况下,相机的弥散圈越大(无论以怎样的方式实现,比如更高分辨率的成像传感器,或者是其他什么黑科技)景深越大,则成像清晰的范围就越大,越不容易产生模糊效果。与此等价的说法是:其他条件相同的情况下,景深越小,弥散圈越小。 公式$(1)$ 的曲线形状类似于$\vert log(x) \vert$,$conf(z) = 0$的零点是 $z = z_f$。给定一个相机的$d_c$,在这个曲线上画一条横线,对应的两个$z_1$,$z_2$就是对焦在$z_f$处物体的景深范围,可见前景深与后景深的变化不是对称的。$d_1$对于这条曲线的影响就是在其他条件相同的情况下如果$d_1$越大,那么这个曲线越收紧,对应的景深就越小,越容易产生虚化效果。

对于厚透镜来说,有高斯公式

$$ \frac{1}{z^{\prime} - p_{z}^{\prime}} - \frac{1}{z - p_{z}} = \frac{1}{f} $$

$p_{z}$ 和 $p_{z}^{\prime}$ 的意义如下图, $p_{z}$ 和 $p_{z}^{\prime}$之间的距离为透镜组的等效厚度,可以看到,薄透镜就是$p_{z} = p_{z}^{\prime}$的情况。

所以,计算透镜厚度的方式就是从场景平行摄入一条光纤,与使用TraceRayFromScene之后返回的那条出射光纤的反向延长线的焦点的$z$位置垂直于光轴作为一个基平面(Cardinal Plane)$p_{z}$,以同样的方式用TraceRayFromFilm找到另一个基准平面。这两个基准平面之间的距离就是厚度。

采样预处理

由于直接暴力采样收敛比较慢,所以在第一个透镜上确定采样点的时候需要有一个预设范围,这个预设范围就是出瞳(exit pupil),这个范围是能最终能射出透镜方向上的点的集合。

因为像场是中心对称的,我们在水平的径向上做预计算就可以。可以去底片对角线的长度为径向的最大长度,然后 对这个镜像分成很多小分,每个小份上均匀采样,作为起点,在镜头上随机采样作为终点形成一条光纤,调用TraceRayFromFilm测试这条光纤是不是能穿过相机,然后扩大这个穿过的包围盒的范围。采样测试足够多的数量,最后这个包围盒作为这个区间段的一个出瞳范围存储起来,作为光线追踪时的预计算信息。

在实际做光线追踪采样时,我们可以根据采样点在底片上的位置先通过旋转,算出落在径向区间段的索引,然后根据对应的包围盒范围,在这个范围内采样,这个范围内的光线都是可以保证有对应的出射光线的。

具体流程

1. 输入镜头数据
2. 对焦:计算透镜厚度,给定对焦距离,通过高斯公式算出透镜离底片的距离,然后改变透镜组的位置。
3. 预计算采样范围
4. tracing

Cameray