当前位置:   article > 正文

Unity 颜色空间(Color Space)转换_unity color space

unity color space

很多小伙伴会遇到下面的问题,就是把UI切好的图片放到Unity中,会发现有些颜色的差异,尤其是透明度混合方面会有很大的变化,这些都是由于Unity中颜色空间的设置问题,先给大家看一下Unity中的效果。

        

可以看到,在Gamma空间下,我是用PS输出的70%透明度的纯黑色的图片,和使用windows自带应用打开的图片没有任何区别,我们打开图片的设置,有一个sRGB选项(下文会详解sRGB选项),不管开启还是关闭这个选项,图片都不会有变。由于PS是使用Gamma空间进行图片制作和输出的,所以我们使用Gamma空间进行设置,可以得到一比一的效果。

        那既然我们显示都是正确的,我们为什么不直接使用Gamma空间,而是要把颜色空间设置为Linear呢,下面是Unity的官方解释。

线性或伽马工作流程 - Unity 手册

        其中有这样一句话

         所以我们在烘焙3d场景,或布置灯光时更倾向于选择Linear颜色空间得到最精确的结果,但是如果我们把颜色空间切换为Linear,就会发现UI有了一些不一样的变化,会发现颜色变浅了,效果如下

        

         下面介绍一下ColorSpace中的Linear和Gamma两种工作流,这里引用一下知乎博主PZZZB的一张图片和Unity官方的一个解释

颜色空间 - Unity 手册

        

        对于我们PS输出的图片,如果我们不做特殊的设置,那么我们的图片就是在Gamma空间下进行输出和制作的,下面有一个很关键的知识点,就是两个颜色空间的透明度混合公式

Linear Color Space

ret = (srcColor^2.2 * srcAlpha + dstColor^2.2 * (1 - srcAlpha) ) ^(1/2.2)

Gamma Color Space

ret = srcColor * srcAlpha + dstColor * (1 - srcAlpha)

        对于美术人员来说,他们在PS中通过透明度混合得到的最终效果,是使用Gamma空间下的计算公式进行计算得到的结果,而Unity中的Linear Color Space下却是使用第一个公式进行处理的,我们要做的就是要是用Linear下的公式,通过一些变化,让他得到与Gamma下相同的结果。

        下面要介绍一个知识,就是图片属性上的sRGB,对于点了sRGB属性的图片,Unity会默认对其做一次变暗的操作,也就是2.2次幂,也就是流程图上写的Remove Gamma Correction,通过这个操作,会得到Gamma1.0空间下的颜色,然后将得到的颜色放入Shader中处理(Shader默认使用的是Linear Color Space的混合公式)

        经过对上图两个公式分析可得,如果我们把UI的图片的sRGB取消,那么就可以让Remove Gamma Correction过程忽略掉,也就是把Gamma0.45下的颜色直接带入的透明度公式,也就变成了下图公式

  1. ret = (srcColor^0.45^2.2 * srcAlpha + dstColor^0.45^2.2 * (1 - srcAlpha) ) ^(1/2.2)
  2. = (srcColor * srcAlpha + dstColor * (1 - srcAlpha) ) ^(1/2.2)

        

        通过比较可知,这个公式和Gamma空间下的透明度混合公式,只差一个2.2次方,所以我们只需要增加一个摄像机的后处理,将UI摄像机的结果进行一个2.2次方即可达到UI最终的效果。(PS:对于项目中的UI的Canvas我们会使用Scene Camera的模式,这样就可以在对应摄像机上添加后处理,也可以增加各种不同的UI特效

       

        现在把我们的脚本添加到我们的摄像机上 

       

        使用的两个脚本如下所示

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class UICameraLinearCorrect : MonoBehaviour
  5. {
  6. private Material mat;
  7. private Material RenderMat
  8. {
  9. get
  10. {
  11. if (mat == null)
  12. {
  13. mat = Resources.Load<Material>("Materials/UILinearCorrectMat");
  14. }
  15. return mat;
  16. }
  17. }
  18. private void OnRenderImage(RenderTexture source, RenderTexture destination)
  19. {
  20. Graphics.Blit(source, destination, RenderMat);
  21. }
  22. }
  1. Shader "MyShader/UILinearCorrectShader"
  2. {
  3. Properties
  4. {
  5. _MainTex("Main Tex", 2D) = "white"{}
  6. }
  7. SubShader
  8. {
  9. Tags { "RenderType" = "Opaque" }
  10. LOD 100
  11. //Blend SrcAlpha OneMinusSrcAlpha
  12. Pass
  13. {
  14. Cull Off ZWrite Off ZTest Always
  15. CGPROGRAM
  16. #pragma vertex vert
  17. #pragma fragment frag
  18. sampler2D _MainTex;
  19. struct appdata
  20. {
  21. float4 vertex : POSITION;
  22. float2 uv : TEXCOORD0;
  23. };
  24. struct v2f
  25. {
  26. float4 vertex : SV_POSITION;
  27. float2 uv : TEXCOORD0;
  28. };
  29. v2f vert(appdata v)
  30. {
  31. v2f o;
  32. o.vertex = UnityObjectToClipPos(v.vertex);
  33. o.uv = v.uv;
  34. return o;
  35. }
  36. fixed4 frag(v2f i) : SV_Target
  37. {
  38. fixed4 color = tex2D(_MainTex, i.uv);
  39. color = pow(color, 2.2);
  40. return color;
  41. }
  42. ENDCG
  43. }
  44. }
  45. }

        但是由于我们把整体颜色调暗了,所以场景中的物体的颜色也会变暗,也就像下图

 

 

       

        可以发现场景中的UI颜色确实还原了,但是红色方块的颜色变化了 ,所以为了让场景颜色还原,我们需要再添加一个摄像机,将这个摄像机只看场景,原有的摄像机只看UI,同时将场景摄像机的颜色进行一个0.45次幂,还原他原来的颜色,操作如下

         

       

        对于场景摄像机,我们只需要看除了UI以外的所有层就可以 ,效果如下,可以发现颜色都得到了正确的显示

        

         

        Scene Camera使用的代码如下

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class SceneCameraLinearCorrect : MonoBehaviour
  5. {
  6. private Material mat;
  7. private Material RenderMat
  8. {
  9. get
  10. {
  11. if (mat == null)
  12. {
  13. mat = Resources.Load<Material>("Materials/SceneLinearCorrectMat");
  14. }
  15. return mat;
  16. }
  17. }
  18. private void OnRenderImage(RenderTexture source, RenderTexture destination)
  19. {
  20. Graphics.Blit(source, destination, RenderMat);
  21. }
  22. }
  1. Shader "MyShader/SceneLinearCorrectShader"
  2. {
  3. Properties
  4. {
  5. _MainTex("Main Tex", 2D) = "white"{}
  6. }
  7. SubShader
  8. {
  9. Tags { "RenderType" = "Opaque" }
  10. LOD 100
  11. //Blend SrcAlpha OneMinusSrcAlpha
  12. Pass
  13. {
  14. // 制作后处理shader的时候要把这几个属性设置上
  15. Cull Off ZWrite Off ZTest Always
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. sampler2D _MainTex;
  20. struct appdata
  21. {
  22. float4 vertex : POSITION;
  23. float2 uv : TEXCOORD0;
  24. };
  25. struct v2f
  26. {
  27. float4 vertex : SV_POSITION;
  28. float2 uv : TEXCOORD0;
  29. };
  30. v2f vert(appdata v)
  31. {
  32. v2f o;
  33. o.vertex = UnityObjectToClipPos(v.vertex);
  34. o.uv = v.uv;
  35. return o;
  36. }
  37. fixed4 frag(v2f i) : SV_Target
  38. {
  39. fixed4 color = tex2D(_MainTex, i.uv);
  40. color = pow(color, 1.0 / 2.2);
  41. return color;
  42. }
  43. ENDCG
  44. }
  45. }
  46. }

(PS:如果UI打了图集,图集的sRGB也要关闭掉) 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/程序安全守护者/article/detail/60334
推荐阅读
相关标签
  

闽ICP备14008679号