量子计算9 发表于 2022-2-2 14:08

Unity线性空间下半透明UI的解决方案

文章目录


[*]前言
[*]一、第一种做法
[*]二、第二种做法
[*]三、第三种做法
[*]总结
[*]参考
<hr/>前言

这篇文章主要介绍解决Unity在线性空间下,UI对于带Alpha半透明的贴图,在混合颜色时就会出现错误的问题。
<hr/>一、第一种做法
这种做法可以在笔者的另一篇文章中有说明,网址下面显示:
其中做法就是:
解决Unity在线性空间下,UI对于带Alpha半透明的贴图,在混合颜色时就会出现错误。(备注:Unity线性空间下的sRGB选项不会对Alpha进行处理)。
混合公式:
Gamma空间下的Alpha混合公式:color = (A.rgb * A.a) + (B.rgb * (1 - A.a))
Linear空间下的Alpha混合公式:color = ((A.rgb ^ 2.2 * A.a) + (B.rgb ^ 2.2 * (1 - A.a))) ^(1 / 2.2)
解决步骤:
1)所有UI素材取消勾选sRGB选项,得到的混合公式为:color = ((A.rgb * A.a) + (B.rgb * (1 - A.a))) ^(1 / 2.2) ;
2)然后在输出的颜色上做一次pow(2.2),Unity内置管道可以直接用后处理实现,Universal Render Pipeline管道中可以在BlitPass中做处理,原理是差不多的。
这种做法有个缺点,就是改动这个后,UI上字体的颜色等都需要重新封装,校正下颜色,还有其他RT等都需要转下,读者可以做个全局开关,如果想换一种做法,开关直接关闭即可。
二、第二种做法
这种做法需要项目定下初期就得这么搞,参考下面这篇解答的做法:
我们只需要在PS上使用线性空间制作,因为PS默认是使用Gamma空间的,转为线性空间,在Unity内部就是统一空间下制作的,就不需要转换了。做法下图所示:


但是这个会存在一个问题,PS调出来的颜色会比原本的亮,因为做了转换。所以需要制作UI相关的同事需要一段时间去适应。如果项目中间临时换做法,支持第一种,因为改成这种做法成本比较高,一般美术领导不会同意,而且第一种做法消耗也不高,笔者可自行测试。
三、第三种做法
由于第二种做法会导致UI美术需要改变自己的于在Gamma空间工作,导致两边的工作流程有一些冲突,UI的美术不太适应线性空间的流程,也不太适用线性空间下的颜色在他们的自产工具里制作。因此我们可以将UI摄像机和场景摄像机分离,场景摄像机用linear空间下绘制,而UI摄像机在Gamma空间下绘制,即可解决这个问题。
过程就是场景中使用一个线性空间的表现形式,它有单独的相机区进行绘制,同时在与UI相机进行blender,输出到屏幕上。然后场景空间的相机进行Gamma校正,而UI本身就是在Gamma空间的流程进行工作的,所以它不需要Gamma校正。


总结

如果是项目创立初期,可以考虑使用第二种做法,这种做法也有不少项目这么搞,如果能使用第三种做法会更好。如果项目中后期换不过来了,就考虑第一种做法。

acecase 发表于 2022-2-2 14:14

请问第三种做法的具体实现是什么样的呢?据我目前所知,Unity中选了线性颜色空间的话,默认都会使用一个带gamma校正的framebuffer。这里难道是需要Unity选择gamma颜色空间,然后单独给场景相机设置一个线性RT嘛?期待解惑~

Ilingis 发表于 2022-2-2 14:16

来公司后可以用编辑器辅助验证想法了:应该是依然选择线性空间,场景相机渲染完后Blit到一个非sRGB buffer上,并手动做gamma校正。然后UI在这个buffer上继续画,画完Blit到backbuffer上,并手动做一个反gamma校正,抵消backbuffer(一般是sRGB的)上自带的gamma校正。此时UI贴图资源不勾选sRGB,看上去最终可以得到和PS默认颜色空间中一样的预览效果

Arzie100 发表于 2022-2-2 14:23

第一种方法对于 UI透明度为0,或者第一层透明叠加在黑底上比较适应吧,多层叠加肯定有问题

xiaozongpeng 发表于 2022-2-2 14:26

按照这种思路实现,虽然解决了UI透明度的问题。但是文本、UI特效又会多做了一次gamma,请问要怎么解决呢?

pc8888888 发表于 2022-2-2 14:33

请问第一种做法场景中的物体也是会收到后处理的影响吗?该怎么解决呢?

Ylisar 发表于 2022-2-2 14:41

同样的疑惑,有解决方案了吗
页: [1]
查看完整版本: Unity线性空间下半透明UI的解决方案