赞
踩
很多小伙伴会遇到下面的问题,就是把UI切好的图片放到Unity中,会发现有些颜色的差异,尤其是透明度混合方面会有很大的变化,这些都是由于Unity中颜色空间的设置问题,先给大家看一下Unity中的效果。
可以看到,在Gamma空间下,我是用PS输出的70%透明度的纯黑色的图片,和使用windows自带应用打开的图片没有任何区别,我们打开图片的设置,有一个sRGB选项(下文会详解sRGB选项),不管开启还是关闭这个选项,图片都不会有变。由于PS是使用Gamma空间进行图片制作和输出的,所以我们使用Gamma空间进行设置,可以得到一比一的效果。
那既然我们显示都是正确的,我们为什么不直接使用Gamma空间,而是要把颜色空间设置为Linear呢,下面是Unity的官方解释。
其中有这样一句话
所以我们在烘焙3d场景,或布置灯光时更倾向于选择Linear颜色空间得到最精确的结果,但是如果我们把颜色空间切换为Linear,就会发现UI有了一些不一样的变化,会发现颜色变浅了,效果如下
下面介绍一下ColorSpace中的Linear和Gamma两种工作流,这里引用一下知乎博主PZZZB的一张图片和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<Material>("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<Material>("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 © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。