很好的视频
https://www.bilibili.com/video/BV15t411Y7cf/?spm_id_from=333.788.b_636f6d6d656e74.96&vd_source=6f3a5e0ac931d869aee3d7c9bb6847e0
● 一些颜色空间的举例,(具体参考2.1节内容)
● 图中可以看到,sRGB和Rec.709的色域是差不多的,三原色的位置是相同的,那么它们之间的区别就是:传递函数不同。
● 什么是传递函数:
○ 知道了颜色的颜色值之后,想要在电子设备上显示,就需要把它转换为视频信号,传递函数就是用来做转换的。
● 一个传递函数包括两部分:
○ 光转电传递函数(OETF),把场景线性光转到非线性视频信号值。
○ 电转光传递函数(EOTF),把非线性视频信号值转到显示光亮度。
○ 一个简单理解:拍照时,将照片存储在内存卡中,就是用视频信号存储的,如果要看这个照片,就把视频信号再转换成光信号。
伽马校正(Gamma Correction)
为什么需要伽马校正?
部分人认为,是由于早期CRT显示器的输出亮度和输入电压存在非线性关系,具体就是近似2.2次幂的关系,导致显示器的亮度要比计算机上存储的亮度要低。
举个例子:假如你计算机存储的亮度是0.5(亮度范围是0~1),CRT显示器的输出亮度并不是0.5,而是约等于 0.218,具体计算过程如下
当你输入0.5时,输出到显示器的值为
其中2.2这个指数就是伽马值,而显示器的这种非线性输出过程称为伽马展开(gamma expansion)。为了能够得到正确的输出,必须对输入进行补偿,方法是对输入进行一次指数为1/2.2的幂次运算,这个补偿的过程就是伽马校正:
经过伽马校正后,显示器便能正确显示我们的输入了 :
既然伽马校正起源于早期CRT显示器的非线性输出问题,而现在基本已经淘汰掉这些显示器了,并且当今的显示器已经可以做到线性输出了,那么我们是不是可以直接废弃伽马校正了呢?
实际上,我们仍然需要伽马校正!原因是:伽马校正可以提高暗部亮度的存储精度。
人眼对于较暗(接近0)的亮度值比较敏感,对于较亮(接近1)的亮度值则不太敏感,我们只能用一个8位二进制(可以表达0~255的整数)来存储亮度值,我们希望在整个图像中尽可能保留暗部细节。
下面举了例子说明:
假定我们要存储0.240和0.243这两个亮度值,如果不进行伽马校正,图片亮度的存储值分别为:
0.240和0.243的存储值变为了133和134,它们的实际显示效果就区分开了。当然,伽马校正会带来亮度较大值的表示精度的减小,例子如下:
无伽马校正:
有伽马校正:
可以看到,无伽马矫正的时候能区分的亮度值,到了伽马校正后反而无法分开了。
不过,人眼恰好对较暗值比较敏感,对较亮值不太敏感,所以亮部细节的丢失不会造成什么影响,而暗部细节的保留则会大大改善图像质量,这就是伽马校正至今依然采用的原因。
○ Gamma是指对线性三色值和非线性视频信号之间进行编码和解码的操作。
·编码和解码的理解: ○ 例如:
■ 拍到的照片,存在电脑里,就是把自然界中的光信号编码为视频信号
■ 查看照片时,就要把视频信号还原为线性的光信号,进行解码操作
○ 如图:线性空间(相机捕捉到的真实世界光信号) + gamma编码 + 显示器显示 = 结果
○
·用一张图来举例:
○ gamma编码:
■ 左图为存在硬盘中,将捕获到的物理数据做一次gamma值约为0.4的映射,这个过程称为gamma编码
■ 由图中可以看到,此时图像要比实际物理像素更亮(图不一定是实际的情况,只是亮度提高了的直观表示)
○ gamma校正:
■ 中间为显示图像时,需要为每一个像素做一次gamma值约为2.2的校正,来使的最终结果为正确的物理数据。
○ 可以看到经过gamma校正好,之前偏亮的图像亮度降低了。
○
·为什么不用线性的方式存储,而要来回转换呢?
● ①和人眼的特性有关
○ 人眼对暗部的变化感应更敏感
● ②非线性转换为了优化存储空间和带宽
○ 我们用于显示图像数据都是8bit,要充分利用带宽,就需要使用更多位置去存储暗部值。也就是 暗部使用高精度保存,亮部使用相对较低精度保存。
● 正如上边所说,我们人眼对于暗部是更敏感的
○ 上边是视觉上的均匀变化,而下边是物理量上的均匀变化。
● 补充:理论上上边的中灰是物理量上(下边)的21.8%,视觉上认为的美术中灰色,大约是物理中灰色的20%
● gamma编码的曲线:
○ 把人感受到的均匀灰阶和自然界线性增长的亮度进行一个映射,就是gamma编码的曲线
● 由图中可以看到
○ 自然界中亮度的0.2左右的亮度,对应的就是人眼感受到的中灰色(0.5)
○ 可以看到暗部的变化率更高,也就是说人眼对暗部的变化感受更敏感。
● 用人话说就是:
○ 当所受刺激越大时,需要增加的刺激也要足够大才会让人感觉到明显的变化,但是只适用于中等强度的刺激。
● CRT(阴极射线显像管)
○ 这种设备的亮度和电压不成线性关系,而是和gamma值约为2.2类似幂律的关系
○ 由于CRT的这个物理特性,刚好可以把亮度压暗,也就说,左图变亮的情况下,经过右图显示器的压低亮度校正,结果刚好可以显示正常。
■ 值得注意的是,上述所说的前提是,在条件相同的情况下(在明暗不同的环境下,看到的结果可能不同),我们取的中灰值,也不是指特定的一个值。
● 所谓的中灰值,并非某个具体的值,而是说人眼的具体感受
● 一个例子可以证明
○ 对于第一张图,可以很明显看到AB颜色不同
对于下面这张图,只是把AB连起来,就可以看到,其实是一种颜色(影子让周围更暗了)
//ps:如果你不信的话,可以用Snipaste取一下图1的A、B两种颜色,你就会发现,真的是一个颜色
1.课程中内容
● 对于技术美术来说,知道上边所说的还不够,因为很多时候我们会接触到一些图形效果的制作和修改。
● 这时候就需要一个正确的工作流程。
● 线性工作流:
○ 在各个环节正确的使用gamma编码/解码,来达到最终输出的数据和最初输入的物理数据一致的目的。
○ 如果使用Gamma空间的贴图,在传给着色器之前需要从Gamma空间转到线性空间。
■ 目的是在着色器中做一些渲染计算时会使用线性空间的颜色值,这样就不会出现一些显示错误的结果。
● 如果不在线性空间下进行渲染工作,可能会产生的问题:
○ ①亮度叠加时
■ 可以看到非线性空间下亮度叠加出现了过曝(亮度>1的)的情况
■ 因为Gamma空间经过gamma编码后的亮度值相对之前会变大。
○ ②颜色混合时
■ 如果在混合前没有非线性的颜色进行转换,就会在纯色的边界出现一些黑边。
○ ③光照计算时
■ 在光照渲染结算时,如果我们把非线性空间下(视觉上的)的棕灰色0.5当做实际物理光强为0.5来计算时,就会出现左边这种情况
■ 在显示空间下是0.5,但在渲染空间下它的实际物理光强为0.18(如右图)
1.在Unity中选择颜色空间
● 点击菜单 -> Project Settings -> Player页签 -> Other Settings 下的Rendering部分,通过修改Color Space可以来选择Gamma/Linear(线性)
○
● 当选择Gamma Space时
○ Unity不会做任何操作(默认Gamma)
● 当选择Linear Space时
○ 引擎的渲染流程在线性空间计算,理想情况下项目使用线性空间的贴图颜色,不需要勾选sRGB;
● 勾选sRGB?
○ 如果勾选了sRGB的贴图,Unity会通过硬件特性采样时进行线性转换
● 目前以下平台可以进行线性空间下的硬件支持
○ Windows,Mac OSx ,Linux(Standalone)
○ Xbox One
○ PS4
○ Android(OpenGL ES3.0)
○ IOS(Metal)
○ WebGL
● Unity主要通过以下两个硬件特性来支持
○ sRGB Frame Buffer
■ 将Shader的计算结果输出到显示器前做Gamma校正
■ 作为纹理被读取时会自动把存储的颜色从sRBG空间转换到线性空间
■ 调用ReadPixels()、ReadBackImage()时,会直接返回sRGB空间下的颜色
■ sRBG Frame Buffer 只支持每通道为8bit的格式,不支持float浮点格式
■ HDR开启后会先把渲染结果会知道浮点格式的FB中,最后绘制到sRGB FB上输出。
○ sRGB Sampler
■ 将sRBG的贴图进行线性采样的转换
● 使用硬件特性完成sRGB贴图的线性采样和shader计算结果的gamma校正,比在shader里对贴图采样和计算结果的校正要快。
1.SubstancePainter
○ SubstancePainter的贴图导出时,其线性的颜色值经过了gamma编码,所以颜色被提亮了。
○ 此时这个贴图需要在Unity中勾选sRBG选项,来让它被采样时能还原回线性值。
2.PS
● 从PS中导出图片,如果把灰度系数设为一的话,在Unity中就不需要勾选sRBG选项了;
● 如果PS中什么都不做设置的话,在Unity中勾选sRGB选项即可。
● Document Color Profile
○ PS对于颜色的管理是很精准的,我们在Unity中看到的颜色要经过显示器的gamma变换,而PS中的不会,PS会读取显示器的Color Profile,反向补偿回去
■ (也就是说,ps中的是真实的颜色值)。
○ PS自身有一个系统,会通过灰度值控制颜色的显示,(通常情况下这个值和显示器的gamma值一致,所以看起来会和Unity中看到效果的一样),可以通过改变灰度值来改变最终颜色显示的结果。
● 半透明效果
○ Unity中:
■ Unity进行半透明混合时,会先将它们转换到一个线性空间下然后再混合
○ PS中:
■ PS的图层和图层之间做混合时,每个上层的图层都会读取他们的Color Profile(gamma值),然后经过一个gamma变换再做混合,这样做得结果就会偏暗一些。
■ (可以在它的工作空间 的设置中进行更改,选择用灰度系数混合RGB颜色,参数设置为一,这样图层才是一个最终直接混合的结果)
● 如果做一次非线性映射(就是gamma校正),把美术灰阶中的中灰提到中间,这样亮部和暗部就都能分配到128个样本。这样下来保存的才是人眼看着舒服的/正常的结果。
②Gamma校正函数的理解
● 它是一个幂函数,y=xgamma
● 永远会穿过(1,1)和(0,0),对应的就是白色和黑色
● 对于gamma的值
○ 如果gamma=1,函数就是y=x,输入值=输出值,也就是不做校正
○ 如果gamma>1,函数图像下压,输入值会被下压