Hello, gamma
Gamma的起源
关于gamma的起源通常有两种说法,一种是CRT历史遗留问题,另一种就是人眼感知论
CRT历史遗留问题
以前我们使用的都是CRT(cathode-ray tube,阴极射线管)显示器,这类设备的显示机制是,使用一个电压轰击它屏幕上的一种图层,这个图层就可以发亮,我们就可以看到图像了。CRT有一个特点,就是输入电压和显示亮度不是呈线性关系的。打个比方,输入电压是5v,显示器的显示亮度是20,我现在把输入电压加大到10v,结果一看,显示器的亮度并没有提高到40。那输入电压和显示亮度是什么关系呢?它们是幂律(power-law)曲线的关系:
CRT显示器输入电压和显示亮度呈幂律曲线关系 对于CRT显示器来说,这条曲线的幂为2.5,我们把它称为显示器的display gamma。现代的LCD显示器尽管已经不存在输入电压和显示亮度的问题了,但是为了兼容性,因此也设置了display gamma。Windows预设的display gamma为2.2,而Apple Mac预设的display gamma为1.8。由于这个问题的存在,当我们把线性空间的亮度值0.5输入到CRT显示器,最终显示的亮度值是 那么该如何解决这个问题呢?我们需要对捕捉到的图像进行gamma矫正,具体的做法就是把捕捉到的线性空间的亮度值转换到gamma空间,然后放到CRT上显示。举例来说,当捕捉到亮度值0.5时,我们进行gamma矫正,矫正后值为 综上所述,一个完整的图像系统包含如下2个过程:
- encoding gamma:即图像设备捕捉到的亮度值和编码的像素值之间的关系:
-
display gamma:编码的像素值和显示的亮度值之间的关系:
完整的图像系统
一般来说,encoding gamma * display gamma = 1,这样显示的亮度值就和捕捉到的亮度值完全一致了。
对于我们的图形渲染来说,我们需要一个encoding gamma,否则输出画面受display gamma的影响就会偏暗: 不同的display gamma对输出画面的影响 以上就是CRT历史遗留问题带来的gamma起源说
人眼感知论
人眼感知论的说法是人眼对亮度的感知是非线性的:
从人眼感知的层面来说,上面一行的亮度变化看上去是线性的。而实际上,下面一行的亮度变化才是真实的线性变化。所以,人眼对光的感知和真实的场景亮度之间的关系为: 人眼对光的感知和真实的场景亮度之间的关系 从上图可知,人眼其实对较暗部分的感知会更加敏感。自然界中0.217的亮度在人眼感知上就已经是中间亮度了。现实中也可以发现这一现象,举个例子,在一个漆黑的房间中,点燃了一根蜡烛,你会发现房间瞬间亮了许多,但当点燃第二根蜡烛的时候,并不会觉得房间比先前亮了两倍。假设我们使用8位空间来存储像素值的话,那我们就可以表达 通过gamma矫正来让暗部细节得到更多的色阶 以上就是人眼感知论的gamma起源说
sRGB
上面提到,为了配合人眼对亮度的感知,我们通过gamma矫正来让暗部细节得到更多的色阶。当显示的时候,我们就需要把图像还原成正确的亮度值来显示。巧合的是,CRT显示器有2.5的display gamma,人们想:“太棒了,我们不需要做任何调整就可以把gamma矫正的图像放到CRT显示器上正确显示了”。但此时的encoding gamma * display gamma = 0.45 * 2.5 = 1.125,不等于1。
直到1996年,微软与惠普开发了sRGB色彩空间,sRGB最初的设计目的是作为生成在因特网以及万维网上浏览的图像的通用色彩空间,最后选择的是使用gamma校准系数为2.2的色彩空间。这样,配合0.45的encoding gamma,就是0.45 * 2.2 = 1了。当然,1这个值不是绝对的,根据《Real-Time Rendering 3rd》书中的描述:在电影院这种昏暗的环境中,encoding gamma * display gamma = 1.5会让我们看起来更舒服。而在明亮的办公室环境中,encoding gamma * display gamma = 1.125会更好。
关于渲染
长期以来gamma矫正一直是容易被忽略的部分。我们会在gamma空间中采样纹理,获取颜色,计算光照,然后将结果输出,最后通过显示器的display gamma显示出来:这个过程虽然简单,但是物理上却是错误的,计算的结果并不准确,但由于显示器的display gamma的存在,因此最终的显示效果还不错,所以人们一直都没有关心gamma矫正。
随着人们对沉浸式、照片级真实感的渲染要求,在gamma空间中的计算结果已经无法达到要求了。特别是PBR渲染是要求一定要在linear空间中完成的。
光照
如果我们在场景中渲染一个球体,你也许认为下图的渲染效果是正确的:
其实不然,以球体表面上的某点p为例,如果点p的法线方向和光的方向之间的夹角为60度,那么计算的结果会是cos60 = 0.5,在显示时因为display gamma的存在,所以最终显示的值是纹理
我们在Photoshop中新建一张8位图,从左到右让它从黑到白渐变:
gamma空间从黑到白渐变 之前提到过,为了配合人眼对亮度的感知,在编码真实的亮度值时会执行gamma矫正。所以你看到的中间灰度0.5对应的其实是真实亮度0.217( linear空间从黑到白渐变 在游戏中我们使用的通常都是8位图,因此纹理中存储的值都经过了gamma矫正,位于gamma空间下。所以,当我们从纹理中进行采样时,需要将采样的值进行gamma decode,让它还原到linear空间下: 如果纹理中存储的值已经位于linear空间下了,就不需要再执行gamma decode了。Mipmap
Mipmap的计算是一种线性计算,需要在linear空间下完成。因此在计算Mipmap的过程中,也需要注意gamma矫正,否则就会得到错误的结果。
纹理过滤
纹理过滤也要注意gamma矫正的问题。对于bilinear过滤,先将采样后的值还原到linear空间下,然后再取平均。对于trilinear过滤,由于已经保证了mipmap计算的正确性,因此在不同的mipmap之间执行bilinear过滤也一定是正确的。
Alpha
Alpha存储的是不透明度,所以从纹理中采样alpha值时,不需要做gamma decode。需要注意的是alpha混合,它很容易受gamma矫正的影响。
在上图中,我们有3个圆,分别是绿色(0, 1, 0.78),黄色(1, 0.78, 0)和紫色(0.78, 0, 1),在绿色和紫色的混合中,出现了比较深的暗蓝色。假设alpha为0.5,当绿色和紫色混合时, (0.126, 0.218, 0.774)对应的颜色 而正确的过程应该是将(0.39, 0.5, 0.89)经过gamma矫正后输出,然后经过显示器的display gamma,最后的结果仍然是(0.39, 0.5, 0.89): (0.39, 0.5, 0.89)对应的颜色 正确的alpha混合结果:后处理
当我们将计算的值写入frame buffer/render texture时,会做gamma矫正以配合显示器的display gamma。如果有后处理,当从frame buffer/render texture中采样时,要做gamma decode,将采样的值还原到linear空间下,因为后处理也需要在linear空间下计算才是正确的。
渲染总结
对于渲染,如果输入的颜色和纹理是位于gamma空间下的,则需要先进行gamma decode,将它们转换到linear空间下,在linear空间下的计算才是物理正确的。对于后处理效果,计算仍然需要在linear空间下完成。在全部计算完成后,将最终结果输出之前,需要做gamma矫正,配合显示器的display gamma,最后的显示效果才是完全正确的:参考资料:
- Gamma Correction(https://learnopengl.com/Advanced-Lighting/Gamma-Correction)
- Gamma & Linear Color Space(https://www.jianshu.com/p/321f39b7fa93)
- 【图形学】我理解的伽马校正(Gamma Correction)(https://blog.csdn.net/candycat1992/article/details/46228771/)
- CRT显示器输入电压和显示亮度的关系(https://www.youtube.com/watch?v=Qmbg2eUwkT4)
- 了解Gamma Correction(http://aboutdada.com/?p=2171)
- 调色名词浅析——Gamma(伽玛)校正(https://zhuanlan.zhihu.com/p/37800433)
- 聊聊Unity的Gamma校正以及线性工作流(https://www.cnblogs.com/murongxiaopifu/p/9001314.html)
- GAMMA AND LINEAR SPACE - WHAT THEY ARE AND HOW THEY DIFFER(http://www.kinematicsoup.com/news/2016/6/15/gamma-and-linear-space-what-they-are-how-they-differ)
- 从0开始的OpenGL学习(二十九)-Gamma校正(https://www.jianshu.com/p/399e71392306)
- 对 Gamma 校正的个人理解(https://zhuanlan.zhihu.com/p/36581276)
- Real-Time Rendering 3rd
- Real-Time Rendering 4th
本文固定链接: https://www.jianshu.com/p/85a8d11b5cce
转载请注明: EnigmaJJ 2018年12月23日 于 简书 发表