Unity Gamma校正转为线性空间


相信大部分了解图形学的人,都听说过Gamma校正或者Gamma空间,线性空间这些词。这里不对Gamma Space形成的历史原因做过多描述。Gamma和Linear空间的一些原理,文章也很多,包括Unity官网的描述,都可以看看。

显示器显示的Gamma空间的颜色变化规律,对应了下图中的黄色曲线。当美术在Gamma空间中,RGB(255,255,255)的颜色单位上,增加了1的颜色亮度,最后输出显示的亮度,其实是低于1的。这个差距,在特别暗的地方更加明显,也就容易让场景因为太暗,而看不清细节。我们公司的美术也表示,线性空间的效果其实更加直观,而Gamma空间的颜色有可能会越叠越深。所以为了更好的美术效果,尤其是让贴图的阴暗处有更多的细节,将Gamma Space转换为Linear Space还是相当有必要的。

基本思路,一般来说就是通过pow(1/Gamma)将颜色强度提高。下图中的蓝色曲线是pow(1/2.2)的近似数,pow(0.45),这样就可以抵消掉黄色曲线的变化,使颜色变化可以趋于线性。
 

三种函数的曲线

Infinite 3D Head Scan by Lee Perry-Smith,licensed under a Creative Commons Attribution 3.0 Unported License(available from www.ir-ltd.net)


虽然Unity 5.5开始,已经提供转换工程为线性空间的功能,但是仅对OpenGLES 3.0及以上的设备进行支持。详细数据可以参考这篇Unity的Blog,可以看到,还有两成左右的设备是不具备这个条件的。所以如果项目组需要考虑低端机,尤其是考虑海外发行的话,就不能直接改变整个渲染空间。

因此替代的方法,是手动在Shader中,修改Colour Space。转换空间用到的相关函数,Unity其实已经在Unity CG.cgnic中提供了,可以直接使用。

函数如下:
 

  1. inline float GammaToLinearSpaceExact (float value)
  2. {
  3.                 if (value <= 0.04045F)
  4.                         return value / 12.92F;
  5.                 else if (value < 1.0F)
  6.                         return pow((value + 0.055F)/1.055F, 2.4F);
  7.                 else
  8.                         return pow(value, 2.2F);
  9. }
  10. inline half3 GammaToLinearSpace (half3 sRGB)
  11. {
  12.                 // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
  13.                 return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
  14.                 // Precise version, useful for debugging.
  15.                 //return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
  16. }
复制代码
  1. inline float LinearToGammaSpaceExact (float value)
  2. {
  3.                 if (value <= 0.0F)
  4.                         return 0.0F;
  5.                 else if (value <= 0.0031308F)
  6.                         return 12.92F * value;
  7.                 else if (value < 1.0F)
  8.                         return 1.055F * pow(value, 0.4166667F) - 0.055F;
  9.                 else
  10.                         return pow(value, 0.45454545F);
  11. }
  12. inline half3 LinearToGammaSpace (half3 linRGB)
  13. {
  14.                 linRGB = max(linRGB, half3(0.h, 0.h, 0.h));
  15.                 // An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
  16.                 return max(1.055h * pow(linRGB, 0.416666667h) - 0.055h, 0.h);
  17.                
  18.                 // Exact version, useful for debugging.
  19.                 //return half3(LinearToGammaSpaceExact(linRGB.r), LinearToGammaSpaceExact(linRGB.g), LinearToGammaSpaceExact(linRGB.b))
  20. }
复制代码


其中主要用到的是GammaToLinearSpace()和LinearToGammaSpace()。下面将说一下,到底怎么用这两个函数。

主要的思路是,手机靓号买号把从贴图中读取进来的颜色,同时也是Gamma Space下的颜色,进行一次转换,转换到Linear Space。之后对这些颜色数据进行原本要进行的处理。处理结束后,在输出的时候,进行一次逆转换,将这些颜色数据,从Linear Space转换回Gamma Space。

以下是我实际使用的一段代码:

  1. <blockquote>half4 color = UNITY_SAMPLE_TEX2D(_MainTex, i.uv);
复制代码


补充一点,由于通道图,一般来说,其实已经是线性的了,所以是不需要参与到这个转换中的,直接用就好。但这段代码里特别注意的一点是,最后转换回Gamma Space的时候,我在Color上乘了一个Unity_ColorSpaceDouble。

最开始,我只进行了一个转换回Gamma Space的方法,然后发现,场景不仅没有变亮,反而变得更暗了。随后查阅到一篇文章提到了,需要在最后转回Gamma Space的时候,乘上一个值。

“与此相关的有,一个Unity提供的与色彩空间相关的值,Unity_ColorSpaceDouble。这个值在Gamma Color Space时为2,在Linear Color Space时为4.594(2的2.2次方)。对于这个值可以这样来理解。一般在Gamma Color Space中将两个Color值相乘后,为了避免颜色变得很暗,会在后面乘以2。”

也就是说,为了避免颜色变暗,应该扩大两倍,但同时因为是在线性空间下,所以这个2要变成Unity_ColorSpaceDouble。

最后来看一下效果吧~
 


上图为Gamma Space时的效果,下图为做完一系列变换后的结果。可以看到,整体颜色变亮,尤其是暗部的亮度和细节都有明显的提升。
 


可以看到特别暗的地方,在进行Gamma校正之后的变化也相对较大。所以这里也需要注意一点,如果是项目已经进行了一段时期之后,想要进行Gamma校正,一定要同时修改光照等一系列参数,以避免一些地方的光照效果过曝。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中的Gamma空间模型是一种颜色空间模型,用于描述计算机图形中的颜色显示和计算方式。在Gamma空间模型中,计算机图形使用的颜色值会根据人类视觉系统的特性进行调整,以更好地适应人类的视觉感知。 在Gamma空间模型中,颜色值会经过一个Gamma校正的过程。这是因为人类眼睛在感知亮度时对不同光强的变化有不同的感知能力。Gamma校正可以调整颜色值中的亮度信息,使得较暗的颜色更容易被人眼感知,而较亮的颜色则会被衰减,以便在显示设备上更好地还原真实场景中的亮度级别。 在Unity中,Gamma空间模型是默认的颜色空间模型。它的工作原理是将颜色从sRGB空间(标准的RGB颜色空间)转换到线性空间,并在渲染完毕后再将颜色转回到sRGB空间,以便正确显示。 Gamma空间模型在图形渲染中起到重要作用。由于人眼对亮度的感知非线性,使用Gamma空间模型可以使渲染的图像更加逼真和准确。而在一些特殊的情况下,使用线性空间模型可能会导致图像亮度不平衡或者颜色失真的问题。 总结起来,Unity中的Gamma空间模型是一种能够根据人类视觉系统特性进行颜色调整的模型,能够使渲染图像更加真实和准确。通过使用Gamma校正,它可以调整颜色的亮度信息,以适应人眼对亮度的感知能力。而相对于线性空间模型,在大部分情况下,Gamma空间模型能够提供更好的图像表现效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值