之前在查询Physically Based Rendering(PBR)资料的时候偶尔翻到了几篇关于光和颜色的博客,才知道原来在我写的shader里一直在用的RGB值的由来,也去阅读了Real Time Rendering(4th Edition)第八章的相关内容,所以这篇算是一个读书笔记吧。
-
Radiometry(光能测量学)
顾名思义,这门学问是测量电磁辐射的。在这里我并不是要来解释这门学问或者将原文这段翻译一下,而是要记录下这段的两个要点。
第一,人眼的可见光波长范围在[400nm,700nm]
第二,光度学所测量的四个重要方面:radiant flux,irradiance,radiant intensity以及radiance
首先来看第一个辐射功率(radiant flux)。我们知道,光都是携带能量的。我们把一束光在我们感知到的一瞬间(1帧)所发出的能量记为radiant flux。一束光中包含了多个光波,每个光波波长不一,波长越长则radiant flux越小。
irradiance,中文为辐照度,这个量是关于感受器(比如说视网膜)的。由于radiant flux无法直接度量感受,想象下一个灯泡在极短的时间内向四周发射光线,不能说谁的视网膜面积大所以感受到的光强吧?所以我们用irradiance来度量,指单位面积接受到多少radiant flux。对于点光源来说,,球的面积是。
第三个radiant intensity,与irradiance用来衡量光能接收器相对的,是衡量光能发出器的一个东西。由于光子从发光源发射之后,随着距离的增加光子分布的越稀疏,在不同距离的irradiance也是不同的,所以拿irradiance来度量并不是一个好的选择。radiant flux可以用来作为衡量的一个标准,但更常用的方式是以发射源作为球心,测量单位球面度上的光子的总能量,这个量用intensity(强度)来表述,。为什么要除以呢?首先要明白什么是球面度,角度是二维圆弧上对应的角度,那么球面度就是三维球上一个弧面对应的球心角度,整个圆的角度为,整个圆弧长为,那么整个球面度为,球面积为。在游戏引擎中,通常用intensity来衡量光源的强度,而且intensity和irradiance可以相互转化,,如果即在单位球上,他们俩相等。
radiance,辐射率,是用于成像的接收器的度量。上文提到的irradiance在视网膜或者摄像机成像中,是不能成像的。理论上视网膜的一个细胞会接受来自场景每个点的光能反射,这些irradiance互相相加平均才产生模糊的像。人眼是个小孔成像系统,其机制是选出一小束光使其通过小孔,射到接收器上。之后就可以用radiance来度量,其表述的是总的光能radiant flux在极小球面度和极小球面积上的值,那么
w是球面角,area是光线与表面接触的球面积,是要算与光线垂直截面的面积。
我们一般用L来代表radiance,它由5个变量所决定(或者6个,包括波长),写成函数即。p为光线的起点,d是方向。在渲染方程里,经常出现或者,代表从点x处发出或射入点x处的光线,d为光线的方向,经常是从x处向外指,是为了计算比如说点积的方便。有了L,我们就可以描述渲染要解决的数学问题了。我们将屏幕当做一个小孔成像系统,追踪在场景中穿过其的每条光线并对其积分,即为像素获得的能量,也就是pixel shader(fragment shader)的最终输出,由于的单位是,所以这个积分要在每个球面角和每个球面积上进行。
-
Photometry(光度学)
以上是光的能量的测量问题,但我们人眼感受到的光和以上所述又有不同,国际照明组织(CIE)给出了一条曲线,叫photometric curve,乘上这条曲线,可以将Radiometry转成Photometry。
那么上面所说的四个量也就能转成人眼所能感受的量了。
我们通常用Luminance表达亮度,HDR电视屏幕的峰值亮度为500-100尼特(nit),干净明亮的天空为8000尼特,一只60w的电灯泡为120000尼特,太阳为600000尼特。
-
Colorimetry(色度学)
人眼中有三种感受光的视杆细胞,每种细胞会对不同波长的光产生不同的反应,但传到大脑中的信号只有三种,而可见光有七种颜色即七种波长,那么到底传到大脑中的是哪三种特定波长即颜色的信号呢?国际照明组织(CIE)做了实验,用人肉的方式得出了结论,即我们现在所熟知的RGB三原色。
这三种颜色的叠加造成了我们能看到超过千万种不同的颜色。然而,这种人肉实验得出的曲线在某些范围内有负值,显然,在这种状态下我们不能用rgb来表达某些颜色了。所以,rgb不能表达所有的颜色,只是对颜色的降维表达,真正要表达颜色还是需要用光谱。
那么,好不容易找到了三原色不可能因为这就抛弃不用吧?事实上,CIE通过一系列的操作,提出了另一种rgb的曲线
虽然在现实中不存在这样的曲线图,但却能表达人类所能看见的所有颜色了。将rgb作为xyz的空间坐标,即能得到颜色空间的图
然后将这三维空间投影到x+y+z=1的二维平面(因为z可以通过1-x-y获得),则得到了一个马蹄形的色域图
我们人眼所能见的颜色都在这张图里,那个在白色三角形内的颜色代表sRGB这种颜色标准所能表达的全部颜色,黑点是白点,是纯白色的所在。我们现在很多设备的显示都是遵循sRGB这种颜色标准的,所以,当你盯着屏幕的时候,其实你能看到的颜色比现实中少很多。当然有许多其他的颜色标准,可以把这个三角形区域扩大很多,但依然有许多颜色不能被物理设备所展现,毕竟rgb是低维的表达,而不是光谱。
那么,radiometry是在表述光的能量,photometry在表述人眼所能辨别的光能,colorimetry在表述人眼所见的颜色,他们之间有什么关系呢?其实,光能强不强和人眼所见的光能强不强是两回事,而人眼所见的光强不强和反馈在rgb这三个量上的数值又是两回事,落实到游戏领域,我们渲染的最终结果还是基于人的感知空间的色度作为度量来进行光照计算。
-
Scene to Screen(场景到屏幕)
前面经过光照计算所得的颜色代表了我们所感知的场景的颜色,然而把它输出给屏幕,在屏幕上显示的颜色是否是我们感知的颜色呢?答案是否定的。首先,人眼有自适性,场景的亮和暗会对物体的颜色产生影响,并且,物体在不同颜色的环境中,人眼也会看到不同的颜色。如图,你感受到的颜色一样么?
其次,所有的物理设备显示的颜色范围是有限的,场景的颜色范围远远大于物理设备所能显示的颜色数量,所以我们需要一些技术,比如HDR,把物理设备显示的颜色范围提高一些,或者,把较宽的颜色范围对应到一个较窄的范围内。
基于这些不同,toon mapping应运而生。这种技术把真实场景中的颜色转成人眼感知的颜色,以达到在屏幕上显示的颜色在被人看到后能够让人还原当时的场景,而不会让人感觉场景很假。
PS. 这是今年的最后一篇博客了,看了下电脑上的便签,还有8个主题想要写成博客(也许会增加),希望能在明年第一季度写完!
参考
RTR4 拾遗(一)-- 图形学的B面
颜色 /About Color --图形学的B面(二)
PBR--RTR4笔记--第八章 光与颜色