PBRT学习笔记: 颜色在离线渲染中的表示方法

来源:互联网 发布:乐巢优品 知乎 编辑:程序博客网 时间:2024/05/01 09:15

本文简单总结下PBRT中的第五章的前半部分,是关于光谱的一些内容。这部分的内容相对而言比较独立,不受其他模块的制约。
计算机是一个有限的资源,我们的显示器同样是只能表示有限的信息量。举个简单的例子,对于一个普通的LCD 22寸的显示器而言,假设分辨率是1650*1080,而每个pixel只能表现出2的24次幂种不同的颜色,那么实际上一个屏幕最多能表示的信息也就是1650*1080*(2^24)。这里我们抛开分辨率不谈,只考虑一个pixel所能表示的信息量,其实只有2^24种不同颜色的表现能力。而我们现实生活中的颜色范围是非常广泛的,要远远大于这个数值,所以我们需要一种映射方式把现实生活中的光谱信息抽象到显示器所能表示的形式。从某种角度理解,我们可以理解为这是一种把一个接近无限的集合映射到一个有限集合的过程。显然这肯定不是一一映射了,前者中的任何一个数据只能对应后者中的相对应的唯一的一个数据,而反过来则未必。
首先,我们先简单解释下计算机中对于颜色的表示方法。这里就介绍两种比较常用的好了。第一种是我们最熟悉的RGB表示方法,即红绿蓝表示法。任何一个pixel所能表示的颜色由红绿蓝三原色组成,每个单独的通道一般用一个byte表示。另一种表示方法相对用的较少,每个颜色XYZ三种分量来控制。相对来说,这个比较难理解一些。不过就本质来讲,两者的差别不大,只是两种表示形式而已,是可以互相转换的。
在简单了解了计算机内部的颜色表示后,我们来了解下生活中的颜色的表示方法吧。中学的时候,大家都学过光具有波粒二项性。这里面我们只谈光波的性质吧,每个单独的光线都是有波长的,不同的波长在人眼中的表现形式是不一样的。波长在400左右的光在我们眼中表现为蓝光,波长为550的光表现为绿光,而波长在650左右的光波则表现为红光。在这个范围之外的,我们认为是红外线和紫外线,对于渲染而言,是没啥意义的,所以基本不用考虑。而我们在生活中看到的光线基本上都是很多光束混合到一起的,所以其波长并不一致,从而导致了我们可以看到多种多样的不同的颜色。所以我们可以用光谱来表示我们看到的光的信息。我对光谱的理解很浅,光谱大概是把光束按照光的波长分开,然后把每个波长的光强度记录下来,从而形成一条曲线,这条曲线可以被用来表示光的信息。
image 上图中分别为荧光灯和柠檬的光谱图(这样说可能不太标准)。对于前者而言,我们注意到其能量是很大的,但是曲线相对较陡,所以我们看到的荧光灯会很亮,而且颜色鲜明。而后者的光谱中的曲线就很缓,而且能量也小很多。
那么对于离线渲染,如果想支持光谱的表示的话,必须把上面的光谱图离散化。其实PBRT的做法并不复杂,它把光按照波长从400到700平均分成k等分,在每个k等分点取光谱的能量值。当k的值足够大的时候,这条曲线基本可以被表示出来。而对于光谱的数据源,一般是来源于文件的。这些文件中的数据都是经过前人实验总结出来的。
现在我们了解了计算机中的颜色表示方法和光谱的离散表示方法,那么两者之间的联系是什么样呢?即使在进行离线渲染过程中,我们都用光谱来表示颜色,最后我们依然要把颜色转换为RGB的形式,从而确保显示器可以正确显示,因为毕竟显示器是不知道如何解析光谱信息的。
这里我们先考虑XYZ与光谱信息之间的关系吧,我们用X、Y、Z来表示三个分量。人眼的主要特性决定了其对于颜色的感知可以由三个浮点数字有效的表示。首先需要定义/overline{x}(/lambda) , /overline{y}(/lambda)/overline{z}(/lambda) 。他们被称为color-matching functions。其实是三个光谱分布,大致的形状如下:
File:CIE 1931 XYZ Color Matching Functions.svg 注意这里的三条曲线绝对不代表是RGB的三条曲线,只不过是有些近似而已。那么对于任意的一个光谱分布I(/lambda)/, ,我们都可以把它转换为X、Y、Z的表示法。
image 这样就可以把光谱信息转换为XYZ的表示法了。(注,上述公式是在wiki里面查到的,与pbrt第二版的内容稍有不符。不敢轻易下定论是哪一个错误)
本质上来讲,上述过程相当于一个降维的过程。可以这样考虑,对于光谱分布的任何一个曲线,由于计算机内部是离散表示的,所以实际是一个k维数组而已。那么这个k维数组的每个实例我们可以理解为是在k维空间中的一个点。而/overline{x}(/lambda) , /overline{y}(/lambda)/overline{z}(/lambda) 可以认为是三个k维轴,用来把k维空间中的点映射到三维空间,即XYZ。这个过程有一点点像PCA的过程,只不过主成分不是根据点集的variation决定的,而是根据人眼的对于颜色的感知特性决定的。
貌似对于上述表示法,已经足够高效而简洁的表示一个颜色了。但是事实上,很多应用中,这种表示法并不合适。考虑两个颜色实例,假设光谱为a0,a1,分别转换为(x0,y0,z0)和(x1,y1,z1)。那么a0与a1的乘积结果a2同样转换成了(x2,y2,z2),可是x2!=x0*x1,y2!=y0*y1,z2!=z0*z1。这对于很多操作是非常不方便的。所以人们又引入了RGB颜色空间,从而解决上述问题。
光谱信息映射到RGB颜色空间与之前的XYZ映射过程是没有本质区别的,只是三条曲线不同而已。这里就不列出三条曲线的形状了。而有了上述的两种映射关系,XYZ与RGB之间的映射关系就变味简单的矩阵变换了。这里就不一一列出了,想了解的朋友自己查一下相关资料吧。