根据 iOS 15 上的黑暗模式,Unity 着色器出现故障
Unity shader glitches according to the Dark Mode on iOS 15
我正在使用着色器(下面的代码),它允许我将图像颜色转换为灰度(如果需要,可以使用透明度)。
一切都很完美,直到我将我的设备更新为 iOS15。自从更新后,我的着色器在渲染场景后立即出现故障。
经过很多天寻找解决方案后,我注意到这与 iPhone 黑暗模式有关。
我在这里提供了一些“概念”示例,以便向您展示当前发生的情况:
灰度着色器应用于红色立方体。
- 立方体 A 在激活暗模式的 iPhone 上运行(这是我在 Unity 中得到的结果,正确的结果)。
- 立方体 B 表示禁用深色模式的同一对象。
问题是我一直在为我的应用程序中的很多项目使用这些着色器,根据用户的暗模式首选项,这给了我一个不一致和丑陋的 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
我正在使用着色器(下面的代码),它允许我将图像颜色转换为灰度(如果需要,可以使用透明度)。
一切都很完美,直到我将我的设备更新为 iOS15。自从更新后,我的着色器在渲染场景后立即出现故障。 经过很多天寻找解决方案后,我注意到这与 iPhone 黑暗模式有关。
我在这里提供了一些“概念”示例,以便向您展示当前发生的情况:
灰度着色器应用于红色立方体。
- 立方体 A 在激活暗模式的 iPhone 上运行(这是我在 Unity 中得到的结果,正确的结果)。
- 立方体 B 表示禁用深色模式的同一对象。
问题是我一直在为我的应用程序中的很多项目使用这些着色器,根据用户的暗模式首选项,这给了我一个不一致和丑陋的 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