Light and Color 光与颜色
这一章节除了辐射度量学,toneMapping、颜色分级我感觉会用到,其他更多是科普内容,比如为什么用RGB就能代替可见光
光量
任何基于物理的渲染方法,其第一步都是以一种精确的方式,来对光进行量化(quantify)。
辐射度量学
在不同的课程中接触了这个东西几次,每次都有不一样的理解😝,下图展示了光的波长范围与人可见光的范围

各个辐射量(radiometric quantity)的存在是为了对电磁辐射的各个方面进行测量和度量,例如:总能量、功率(随时间变化的能量)以及相对于面积、方向或者二者的功率密度等

- 在辐射度量学中,最基本的单位是辐射通量(radiant flux)Φ,辐射通量是指辐射能量随时间的流动变化,又叫做功率(power),其单位为瓦特(watts,W)。==理解为做功的功率即可==
- 辐照度(irradiance)是辐射通量相对于面积的密度,即$ d \Phi / d A$。irradiance是相对于一个面积来进行定义的,这个面积可能是空间中的一个假想区域,但是在渲染中一般都是物体的表面。irradiance的单位是瓦特每平方米($W/m^2$)。==理解为功率在单位面积上的大小==,
- 辐射强度(radiant intensity),即辐射通量相对于方向的密度,更准确地说,是相对于立体角的密度$(d \Phi / d \omega)$。它的单位是瓦特每立体弧度$(W/sr)$
- 最后,辐射度(radiance)L是对单条光线中电磁辐射的度量。更精确地说,它是辐射通量相对于面积和立体角的密度$(d^{2} \Phi / d A d \omega)$。这里的面积位于垂直于光线的平面上,如果想要在其他方向上对表面施加辐射,则必须使用余弦因子进行校正。==进一步把irradiance划分到单位立体角==
立体角可以理解为立体空间的一个立体方向截取一个单位球体的面片面积

radiance是传感器(例如眼睛或者相机)所直接测量的对象,因此它对渲染而言至关重要。计算着色方程的目的就是沿着给定的光线,计算从着色点到相机的radiance;沿着这条光线计算出来的结果L。radiance的公制单位是瓦特每平方米每立体弧度$(W/m^2sr)$
环境中的radiance可以被认为是五个变量(或者六个变量,将波长考虑在内)的函数,它被称为辐射分布(radiance distribution);其中有三个变量指定了位置,另外两个变量指定了方向,这个分布函数描述了在空间中任何地方传播的任何光线。根据上面的描述,我们可以这样来理解渲染过程:将眼睛和屏幕定义为一个点和一组方向(例如从眼睛出发,穿过每个像素的光线),然后使用这个函数,在这组方向上对眼睛所在的位置进行评估。
在着色方程中,radiance通常会以$L_{o}(\mathbf{x}, \mathbf{d})$或者
$$L_{i}(\mathbf{x}, \mathbf{d})$$的形式出现,它代表了从点x发出,或者进入点x的radiance具体是多少。方向向量$\mathbf{d}$表示了光线的方向。radiance的一个重要特性是,在忽略了雾等大气效应影响的前提下,radiance不会受到传播距离的影响。换句话说,无论一个表面与相机的距离有多远,它们都将具有相同的radiance。当距离相机越远时,这个表面所覆盖的像素就越少,但是来自表面上每个像素的radiance是恒定的。
多数光波中都包含了许多不同波长的单色光,这通常可以被可视化为一个光谱功率分布(spectral power distribution,SPD),它是一个展示了光线能量如何在不同波长之间分布的图片。(三种不同光波的光谱功率分布(SPD)。第一行是一个绿色激光的SPD,它有一个非常狭窄的光谱分布,其波形类似于图9.1中的简单正弦波。第二行的SPD是由相同的绿色激光,外加两个额外的激光所组成的,分别是红色激光和蓝色激光。将这些激光的波长和相对强度转换到RGB激光投影显示器上,会显示出中性白色。第三行的SPD是标准的D65光源,这是一个典型的中性白色参考值,旨在代表室外的自然光照,类似第三行的SPD,其能量连续地分布在可见光谱上,是典型的自然光。)
==在下图中人眼对于第二行和第三行的感知是一样的,这就是为什么只用三个数字就可以精确地表示任何颜色的原因==

光度学
辐射度量学仅仅对物理量进行了研究,它完全没有考虑人眼的感知。与此相关的一个领域被称为光度学(photometry),它与辐射度量学类似,不同之处在于,它会根据人眼的敏感度,对辐射度量学中的一切事物进行加权处理。通过乘以CIE光度曲线(CIE photometric curve),辐射度量学中的计算结果可以被转换为相应的光度单位。CIE光度曲线是一条以555纳米为中心的钟形曲线,它代表了人眼对各种波长光线的响应程度。
这个转换曲线与测量单位,是光度学理论和辐射度量学理论之间的唯一区别。每个辐射物理量都有一个对应的光度学物理量

Luminance通常用来描述平面的亮度。例如:高动态范围(high dynamic range,HDR)电视屏幕的峰值亮度通常在500到1000尼特(nit)之间。相比之下,晴朗天空的亮度大约为8000尼特,60瓦的电灯泡约为12万尼特,地平线上的太阳约为60万尼特。==所以尼特相当于Radiance==
色度学
人眼对于颜色的感知与光线的SPD(光谱功率分布,上上一节提到)密切相关。同时我们还知道了,二者之间并不是简单的一一对应关系。第二行和第三行所展示的SPD完全不同,但给人的感知却是完全相同的。色度学(colorimetry)研究的就是SPD和颜色感知之间的关系。
人眼可以分辨大约1000万种不同的颜色。对于颜色感知,人眼的视网膜上有着三种不同类型的视锥感受器(细胞),每种感受器对于不同波长的光线都有不同的反应。其他动物的眼睛则有着不同数量的颜色感受器,有些动物的眼睛甚至多达15个。因此,对于一个给定的SPD,我们的大脑只会从这些感受器中接收到三种不同的信号,这就是为什么只用三个数字就可以精确地表示任何颜色的原因
书中描述了一组实验来说明人类如何用科学方法量化 “颜色感知”。从人眼的生理特性出发,通过实验建立标准,最终用简单的数值(比如 XYZ、xy)精准描述任何颜色,解决了 “不同光线(SPD)可能看起来一样” 的问题。 用 XYZ 表达任何颜色的核心原理,不管光线的光谱多复杂,只要编码(XYZ)相同,人眼感知到的颜色就完全一致。
CIE 1931 色度图(图 8.8)是一张「人类可见颜色的 “地图”」—— 把所有我们肉眼能分辨的颜色,都精准定位在一张二维图上,核心作用是直观展示 “颜色的位置、范围和关系”,方便标准化对比和应用(比如屏幕、打印机的颜色匹配)。

- 图上的黑色轮廓线,就是 “人类可见颜色的全部范围“。
- 白色三角形:代表某类设备的「色域范围」。三角形的三个顶点,对应设备能发出的 “三种基础色”(比如屏幕的红、绿、蓝像素,打印机的青、品红、黄墨水);
- 三角形内部的所有颜色,都是这台设备能精准还原的颜色;
- 三角形外部、但在黑色轮廓内的颜色,这台设备 “显示 / 打印不出来”(会被近似替代);
- 黑点:代表「标准白光」
色度图仅仅描述了一个平面,它仅包含了颜色的色调信息,想要完整地描述一个颜色,还需要第三个维度Y,即亮度luminance。这三个坐标在一起,定义了所谓的xyY坐标系。色度图对于理解颜色在渲染中的使用,以及理解渲染系统中的限制而言非常重要。电视或者计算机显示器会通过使用R、G、B颜色值来呈现颜色,每个颜色通道都会控制一个显示原色(display primary),这个原色会发出具有特定SPD的光线。三种原色都会按其各自的颜色值进行缩放,这些颜色值被叠加在一起,从而生成一个被观众所感知的单一SPD。
在图形渲染中有几个值得关注的RGB色域空间,每个空间都由R、G、B三原色和一个白点进行定义。为了对它们进行比较,我们将使用一种不同类型的色度图,它被称为CIE 1976 UCS (uniform chromaticity scale)色度图。它是CIELUV颜色空间的一部分,CIE将CIELUV颜色空间(以及另一个颜色空间CIELAB)作为XYZ颜色空间的替代方案

上边这些东西总结起来用于解释为什么RGB的vec3就可以用来渲染颜色,因为不管光线的波长组合多复杂(也就是 SPD 多不一样),只要它们给人眼的颜色感知相同,就都能用同一组 RGB 数值代替。
使用RGB颜色进行渲染
严格来说,RGB颜色值代表的是感知量,而不是真实的物理量,使用RGB颜色值来进行基于物理的渲染,在技术上来说是一个分类错误。正确的方法应当是在光谱物理量上执行所有的渲染计算,然后通过密集采样或者是投影到适当的基底上,并在最后将其转换为用于屏幕输出的RGB颜色值。
展示了一种用于激光投影仪屏幕的材料,它在激光投影仪光线波长的窄带处,具有较高的反射率,而在其他大多数波长上的反射率都较低。这使得这个屏幕表面会反射投影仪所发出的大部分光线,同时会吸收来自其他光源的大部分光线。在这种情况下,RGB渲染器将会产生严重的渲染错误。==一个极端例子展示RGB会错误渲染的场景==

然而,对于大多数渲染系统而言,尤其是那些并不是用于预测模拟的交互式应用程序而言,RGB渲染的效果得出奇的好。即使是动画电影的离线渲染中,也只是在最近才开始使用光谱渲染,而且只是少数情况,大部分离线渲染仍然使用的是RGB渲染。
从场景到屏幕
对于一个给定的虚拟场景,基于物理的渲染有着这样一个目标,即计算场景中可能存在的真实radiance。然而计算完成之后,渲染的工作还远未完成,我们仍然需要确定最终的结果,即显示器帧缓冲中的像素值。在本小节中,我们将讨论与此有关的一些因素。
HDR显示器通常会使用Rec. 2020和Rec. 2100标准。其中Rec. 2020定义了一个具有更宽色域的颜色空间,如图8.12所示,并且它与Rec. 709和sRGB色彩空间具有相同的白点(D65)。

虽然峰值亮度(peak luminance)和色域规格(gamut specification)对于编码而言十分重要,但是对于实际的显示设备而言,它们多少有些不切实际(aspirational)。因此,HDR显示器会在内部执行从标准规格到实际显示功能的色调映射(tone mapping)与色域映射(gamut mapping)。这个映射过程也可能会受到应用程序所传递过来的原始数据的影响,这些原始数据可能会指明实际的动态范围和色域范围
色调映射 toneMapping
在伽马矫正时,即将线性的radiance值,转换为用于显示设备的非线性编码值的过程。显示编码所使用的函数是显示器光电转换函数(electrical optical transfer function,EOTF)的逆函数,它确保了输入的线性值与显示器发出的线性radiance相匹配。在我们前面的讨论中,忽略了发生在渲染和显示编码之间的一个重要步骤,下面我们将对这个步骤进行介绍和讨论。
这个步骤叫做色调映射(tone mapping)或者色调再现(tone reproduction),它是指将场景的radiance转换为显示器radiance的过程。在这个步骤中所应用的转换函数称为端到端转换函数(end-to-end transfer function)或者场景到屏幕转换函数(scene-to-screen transform)。图像状态(image state)的概念是理解色调映射的关键[1602],有两种基本的图像状态:场景参考(scene-referred)图像是根据场景中的radiance进行定义的,显示参考(display-referred)图像是根据显示器的radiance进行定义的。图像状态与编码无关,在这两种状态下的图像,都可以进行线性编码或者非线性编码。图8.13展示了图像状态、色调映射和显示编码是如何在成像管线中进行组合的,这个成像管线用于将最初渲染生成的颜色值,转换为最终用于显示的颜色值。

同一个场景使用了四种不同的色调变换。这些结果的差异主要体现在图中的绿色圆圈区域,因为那里的场景像素值特别高。左上角:直接裁剪(同时使用了sRGB OETF);右上角:Reinhard方法[1478];左下角:Duiker方法[392];右下角:寒霜方法(保持色相的版本)[497]。Reinhard,Duiker和寒霜的变换,都可以保留因裁剪而丢失的高光信息。然而,Reinhard曲线倾向于降低图像中较暗部分的饱和度[628, 629],而Duiker变换则增加了较暗区域的饱和度,后者有时会被认为是更好的特性[630]。通过一些特殊设计,寒霜变换保持了饱和度和色相,避免了强烈的色相偏移,请仔细观察其他三张图片左下角的圆圈区域。

曝光
- 动态曝光:用上述方法(对数平均 / 直方图 / 光照强度)实时计算每帧曝光,适配场景光照变化(比如从室内到室外,曝光自动降低,避免过曝);
- 静态曝光:多数游戏的选择 —— 美术人员根据场景固定光照(比如室内、室外、夜景)手动设置曝光值,避免动态曝光的意外波动(比如突然出现极亮像素导致画面骤暗);
- 核心原则:无论哪种策略,曝光都是 “线性缩放”—— 只改变亮度的整体范围,不破坏线性空间的计算规则(后续色调映射才做非线性变换)。
曝光的本质是「场景亮度到显示亮度的 “预处理缩放”」,核心是找到一个稳定、合理的缩放因子。核心目标让场景的关键细节(中间调、灰卡对应的亮度)落在显示器的敏感区间,同时尽可能保留高光和阴影细节,符合人眼感知。
颜色分级
这个内容动手实践一下应该就好懂了
在章节8.2.2中,我们提到了择优图像再现(preferred image reproduction)的概念,即生成在某种意义上看起来比原始场景更好的图像。它通常会涉及到对图像颜色的创造性处理,这个过程被称为颜色分级(color grading),或者调色、校色等,它们的含义实际上都是一样的。
数字颜色分级已经在电影工业中使用了一段时间,早期的例子包括电影《逃狱三王(O Brother, Where Art Thou?)》(2000)和《天使爱美丽(Amelie)》(2001)。颜色分级通常是通过交互式的操作,来对场景图像的颜色进行调整,直到实现想要的创意“外观”,然后再将相同的操作序列,重新应用到一个镜头或者一个序列中的所有图像上。颜色分级技术从电影传播到游戏领域中,现在在游戏中被广泛应用[392, 424, 756, 856, 1222]。
Selan [1601]展示了如何将来自一个颜色分级,或者图像编辑应用的任意颜色转换,“烘焙”到一个三维颜色查找表(LUT)中。通过将RGB颜色值作为xyz坐标输入,来从这个表中快速查找对应的新颜色;这种方式可以用于从颜色到颜色的任何映射,不过这个过程会受到LUT分辨率的限制。Selan的烘焙过程从一个相同LUT开始,这个LUT会将每个输入的颜色,映射到相同的输出颜色,然后再将其“切片”从而创建一个二维图像。然后将这个切片的LUT图像加载到一个颜色分级应用程序中,并对其应用定义目标创意外观所需要的操作。需要注意的是,只能对LUT应用颜色操作,需要避免模糊等空间操作。然后将编辑好的LUT保存下来,“打包”到一个三维GPU纹理中,并在渲染的过程中进行使用,从而动态地对渲染像素应用相同的颜色转换。Iwanicki [806]提出了一种聪明的方法,当在LUT中存储颜色变换的时候,可以使用最小化的最小二乘法,来减少采样误差。
在后来的出版物中,Selan [806]对两种执行颜色分级的方法进行了区分。第一种方法是对显示参考的图像数据进行颜色分级操作。第二种方法通过显示变换,对结果进行预览,然后再对场景参考的数据进行颜色分级操作。虽然显示参考的颜色分级方法更加容易操作和实现,但是对场景参考的数据进行颜色分级操作,可以生成更高保真度(fidelity)的结果。
当实时应用程序首次使用颜色分级技术时,显示参考方法占据了主导地位[756, 856]。然而,场景参考方法由于其更高的视觉质量,而获得了更多的关注[198, 497, 672],如图8.16所示。对场景参考的图像数据应用颜色分级操作,还可以将色调映射曲线烘焙到颜色分级LUT中[672],从而节省一些计算量,就像在游戏《神秘海域4》中所做的那样[198]。
游戏《神秘海域4》中的场景画面。最上面的截图没有使用颜色分级,下面两个截图各自应用了一个颜色分级操作。为了便于说明,我们选择了一个极端的颜色分级操作(将原始图像乘以一个高饱和度的青色)。在左下角的截图中,将颜色分级应用在了显示参考图像上(即色调映射之后);而在右下角的截图中,将颜色分级应用在了场景参考图像上(即色调映射之前)

在进行LUT查找之前,还必须将场景参考的数据重新映射到$[0,1]$范围中[1601]。在寒霜引擎[497]中,使用了感知量化曲线OETF来实现这个目的,尽管可以使用一些更加简单的曲线。Duiker [392]使用了一个对数曲线,而Hable [635]则建议使用一次或者两次的平方根运算来实现。