浅谈unity中gamma空间和线性空间

转载请标明出处:http://www.cnblogs.com/zblade/

1、概述   

好久没有写文章了,今天写一篇对gamma空间和线性空间的我的理解总结,在查阅和学习了各个资料后,算是一个我的笔记吧。  html

2、Gamma颜色空间和线性颜色空间

其实对于颜色空间的理解,我我的是这样理解的:全部的一切颜色空间,最终的目的,都是为了最终投入到人眼中,可以基本重现天然界的颜色。   函数

记住这一个目的,对下面的一些理解就会更加的有依据了。    学习

2.1 人眼的感知能力

既然目标是咱们人自身,那么咱们就须要对人自身的眼睛的感知能力有一个基本的认识:人眼对于光强度的感知是非线性的。   测试

什么是线性,什么是非线性,从数学的角度说,就是自变量的变化和因变量的变化是否成固定比例(默认为1),若是成比例,即:y = kx, 那么这个变化就是线性的。编码

若是不成固定比例,那么这个变化就是非线性的,非线性是天然界最多见的变化关系。   3d

人类对于不少环境因素的变化的感知能力,都是非线性的,例如对于音阶,就是基于等比关系,而不是线性关系;对于分贝,对于疼痛等级,等等。  htm

回到对光强的感知,人眼对于光强度的变化的感知,是非线性的,这是经过实验得出的结论。若是在一个全黑的房间中,放入一根蜡烛,此时感知的光强变化比较明显;blog

若是房间中已经放入100根蜡烛,再次放入一根蜡烛,此时人眼对这新加入的一根蜡烛带来的光强度变化是没有最初从0到1的感知强的(默认每根蜡烛的光强度增量同样)。   游戏

可见,人眼对于高亮部分的感知能力,是没有暗部的感知能力强的。   图片

2.2 存储空间的有限

上面说了人眼的感知能力特色,那么天然界的光又是如何?天然界的光强度,是和其对应的功率成正比的,对应的范围是极其大:日光下100000lux,  星光0.0003 lux...  

若是要将这么大范围的光强度变化都表示存储起来,其对内存的占用以及传输带宽的占用是没法承受的。

业界目前主流的,对于颜色亮度的表示,用的是8位,也就是8bit,从0-255来进行表示。逐渐也有32位的真彩,固然不在此次的讨论中。   

2.3 Gamma空间

基于1和2的论证,那么如何将天然采光的结果存储到实际的图片中,就有一个基本的思路:将天然光以接近人眼感知能力曲线的函数进行压缩到8位图像中,这时候获得的图形就是通过压缩后的颜色结果。   

所谓Gamma压缩,其实质就是这个压缩的函数,是以Vout = VinGamma 来进行压缩的。   

如今业界提到的Gamma = 2.2, 是业界通过反复测量,获得的一个数值,这样能够在256个灰度阶的范围内更多的保留暗部的细节:

 

 

 上面的两个图两个图,就能够基本的解释Gamma = 2.2 的来源,人眼的感知能力和n = 1/2.2的幂函数比较靠近,固然不一样环境下有不一样的数值,大概范围在1.8-2.5之间。   

2.4 线性空间

理解非线性空间-Gamma空间后,天然能够理解线性空间,就是上面图二中的 n = 1这条曲线,为何要提线性空间?由于咱们的相机对于光强的感知,是基于线性空间的。  

举一个简单例子,两个光子投射到相机上,其获得的光强就是2倍光子光强,固然咱们已经知道人眼并非2倍光强。   

而业界的图片都是Gamma空间中存储,那么相机到最终图片,就会经历一个编码过程,这就是所谓的Gamma编码,也就是: Vout = Vin(1/2.2) 这个过程。   

 

3、Gamma补偿

如今,咱们经过相机拍摄的图片,最终是以gamma空间的格式存储(业界标准称为sRGB), 那么咱们在显示器上查看图片,是否也是以sRGB的结果显示的?答案是否认的。

前面业界已经将原生天然界的光照进行了压缩,那么业界定然要经过必定的办法将压缩的图片从新转换回来,获得更接近天然界的图像,这个过程,就是Gamma补偿,也被叫作Gamma校订。   

既然咱们知道是以什么函数进行压缩,那么解压的过程,天然就是一个求逆的过程,能够获得:Vout = Vin2.2     

这一步是业界的显示器自动默认执行的,因此咱们在最终向显示器上提交的颜色,须要知足对应的关系。

用一张图表示整个采样到显示的过程: 

一句话总结: 采样生成,使用了Gamma编码,这是业界标准,显示过程,使用了Gamma补偿,这也是业界标准,选取gamma = 2.2, 这是业界根据人眼进行测试获得的比较靠近人眼感知能力曲线的数值。

 

4、Unity中使用线性空间和Gamma空间

 在图形学界,技术是不断进步和探索的,应用一直都是延迟更新的(为了向下兼容的须要)。  

固然gamma空间的存在,之前都是忽视这部分的差别,直接基于gamma空间的存图进行光学计算的。   

可是引擎中的光学计算(shader中),是基于线性空间的公式进行的,这样就会带来较大的差别,咱们推算的公式基于线性空间获得的,可是输入的数据是基于gamma空间存储的格式,图像采集获得的结果

做为光学计算公式的输入,获得的输出天然是错误的。之前游戏行业对于这个一直处于忍受阶段,也能够经过美术进行调整,获得较为差别不大的计算结果。   

最近几年逐渐推广的PBR技术,对于光照的计算更为苛刻,这推进了线性空间在游戏行业的逐步推广。   

4.1 Gamma空间的处理过程

在gamma空间中,在shader进行光学计算的过程当中,直接将图像采样获得结果带入公式中进行计算,获得的color存入colorbuff中,而后提交到显示器,进过一次gamma补偿,就获得最终的颜色。  

4.2 线性空间的处理过程

线性空间中,对全部的图片,默认认为图片都是线性存储的方式。因此若是原图是Gamma空间的sRGB的存储方式,须要勾选sRGB的标志,这样在进行shader计算的时候,会首先进行一次gamma补偿,

将颜色从gamma空间转换到线性空间,而后进行正确的光照计算,获得结果最后再转换回到gamma空间(gamma压缩), 最后提交到显示器,进行一次gamma补偿,获得最终的颜色。  

用一张图表示这两种处理的流程(直接用参考文章的图): 

 

一句话总结:unity中的gamma空间和线性空间,其实质就是对存储sRGB格式图片,进行不一样的光照计算,不一样的光照计算进行不一样的流程,获得精度不一样的结果,最后都须要统一为gamma空间

的格式,提交到显示器上进行gamma补偿,获得最终的显示图片。

 

 参考文章:

 https://www.zhihu.com/question/27467127 该问题下的大部分回答

https://zhuanlan.zhihu.com/p/37679604 较为简易

https://www.cambridgeincolour.com/tutorials/gamma-correction.htm 非游戏向的解释gamma校订   

https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html unity官网的gamma/线性介绍

相关文章
相关标签/搜索