根据 iOS 15 上的黑暗模式,Unity 着色器出现故障

Unity shader glitches according to the Dark Mode on iOS 15

我正在使用着色器(下面的代码),它允许我将图像颜色转换为灰度(如果需要,可以使用透明度)。

一切都很完美,直到我将我的设备更新为 iOS15。自从更新后,我的着色器在渲染场景后立即出现故障。 经过很多天寻找解决方案后,我注意到这与 iPhone 黑暗模式有关。

我在这里提供了一些“概念”示例,以便向您展示当前发生的情况:

灰度着色器应用于红色立方体。

问题是我一直在为我的应用程序中的很多项目使用这些着色器,根据用户的暗模式首选项,这给了我一个不一致和丑陋的 UI。

注意:我不认为问题出在着色器本身,因为在 < iOS 15 版本上它工作正常。我想是关于 iOS 15 如何处理具有透明效果的着色器,但这只是一个假设,因为我仍然不知道如何使用着色器(我是一名学生)。

这是我正在使用的着色器:

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
        _EffectAmount ("Effect Amount", Range (0, 1)) = 1.0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
        }

        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha
    
        Pass
        {

        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                half2 texcoord : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            uniform float _EffectAmount;
            
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 c = tex2D(_MainTex, i.texcoord);
                c.rgb = lerp(c.rgb, dot(c.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);
                return c;
            }

        ENDCG
        }
    }
    Fallback "Standard"
}

这是一个错误还是我遗漏了什么?

更新 - 解决

这是一个错误,已通知 Unity 开发人员。

“着色器工作 < iOS 15”并不意味着着色器本身总是正确的。

一些简单的着色器变量类型,如 float、half 和 fixed 可以在不同的设备上给你完全不同的结果 OS。

“一半”和“固定”变量可获得更好的性能,而“浮动”变量可减少错误。

由于不同的 CPU/GPU 规范以及您的图形 API 选项,它主要发生在移动设备上。

另一个关键字是“颜色 Space”,请在您的 Unity Build Player 设置中检查线性和伽马选项。

损坏的着色器将 return 粉红色。如果它不是粉红色,那一定是你的着色器中的一些数学问题导致了错误的结果。 着色器代码非常直接。如果渲染结果在一段时间后发生变化,似乎某些变量在运行时也发生了变化。很明显,您使用的插件还包含大量 C# 和 Shader 之间的数学计算。

你可以这样想象: 当 C# 代码试图从着色器获取变量时,但着色器 return 是您在 C# 中计算的错误变量。然后,C#再次将错误的计算结果赋值给Shader。 这将导致错误结果无限循环。

Unity UI 效果(带着色器)不可靠: 有时,它们只是没有更新......你必须通过脚本强制它们更新。以下命令有时可能会有所帮助,但并非总是如此...

Canvas.ForceUpdateCanvases();
ScrollRect.GraphicUpdateComplete();

因此,您应该联系维护此插件的开发人员。因为他们最了解他们的插件是如何工作的

否则,您应该开始编写自己的着色器脚本。 灰度着色器非常容易编写..

编辑 2021-12-07:

从你的着色器中,我看不出灰度和 alpha 通道之间有任何关系。

 c.rgb = lerp(c.rgb, dot(c.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);

我认为这是实现您所需的正确方法。

fixed3 greyColor = dot(c.rgb, float3(0.3, 0.59, 0.11));
c.rgb = lerp(c.rgb, greyColor, _EffectAmount);
c.a = greyColor.a;

同时,删除“Fallback...”行应该有助于调试。因为有时回退着色器会覆盖您当前的着色器脚本。

Fallback "Standard"//remove it<---

你原来的代码中还有一个不匹配的变量类型,应该是float2而不是half2。

struct v2f
{
    float4 vertex : SV_POSITION;
    float2 texcoord : TEXCOORD0;
};

我遇到过类似的事情,与编辑器或打开暗模式的 IOS 构建相比,关闭暗模式的 IOS 构建中的材质(可能还有阴影...)看起来不同.

here 开始,直到这个错误被解决之前,一个肮脏的黑客是将这个密钥添加到 info.plist:

UIUserInterfaceStyle = Dark

info.plist

这基本上强制应用程序使用深色模式。它对

同样有效
UIUserInterfaceStyle = Light