TA入门笔记(十一)
参考
may佬《技术美术百人计划》
韩世麟 Gamma校正与线性工作流入门讲解
PZZZB Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗?
图形2.6 伽马校正
Gamma校正
颜色空间
回顾:图形2.1 色彩空间

- sRGB与Rec-709的三原色相同,传递函数不同
传递函数
颜色空间下的颜色要显示到电子设备上,需要转换成非线性的视频信号,此时就要用到传递函数
一个传递函数包含两部分:
- 光转电传递函数(OETF),负责把场景线性光转到非线性的视频信号
- 电转光传递函数(EOTF),负责把非线性视频信号转换成显示光亮度

定义
Gamma可以简单定义为:
V o u t = V i n g a m m a V_{out}=V_{in}^{gamma} Vout=Vingamma
Gamma是指对线性三色值和非线性视频信号之间进行编码和解码的操作

- 相机拍完照片后,需要把它转化成电脑可以识别的视频信号进行存储,这时候需要进行Gamma编码操作
- 通过显示器进行显示时,又需要进行Gamma解码操作来把非线性的视频信号还原成线性的光信号

- 图像经过gamma编码储存时会进行一次gamma值为0.45的映射,此时的图像会比实际的物理像素值要亮(脑补)
- 显示器进行显示时,需要将储存的每个像素做一次gamma值约为2.2的校正,使最终的显示结果还原为正确的物理数据,过亮的图片会被还原成正常的亮度
question:为什么不直接将图片使用线性方式存储呢?
- 主要目的是为了优化储存空间和带宽,更好地利用编码空间
- 人眼对暗部的变化更加敏感,因此需要使用更高的精度来保存暗部信息
韦伯定律与CRT
韦伯定律

从人的主观视觉感受上来说,上边的灰度值过渡更加均匀,但是事实上下边的亮度才是均匀线性变化的
- 上边的中灰色称为美术中灰,实际光强只有白色的21.8%
- 中灰值并非固定的,人眼对亮度的感知是相对的,完全相同的色条在不同的背景下也会带来截然不同的感受


- Gamma编码的曲线就是物理线性增长的亮度到人眼视觉感受上的均匀灰阶的映射
韦伯定律:感觉的差别阈限随原刺激量的变化而变化,且表现为一定的规律性
- Δ Φ / Φ = C \Delta \Phi/\Phi=C ΔΦ/Φ=C
- Φ \Phi Φ为原刺激量
- Δ Φ \Delta \Phi ΔΦ为此时的差别阈限
- C C C为常数,又称韦伯率
- 简单来说就是,当所受刺激越大时,需要增加的刺激也要足够大才会让人感觉到明显变化,但是只适用于中等强度的刺激
question:为什么不直接将图片使用线性方式存储呢?
回到刚才的问题,在了解了韦伯定律的原理之后对Gamma编码储存的目的会有进一步的了解
8bit图片只能存储256个灰阶,如果采用均匀分布的物理灰阶,采样分布如下:

采用均匀分布的美术灰阶时,采样分布如下:
可以看出,采用物理分布时,采样是明显朝着亮部集中的,暗部的采样信息会过少
反映到图片本身,对于8bit图片来说,如果线性记录物理光强,图片的暗部会产生明显的色阶断层
因此,Gamma编码的作用就是通过函数将美术中灰映射到中间,使得物体的亮部和暗部能获得相同的色阶数目,更符合人眼的直观感受
小结
- 人眼对暗部变化比亮部更加敏感
- 我们目前所使用的真彩格式RGBA32,每个颜色通道只有8位用于记录信息,为了合理使用带宽和存储空间,需要进行非线性转换
- 目前我们所普遍使用的sRGB颜色空间标准,他的传递函数gamma值为2.2(2.4)
CRT
早期的大屁股显示器使用的是CRT(阴极射线显像管),这种设备的亮度与电压不成线性关系,而是gamma值约为2.2的类似幂律的关系,与存储图像的gamma映射恰好成反函数
这种硬件特性会把画面压暗,刚好把储存的偏亮的图片恢复到真实的物理光强

线性工作流
TA很多时候需要接触到一些图形效果的制作以及修改一些图形效果出错的问题,因此需要有意识地建立正确的工作流程
线性工作流就是在各个环节正确地使用gamma编码解码,保证最终得到的颜色和输入的物理数据是一致的
- 如果是使用gamma空间的贴图,在传给着色器之前需要从gamma空间转到线性空间,让我们在着色器中进行渲染计算时使用的是线性空间的颜色,避免出现显示上的错误

统一到线性空间的过程是看起来是这样的,用图中橙色的框表示

我们从橙色框的左上角出发。
第一步,输入的纹理如果是sRGB(Gamma0.45),那我们要进行一个操作转换到线性空间。这个操作叫做Remove Gamma Correction,在数学上是一个2.2的幂运算 c → c 2.2 c\rightarrow c^{2.2} c→c2.2。如果输入不是sRGB,而是已经在线性空间的纹理了呢?那就可以跳过Remove Gamma Correction了。
注:美术输出资源时都是在sRGB空间的,但Normal Map等其他电脑计算出来的纹理则一般在线性空间,即Linear Texture。
第二步,现在输入已经在线性空间了,那么进行Shader中光照、插值等计算后就是比较真实的结果了。如果不对sRGB进行Remove Gamma Correction直接就进入Shader计算,那算出来的就会不自然。
第三步,Shader计算完成后,需要进行Gamma Correction,从线性空间变换到Gamma0.45空间,在数学上是一个约为0.45的幂运算 c → c 1 2.2 c\rightarrow c^{\frac{1}{2.2}} c→c2.21。如果不进行Gamma Correction输出会怎么样?那显示器就会将颜色从线性空间转换到Gamma2.2空间,接着再被你看到,结果会更暗。
第四步,经过了前面的Gamma Correction,显示器输出在了线性空间,这就和人眼看物理世界的过程是一样的了!
不使用线性工作流可能出现的问题:
亮度叠加:由于gamma变换之后的光强度是原来的2.2倍,在进行亮度叠加时易出现过曝的问题

颜色混合:进行纯色的混合之前如果没有对非线性的颜色进行转换,在纯色的边界会出现黑边

渲染计算:如果将非线性空间下的中灰色0.5作为物理光强0.5进行计算会出现下图左边的现象

Unity中的颜色空间
通过点击菜单Edit->Project Settings->Player页签->Other Settings下的Rendering部分进行修改,参数Color Space可以选择Gamma或Linear

- 当选择Gamma Space时,Unity不会做任何处理(默认),即Remove Gamma Correction 、Gamma Correction都不会发生,除非自己手动实现
- 当选择Linear Space时,Unity会采用上文中提到的线性流程。对于sRGB纹理,Unity在进行纹理采样之前会自动进行Remove Gamma Correction,对于Linear纹理则没有这一步。而在输出前,Unity会自动进行Gamma Correction再让显示器输出。
- 对于特定用途的纹理,可以直接设置他们所属的类型:如Normal Map、Light Map等都是Linear,设置好类型Unity自己会处理他们。

- 还有一些纹理不是上面的任何类型,但又已经在线性空间了(比如说Mask纹理、噪声图),那你需要取消sRGB这个选项让它跳过Remove Gamma Correction过程

硬件支持
线性空间需要图形API的硬件支持,目前支持的平台有:
- Windows,Mac OS,Linux(Standalone)
- Xbox One
- PS 4
- Android(OpenGL ES 3.0)
- iOS(Metal)
- WebGL
Unity主要由两个硬件特性来支持
- sRGB Frame Buffer
- 将Shader的计算结果输出到显示器前做Gamma校正
- 作为纹理被读取时会自动把存储的颜色从sRGB空间转换到线性空间
- 调用ReadPixels()、ReadBackImage()时,会直接返回sRGB空间下的颜色
- sRGB Frame Buffer只支持每通道为8bit的格式,不支持浮点格式
- HDR开启后会先把渲染结果绘制到浮点格式的FB中,最后绘制到sRGB FB上输出
- sRGB Sampler
- 将sRGB的贴图进行线性采样的转换
使用硬件特性完成sRGB贴图的线性采样和shader计算结果的gamma校正,比起在shader里对贴图采样和计算结果的校正要快
资源导出问题
Substance Painter
当Substance的贴图导出时,线性的颜色值经过伽马变换,颜色被提亮了,所以需要在Unity中勾选sRGB选项,让它在采样时能还原回线性值

Photoshop
如果使用线性空间,一般来说Photoshop可以什么都不改,导出的贴图只需要勾选sRGB;如果调整PhotoShop的伽玛值为1,导出的贴图在Unity中也不需要勾选sRGB

Document Color Profile
- PhotoShop对颜色管理特别精确,Unity里看到的颜色要经过显示器的伽玛变换,而PhotoShop不会,PhotoShop会读取显示器的Color Profile,反向补偿回去
- PhotoShop有第二个Color Profile,叫做Document Color Profile。通常它的默认值就是sRGB Color Profile,和显示器的Color Profile一致,颜色是被这个Color Profile压暗了,所以PhotoShop中看到的结果才和Unity中一样
Unity中的混合是线性混合,Photoshop的图层和图层之间做混合的时候,每个上层图层都经过了伽马变换,然后才做了混合。在设置中更改,选择“用灰度系数混合RGB颜色”,参数设置为1,这样图层才是直接混合的结果

作业:尝试伽马校正的几种方法
Gamma空间

Linear空间+勾选sRGB

Linear空间+不勾选sRGB

Linear空间+不勾选sRGB+手动进行gamma校正
fixed4 MainTex = tex2D(_MainTex, i.uv);MainTex = pow(MainTex,2.2);

通过对比可以看出,没有经过Gamma解码的贴图会明显偏亮
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

