Unity Gamma空间和线性空间

线性空间(Linear)

在物理世界中,如果光的强度增加一倍,那么亮度也会增加一倍,这是线性关系,为了模拟真实的物理世界,需要把亮度值转换到线性空间计算,这样才能得到正确的结果

Gamma空间

Gamma的产生有两个主要原因:一个是CRT显示器非线性响应的历史原因,另一个是人眼对暗部颜色更敏感
在这里插入图片描述
早期CRT显示器的电压和输出的亮度是非线性的,亮度( l l l)等于电压( u u u)的2.2次幂,即图中下凹曲线

l = u 2.2 , l ∈ [ 0 , 1 ] , u ∈ [ 0 , 1 ] l = u^{2.2},l\in[0,1],u\in[0,1] l=u2.2l[0,1]u[0,1]

这里的Gamma值就是2.2,现代显示器仍然使用这个Gamma值,显示器使用Gamma2.2空间意味着显示器会对每个像素进行一个2.2的幂运算,整体画面就会偏暗,为了抵消显示器的影响,需要对图像进行一个0.45的幂运算(0.45 ≈ 1 / 2.2),这个平衡的操作就叫做Gamma校正

在这里插入图片描述

另一个原因是人眼对暗部颜色更敏感
在这里插入图片描述

上方是人眼感觉到的亮度从0到1的变化,下方是真实世界中亮度从0到1的变化,人眼的感知是非线性的
RGBA中每个通道只有8位,只能存储256( 2 8 2^8 28)个级别的亮度,为了存储更多的暗部信息,会对存储的图像进行Gamma矫正(即进行0.45的幂运算),这样图像会更亮,相当于扩大暗部的范围,当然较亮的部分会丢失细节

Gamma空间计算问题

两个颜色叠加,0.2和0.3
在线性空间直接计算,0.2 + 0.3 = 0.5
在Gamma空间中, ( 0. 2 0.45 + 0. 3 0.45 ) 2.2 ≈ 1.15 (0.2^ {0.45} + 0.3^ {0.45} )^{2.2} ≈ 1.15 (0.20.45+0.30.45)2.21.15

两个颜色混合,0.1和0.7
在线性空间直接计算,(0.1 + 0.7) / 2 = 0.4
在Gamma空间中, ( ( 0. 1 0.45 + 0. 7 0.45 ) / 2 ) 2.2 ≈ 0.3289 ((0.1^ {0.45} + 0.7^ {0.45} ) / 2)^{2.2} ≈ 0.3289 ((0.10.45+0.70.45)/2)2.20.3289

在这里插入图片描述
这就导致在Gamma空间中一些较亮的部分容易过曝

工作流

在这里插入图片描述
Gamma工作流,这里的Shader计算就会出现上面说的问题
适合:无光照,无透明混合
对性能无影响
在这里插入图片描述
线性工作流,对性能有影响
在这里插入图片描述
在Unity中设置色彩空间,现在主流游戏都已经转向线性空间

sRGB

1996年,微软和惠普一起开发了一种标准sRGB色彩空间,s表示Standard。sRGB对应的是Gamma0.45所在的空间。
进过Gamma矫正和显示器矫正,还原到原来的亮度

( u 0.45 ) 2.2 (u^ {0.45})^{2.2} (u0.45)2.2
在这里插入图片描述
线性空间下,贴图如果勾选sRGB表示移除Gamma矫正,即会对贴图做一个2.2的幂运算,就是贴图会变暗一点,具体参考上面的线性工作流,等价于在片元着色器中做了如下操作

     fixed4 frag (v2f i) : SV_Target
     {
    
    
         float3 c = tex2D(_MainTex, i.uv);
         c = pow(c, 2.2);
         return float4(c, 1);
     }

在变量前加[Gamma]也表示移除伽马矫正,即会对变量做一个2.2的幂运算,[Gamma]只在线性空间下有用

    [Gamma]_Metallic("Metallic", Range(0,1)) = 0.5 

参考

Unity中Color Space、Gamma、Linear、sRGB都是什么?

Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗?

Unity项目从Gamma转Linear颜色空间的经验分享

猜你喜欢

转载自blog.csdn.net/sinat_34014668/article/details/128604170