Unity 颜色空间(Color Space)转换 您所在的位置:网站首页 gamma颜色空间与linear颜色空间的区别 Unity 颜色空间(Color Space)转换

Unity 颜色空间(Color Space)转换

2024-07-16 17:11| 来源: 网络整理| 查看: 265

很多小伙伴会遇到下面的问题,就是把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下的颜色直接带入的透明度公式,也就变成了下图公式

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

        

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

       

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

       

        使用的两个脚本如下所示

using System.Collections; using System.Collections.Generic; using UnityEngine; public class UICameraLinearCorrect : MonoBehaviour { private Material mat; private Material RenderMat { get { if (mat == null) { mat = Resources.Load("Materials/UILinearCorrectMat"); } return mat; } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, RenderMat); } } Shader "MyShader/UILinearCorrectShader" { Properties { _MainTex("Main Tex", 2D) = "white"{} } SubShader { Tags { "RenderType" = "Opaque" } LOD 100 //Blend SrcAlpha OneMinusSrcAlpha Pass { Cull Off ZWrite Off ZTest Always CGPROGRAM #pragma vertex vert #pragma fragment frag sampler2D _MainTex; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag(v2f i) : SV_Target { fixed4 color = tex2D(_MainTex, i.uv); color = pow(color, 2.2); return color; } ENDCG } } }

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

 

 

       

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

         

       

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

        

         

        Scene Camera使用的代码如下

using System.Collections; using System.Collections.Generic; using UnityEngine; public class SceneCameraLinearCorrect : MonoBehaviour { private Material mat; private Material RenderMat { get { if (mat == null) { mat = Resources.Load("Materials/SceneLinearCorrectMat"); } return mat; } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, RenderMat); } } Shader "MyShader/SceneLinearCorrectShader" { Properties { _MainTex("Main Tex", 2D) = "white"{} } SubShader { Tags { "RenderType" = "Opaque" } LOD 100 //Blend SrcAlpha OneMinusSrcAlpha Pass { // 制作后处理shader的时候要把这几个属性设置上 Cull Off ZWrite Off ZTest Always CGPROGRAM #pragma vertex vert #pragma fragment frag sampler2D _MainTex; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag(v2f i) : SV_Target { fixed4 color = tex2D(_MainTex, i.uv); color = pow(color, 1.0 / 2.2); return color; } ENDCG } } }

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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有