Unity 图片叠加 实现五边形 unity两张图片切换_unity切换图片


1.前言

由于现在大家都喜欢用PBR 很显然要考虑到 线性空间。手机上大部分现在的都做法都是在Gamma下 shader中 Color 平方一下 最后在后处理中 再转为Gamma空间 而UI显然还是Gamma空间 我本人也是比较赞同这个做法 毕竟 增加的消耗不多。 具体可以看下大神的这篇文章具体可以看下大神的这篇文章(Unity的Gamma校正以及线性工作流)。。。。。再看完这篇文章后 陈嘉栋提到了关于解决混合问题的处理方法

1.所有美术制作人员在线性空间中制作

2.ui shader alpha pow(2.2) 操作(PS:每个UI 都要做pow 2.2? 算了吧 感觉很费)

3. “仍然使用gamma space的workflow,但是涉及光照的shader自己来做pow 2.2和pow 0.45的” PS:通过抓帧看 很多游戏 是直接平方 和开根 毕竟 很近似 为了性能考虑吧

然后真的没办法了?公司有几个项目组 考虑就在Unity线性环境下制作。特效 场景 角色 可以在线性环境下工作 但是UI在混合上 出现了问题。我觉得UI有没光照计算 也没要线性下工作。。而且切换到线性 workflow 制作UI 会给美术带来一些麻烦吧(我这么觉得的。。很多人可能从来没把PS调到过线性下吧。当然也可以这么干PS: Unity 线性空间下UI Alpha混合错误,Photoshop设置) 。 那有没有可以不改变UI制作的流程 在GAMMA下 制作呢 我想到一种方法 以下仅供参考。

2.原因分析

首先我在PS下做了一张 (0.5,0,0,0.5) 的半透红色贴图在GAMMA工作下的展示


Unity 图片叠加 实现五边形 unity两张图片切换_贴图_02

上图是在GAMMA下


Unity 图片叠加 实现五边形 unity两张图片切换_unity切换图片_03

上图是在linear下勾选SRGB

Unity 图片叠加 实现五边形 unity两张图片切换_工作流程_04

上图是linear下 没有勾选srgb

可以看出 图2 比图1亮一些 原因在于在 SrcAlpha OneMinusSrcAlpha 下(背景纯黑)

图1:color = 0.5 r * 0.5 alpha + 0 * (1-0.5) = 0.25

我们看下 linearworlflow下


Unity 图片叠加 实现五边形 unity两张图片切换_Unity 图片叠加 实现五边形_05


在RD下看到 BackBuff 是srgb的 所以 图2 color = (0.5 * pow(2.2) *0.5 + 0 * pow(2.2) *(1-0.5) )pow(1/2.2) = 0.3648.. 所以亮于 图1

图3 color = (0.5*0.5 + 0 * pow(2.2) *(1-0.5) ) * pow(1/2.2) = 0.5325...

所以图3最亮 > 图2> 图1 (PS: 可以拿颜色截取工具看下哦)

3.如何解决?

既然知道了原因。。。既然是因为FrameBuff 是SRGB的 那我自己建一张 线性的 RT不就行了吗。于是立马动手板砖。

1.首先简历一张 线性RT 绑定在UICamera上


public void OnPreRender()
    {
       RenderTextureFormat format;
        format = RenderTextureFormat.ARGB32;
        m_RT = RenderTexture.GetTemporary(m_Camera.pixelWidth, m_Camera.pixelHeight, 24, format,RenderTextureReadWrite.Linear);
        m_RT.DiscardContents(true, true);
        m_Camera.targetTexture = m_RT;
    }

    public void OnPostRender()
    {
        if (m_RT != null)
        {
            m_Camera.targetTexture = null;
            RenderTexture destination = null;
            Graphics.Blit(m_RT, destination, mt,0);
            RenderTexture.ReleaseTemporary(m_RT);

        }
    }


2.取消图片SRGB选项

3.Render..


Unity 图片叠加 实现五边形 unity两张图片切换_贴图_06


linear workflow 下的 效果

4.最终检测 和 GAMMA下渲染效果一样

4.原理

1.讲所有的UI 绘制到 linear 下的RT,因为图片本身也是linear的 所以 在RT中的颜色 = 0.5 * 0.5 + 0*(1-0.5) = 0.25

然后绘制 RT到 frameBuff上 color = (0.25 * Pow(2.2) + 0 *(1-0.5) *pow(2.2)) *pow(1/2.2) = 0.25,

当中的 “0.25 * Pow(2.2)” 需要你在shader中加上


fixed4 col = tex2D(_MainTex,i.uv);
				col.rgb = GammaToLinearSpace(col.rgb);
				return col;


最终效果 两遍一样 ~开心 当然 这个工作流程 需要 多一个RT 和多一次后效的draw call

5.实际项目中。。。当你用这个方法一样。。就会遇到坑爹情况


Unity 图片叠加 实现五边形 unity两张图片切换_unity切换图片_07


这个原因是因为我们的rt中Alpha通道倍多次写入造成的 。那我们的解决办法就是整个场景渲染也作为一个RT进行混合sceneRT=>UI RT====》Framebuff=>最终结果


Graphics.Blit(null, rt) //拷贝一下SceneRT
Graphics.Blit(rt, rt,Material); //因为拷贝之后场景是线性的 偏暗 所以再转回GAMMA下颜色


在写回Framebuff时候 记得 混合模式修改 1 0 然后大功告成!让我们看下效果


Unity 图片叠加 实现五边形 unity两张图片切换_Unity 图片叠加 实现五边形_08


上面区域的是GAMMA模式 下面是线性 混合正常 搞定

5.结束

当然 会多出3次draw call全屏渲染 但是如果考虑场景本身也会做 tonemapping 和bloom 其他 也就多一次吧 当然。。这样做IOS马甲包时候 是不是可以不用换UI。。直接风格化下 就可以了。。反正是后效。。。前面的几种方法都可以 我个人倾向于 GAMMA下的工作流程

PS:9流程程序员 第一次分享 大家见谅