RTR4 拾遗(一)-- 图形学的B面

        RTR(Real Time Rendering)对于游戏图形开发来说是本宝书,最近对新版的RTR4进行重读,知识需要经过自己的消化重表述才能成为自己的,所以在这里对里面一些重要内容以我自己的理解重新整理,这篇是关于第8章的Light and Color。它对应于RTR3的第7章advanced shading,后面会陆续更新。写本连载的文,希望自己能够坚持下去

 

图形学的Second Half

 

在我看来,大多图形学教程是一个经常抛开前因后果去讲其中某个关键部分的教程,就好比opengl上来就讲管线,着色器,那么着色器着的每个pixel的颜色单位是什么,大部分渲染的教程会直接教我们光照模型,那么光照模型里的光线是被看做有多细?一个直线光会发出多少条光束?射到一个pixel上的有多少?为什么rt上的某个pixel是会对应到物体表面的某个位置?物体表面任何一点都会射入到眼球里的每一个点,那么为什么光照模型里从某个表面点进入眼球的是一条光线?光照模型里射入眼球的光线是哪一条?…这些就是图形学知识的“B面”。这里就是这样的一些知识。

 渲染要解决什么问题?渲染要表现在某个给定时间内光源发出的所有光线跟场景所有物体表面反应后进入到眼球视网膜上的光能给人的感受。问题需要被解决,就需要被数学模型化,这里首先要去度量这种人眼的感受,这种感受本质上跟光线的能量有光。

 

  1. 光,能量,度量

 

Radiant,Irradiance,Intensity,Radiance

 

光的能量Radiant

首先定义光线的能量,光线是一束各种波长的光波的组合,光波携带能量,我们把光线在我们感知的一瞬间(1帧)内发射出的能量记为这个光波的辐射量Radiant(或φ),光波的能量同波长相关,光波长越短,Radiant越大。

 

感受器度量Irradiance

但是Radiant不能直接度量感受,想象一个灯泡在极短时间内向四周发射光线,发出的Radiant是恒定的,但不能说谁的眼球视网膜越大,谁接受的E多谁感知的光越强。光感的度量要靠单位面积接受的Radiant多少。所以我们不用能量总量Radiant来度量,而是用另外一个概念Irradiance来度量,它叫做辐照度,对于点光来说,Irradiance = Radiant/4πr2, 因为球面的面积是4πr2。

 

发射器度量Intensity

Irradiance用于度量接收器的反应,而对于光能发射器来讲,Irradiance不是好的度量方式,因为光子从光源发射出来后,随着距离越远分布越稀疏,离发射器不同距离上的irradiance是不一样的,用Radiant可以度量,但是更常用的度量方式是以发射器为球心,测量单位球面度上的光子能量总量,这个量叫做Intensity(我们常翻译强度),Intensity = Radiant/4π。理解这个要理解球面度,角度是二维上圆弧对应的角度,而球面度就是三维上一个弧面对应的球心的角度,二维上整个圆的角度是2π,整个圆弧长是2πr,而三维上的整个球的球面度是4π,整个球面积是4πr2.在游戏引擎中,一般都会用Intensity去度量光源的强度。这里Intensity同irradiance也是可以互相转化的,Intensity = irradiance * r2,可以理解为同样强度的光源下,距离和接收到的辐射成反比,或者要想接受同样强度的辐射,距离增加强度也得增加。还有在r=1的时候,即光源的单位球面上,Intensity = irradiance = Radiant/4π。

下图直观说明光能,辐射度,强度三者的含义。

 

成像的感受器度量 单光束 Radiance

前面提到的感受器对光能量的度量Irradiance是在一个单光源球面上的度量,在真正的视网膜或摄像机的成像中,只使用Irradiance是不能成像的,因为理论上一个视网膜细胞会接受来自场景每个点的反射光能,这些个Irradiance互相叠加平均,就会产生模糊的像,人眼是个小孔成像系统,小孔成像的机制是筛选一小束光束使其通过小孔,辐射到感受器上,这个可以用于成像的感受器的度量叫做Radiance(或翻译为光束),因为Radiance是总光能Radiant在极小球面角和极小球面积上的值,所以Radiance是对球面角和球面积两者的微分,即Radiance = d Radiant / d w * d area * cosθ,这里w是球面角,area是光束与表面的接触面积,θ是光束和表面的夹角,之所以乘cosθ,是因为我们要度量radiant对光束所在截面的微分,如下图

 

容易得到Radiance = d Irradiance / d w,以及Radiance = d Intensity/ d area * cosθ。用光的能量Radiant来表征光源的辐射总量,最终用Radiance来表征能量中对成像感受器的光能感受。这几个量的单位是不一样的,辐射量Radiant是watt,辐照度Irradiance是watt/m2,强度是watt/sr(sr是球面角度),光束强度radiance是watt/m2.sr. 注意这里的watt本身就已经是一个能量在时间内的比率,它描述一个辐射通量,可理解为辐射量的速率,单位等同于J/t (焦耳/时间),这样我们就可以理解光速强度radiance是一堆光子能量在一帧时间内在极小球面角(小块成像)在极小面积(光感单位)上的微分,

Radiance是渲染里面非常重要的一个度量,因为它其实是在用微分的方式度量一个被细化的光线携带的能量。一般用L代表Radiance,L是一个有5个自由量的函数,即L(p,d),其中p是光线的起点,d是方向。有时还有种变体,即Li(p,d),即对于一个被光线照射的点,反向描述它,这里的p就变成了光线碰到的这个位置,而d通常表达成光线的反方向。此外L有个重要特性,即它不随位置变化,在真空下,L的强度是在传播的路径点不变的,这里有个易混淆的概念,离光源越近接受光能更强,但是这里描述的是Radiance,radiance是有面积的,而L是个微分概念,离光源越近只能说物体接受了更多的L,但是每个L的强度没有变。

有了L,我们就可以这样描述我们的渲染要解决的数学问题,我们将渲染屏幕或者眼睛当做一个小孔成像系统,从成像系统的底板的每个微小感光单元(RT的pixel),追踪穿过它的在场景的每条Li,对这些Li做积分,即是像素获得的能量,也是pixel shader的最终输出,因为Li单位是watt/w.sr,而pixel shader的输出是watt,所以这个积分要在影响成像pixel的每个球面角和每个面积上积分。这个原理也是ray-tracing的本质。

 

 

 

能量守恒

光线的能量在空间中是不是守恒的,其实不是,光波的复合其实并不会简单的线性增加他们的能量,可能会导致完全抵消为0,也可能是平方和,但是对于完全的随机的一些光波进行复合,统计上讲会接近与线性叠加,因此光线的能量守恒在渲染这里其实是一个基于统计的假设。

  1. 人的感知

感知强度

前面章节讨论的是光的能量,但是光的能量和人眼对光能的感知又是两回事,首先光线的能量对波长增长而降低,但是人对光的感知不同,是另一条曲线。能量的度量叫做Radiometry辐射度,而人眼的感知的度量叫做Photometry光度。光度和辐射度又都可以用luminous做单位。

 

所以从1.1讨论的辐射度(或者Radiance)转化到光度,还缺一个转换系数,这个就是上面的这个曲线,他叫做CIE photometric curve,国际照明组织的光度曲线。即对不同的波长的光波的辐射度再按照曲线成一个效率比。所以光能强归强,但人类感光最强的波段在550nm左右,它的转换比高。

感知色度

人眼如果度量感知到的光强,它靠3种不同类型的感受器,也就是讨论人的感知必须在这三个感受器的维度上讨论,只讨论一种强度是不正确的,当讨论了3种感受器的光度感知,就进化成了讨论颜色,即色度。就算是一个单波长的光,它都会同时触发3中感受器的不同能量感知。这里我们终于可以给颜色下个定义,颜色即人眼的3种感受器对一束由各种波长的光(或光谱)的综合反映。

RTR上还讲了人们是如何确定是RGB这三个元素成为这三种感受器类型的,这个我也想总结一下,因为理解颜色是个很重要的事情。

人们想找到这ABC这三种感受器并量化其实就是想找到三种状态下的颜色(或三种状态下的波长组合或光谱,注意,这并不要求只是由一种波长的光波导致的,大部分的颜色状态要求多种波长的光组合),这三种状态分别要求其中一种感受最强,其他两种感受尽可能低。因为我们不可能控制视网膜的信号传递,所以我们没有直接的方法描述这三种状态的颜色。只能人肉尝试。如果ABC是这三种状态,那么必然ABC三种的任意比例组合可以组合出所有可以感知的颜色状态。(反证法可以证明,因为如果不能就说明需要其他颜色调和,那么人眼就多出一种感受器)。所以人们把任意组合的三种颜色投到白屏幕上,然后取任意颜色的投到白屏幕旁边,然后通过调节前三种颜色比例,使其能拟合出旁边的任意颜色。最终人们找到了这三种颜色状态,称为Red Green Blue,就是三原色,其中任何一个颜色都不能通过单一波长的光表现,都需要光谱的组合。但是我们可以找到那个波长分别对R/G/B的反馈最强。波长分别在444 526 和645附近,能最大化引起G感受器的单波长光同时也能激起较强的R。这里面的纵轴是测试中用的权重。

光度还是色度?

到这里我们需要思考我们图形学的渲染结果到底是为了表达photometry光度还是色度colorimetry?

首先无论是光度还是色度,都需要原始的射向你的那个光束Radiance的光谱组成(即它由那些波长的光复合),光度就用Radiance同Photometry的curve相乘取和,色度就用上面的color curve相乘取和得到RGB表征,从人眼的物理特性来讲是色度,所以这里有个有意思的逻辑,就是光线的能量强和你感知到强不强是两回事(能量超强的X光你根本看不到),而你感知到强不强和反馈再RGB这个向量上的3个数值又是两回事(对你来说感知能量超强的526nm单波长光即绿光在rgb(0,1,0)的表示上不如感知能量弱一些的645nm红光在rgb(3,0,0)数值大)。因为辐射能,光度,色度本身就在三个维度上,我们用色度表示彩色照片,而用光度表示照片。这里就不难理解为什么RGB转换gray图时候的那个看上去拍脑壳的公式0.299*r+0.587*g+0.114*b了吧。绿色光确实有更高的光度能量,最不应该被人眼忽略,所以在很多图像格式的压缩算法中,都会格外优待一些g通道,让你损失稍小于r和b,所以在dxtnm格式的法线的压缩中,法线的两个通道会被放入g和a通道,因为rgb和a各占一半位宽,g又享受优待,这可不是随随便便放置的。

一句话总结,光谱spectrum代表了光的物理属性的能力,光度Photometry是感知的能量,而色度Colorimetry是人眼三种感受器下感受到的色彩。在现有的光照模型中,我们基本用色度(RGB)去进行一切光照计算,表征材质,表征光源,可事实上这是不够准确的,实际上基于物理的方式我们应该基于光谱,Spectrum Based Rendering才是最准确的屋里渲染,我们用光谱量化光,用光谱量化材质,在得到人眼接收到的光谱后,最后从光谱转向色度,现在的实时渲染领域还没有这方面的大规模尝试,然而在很多离线的领域,如工业上的汽车涂漆等都应用了光谱渲染,然而在游戏领域我们还是基于人感知空间的色度为度量做光照计算。

RGB和XYZ

我们看到上图基于RGB的色度表示有缺陷,RG在一个范围内会进入负值,这意味着我们的一些颜色是不能够用RGB这三种正交颜色表示的,所以国际照明组织(CIE)提出了一种想象中的空间XYZ,如下图。

并基于xyz的色度表示出现了一批色彩空间标准,如CIE1978 CIE等等。

 

Scene Radiance 到 Display Radiance

在前面讨论的基于光照计算得到的RT上的rgb其实是代表了场景被我们感知的颜色,叫做Scene Radiance,但是事实上如果把它直接输出给屏幕,它同人眼真正感受到的Radiance还有差别,这里面会存在几个问题,场景的颜色就是人眼真正感知的颜色么?

人眼具有自适应性,在光照暗的环境下会提高物体的亮度,并降低对比度;

一个物体放在不同颜色的环境中,也会有不同的颜色;

此外显示器能够显示的颜色范围是有限的,我们需要把场景原始的颜色压缩到一个显示器范围相对较窄的颜色范围内。

因为这些区别,我们会把人眼真正感受到的Radiance叫做Display Radiance,在Scene Radiance和Disaplay Radiance中间还需要一个转换,这个过程就叫做Tone Mapping,Tone Mapping 要解决上面提到的这些问题,目的就是给最终呈现在屏幕的颜色最贴近人眼感受到的这个场景的颜色。就好比让照相机拍摄的照片和人眼看到的景象尽可能的一致。至于Tone Mapping的具体作法,后面章节会继续补上。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值