Gamma 校正与 Color Space

居然现在才发现~原来我们在计算机里用的颜色一直都是错的~~

参考 Youtube 的视频,很形象的介绍了,一般Gamma 空间使用的颜色,通过混合后,为什么会比真实下的混合要更加暗 https://www.youtube.com/watch?v=LKnqECcg6Gw Unity官方文档关于颜色空间 https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html

Unity颜色空间的总结

《UnityShader 入门精要》第18.4 关于伽马校正




UNITY 圆环 不同颜色 unity加颜色_UNITY 圆环 不同颜色


1.颜色混合的时候会变黑 原因可以看下图~~


UNITY 圆环 不同颜色 unity加颜色_颜色空间_02


个人测试

在Gamma 空间输出颜色 0.5 中间的面片为 输出 0.5 值的时候


UNITY 圆环 不同颜色 unity加颜色_颜色空间_03


在线性空间下


UNITY 圆环 不同颜色 unity加颜色_unity透明通道加颜色_04


很明显在线性空间下的面片明显要比 Gamma空间的要亮,这是因为伽马空间下,直接输出 0.5 会被显示器 进行显示Gamma的操作,也就是得到了 pow(0.5,2.2) = 0.22左右的亮度

而在线性空间下,Unity 会自动帮我们进行伽马校正 ( pow(fragColor.rgb,1.0/2.2)) 这就叫伽马校正,即 0.5 最后输出还是 0.5 而不是 0.22

自己在Shader 中进行伽马校正

由于并不是所有的平台都支持伽马校正,所以我们可以通过Shader自己进行Gamma校正,这样的做法在Pbr等基于物理的计算中才会得到正确的值。


//大部分的图片都是经过伽马编码的,先还原它
 float3 diffuseCol = pow(tex2D(diffTex,texCoord),2.2);
fragColor.rgb = pow(fragColor.rgb,1.0/2.2);
    return fragColor;


这样就能保证在计算的时候使用的是线性空间下的颜色,但是这样的做法,在混合的时候依然是不正常的,因为这不是一个线性的值 如同Youtube上面说的 $$frac{(sqrt{x}+sqrt{y})}{2} <= frac{sqrt{x+y}}{2}$$

如果要想混合也正常,就只能让所有的Shader 先还原Gamma 保证所有的计算都是正确后,再用屏幕后处理进行一次 编码Gamma

对中间的面片进行了一次 编码Gamma,可以发现得到的颜色和在线性空间上基本是一致的


UNITY 圆环 不同颜色 unity加颜色_UNITY 圆环 不同颜色_05


关于线性空间工作流 1.纹理如果是sRGB(从PS 或者其他制图软件做的时候就需要确定颜色空间) 则读入的时候会进行 伽马矫正 2.如果在 PS 或者其他软件中 颜色空间 是RGBA 即线性空间,则在Unity 中无需选择sRGB,在Shader 读入图片的时候即是正确的值 在gramma空间下,勾选与否无关。 在liner空间下,勾选shader会自动将读到的像素作gramma矫正,即x的0.45次方 不勾选,shader读到的就是原始的颜色值 然后unity如果选了gramma空间,会自动将输出颜色做一个伽马矫正,偏暗,相当于拍照对图片的自动处理。 透明通道的值不会受到伽马编码的影响,勾选与否都不会影响其线性值。值得注意的是ps里必须用这个取色


UNITY 圆环 不同颜色 unity加颜色_贴图_06


探讨Texture Import Setting 的sRgb作用

使用renderDoc调试shader实际的值

1.Gamma空间下直接返回0.5


UNITY 圆环 不同颜色 unity加颜色_伽马校正_07


UNITY 圆环 不同颜色 unity加颜色_unity透明通道加颜色_08


2.linear空间下返回0.5


UNITY 圆环 不同颜色 unity加颜色_伽马校正_09


UNITY 圆环 不同颜色 unity加颜色_贴图_10


可以看出贴图格式不同,Gamma下是普通贴图,Linear下是sRgb贴图

读取贴图


UNITY 圆环 不同颜色 unity加颜色_UNITY 圆环 不同颜色_11


贴图在ps 默认的srgb空间下 rgb均为 128的值

1.在gamma空间下读取贴图 分开开启srgb贴图和不开srgb贴图


UNITY 圆环 不同颜色 unity加颜色_贴图_12


UNITY 圆环 不同颜色 unity加颜色_UNITY 圆环 不同颜色_13


开启不开启 在gamma空间下不影响~读取的数值,而且贴图的显示和ps中的一样

2.在linear空间下读取贴图 开启srgb贴图


UNITY 圆环 不同颜色 unity加颜色_伽马校正_14


UNITY 圆环 不同颜色 unity加颜色_伽马校正_15


shader 里面读到的值瞬间变成了 0.22,卧槽。。

关闭srgb贴图


UNITY 圆环 不同颜色 unity加颜色_颜色空间_16


UNITY 圆环 不同颜色 unity加颜色_unity透明通道加颜色_17


这时候虽然读出来是0.5的值,很明显贴图却变量了,和ps不一样

Color颜色值shader


UNITY 圆环 不同颜色 unity加颜色_伽马校正_18


unity里面这个颜色值,在线性空间下~选的0.5居然就是0.21


UNITY 圆环 不同颜色 unity加颜色_伽马校正_19


结论

1.我们在ps中使用的srgb图片,本身我们就一直在使用错的颜色值,也就是0.5看到的实际上是0.2,即使我们输入的还是0.5的值。 2.在Gamma空间中不会做任何矫正,ps做的值 就是shader读到的值 3.在linear空间中,shader中读到的值,如果在ps中是srgb的话,且贴图开启了sRGB格式读到的是 pow2.2后的值得,如上面的0.5会变成0.21。如果没勾选的话则输出为0.5,但是图片变亮 4.结论应该就是 在选了linear模式后,输出frambuffer前 做了一次 pow0.45来抵抗显示器的2.2 5.Gamma切换Linear 最好在项目初期确定好,由于混合效果的不同,对有Alpha通道的UI有一定的影响。也是不可转换的,应该在初期统一ps混合 勾选用 灰度系数混合RGB 颜色


UNITY 圆环 不同颜色 unity加颜色_unity透明通道加颜色_20