渐变着色器 Z 仅在场景视图中战斗

Gradient shader Z fighting in Scene view only

我创建了以下渐变,它采用图像组件源图像并对其应用两种颜色的渐变。使用切换可以将其切换为使用源图像的 alpha 作为渐变 alpha,或设置每种渐变颜色的 alpha。

 Properties
{
    [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
    [Header(Colours)]
    _Color1("Color 1", Color) = (0,0,0,1)
    _Color2("Color 2", Color) = (1,1,1,1)

    [Toggle]_UseImageAlpha("Use Image alpha", float) = 0
    [Header(Cull mode)]
    [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull mode", float) = 2
    [Header(ZTest)]
    [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", float) = 4
    [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 1

}
SubShader
{
    Tags {"Queue" = "Transparent" "RenderType"="Transparent"}
    LOD 100
    Blend SrcAlpha OneMinusSrcAlpha
    ZTest [_ZTest]
    Cull [_CullMode]
    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
        #include "UnityCG.cginc"
        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
            fixed4 col : COLOR;
        };
        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
            fixed4 col : COLOR;
        };
        sampler2D _MainTex;
        float4 _MainTex_ST;
        fixed4 _Color1;
        fixed4 _Color2;
        bool _UseImageAlpha;
        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);
            o.col = v.col;
            return o;
        }
        fixed4 frag (v2f i) : SV_Target
        {
            if (_UseImageAlpha) {
                _Color1.a = i.col.a;
                _Color2.a = i.col.a;
            }

            fixed4 col = tex2D(_MainTex, i.uv);
            col *= lerp(_Color1, _Color2, i.uv.y);
            col.a = clamp(col.a, 0, 1);

#ifdef UNITY_UI_ALPHACLIP
            clip(col.a - .001);
#endif

            return col;
        }
        ENDCG
    }
}

此着色器工作正常并按预期显示渐变,但是一旦我开始添加多层图像(例如,它后面有一个蓝色方块,前面有一个绿色方块),它就开始出现 Z fighting 问题仅在场景视图中 基于场景相机与层次结构中下一个对象(在本例中为绿色方块)的角度。在游戏视图和构建中,不会发生 Z 战斗。

我正在使用默认的 LessEqual ZTest 选项,将反向剔除和渲染队列设置为 3000(这与其前后图像的渲染队列相同)。根据 Unity's documentation 将其设置为 LessEqual 应该可以使前面的对象绘制在顶部,后面的对象隐藏:

How should depth testing be performed. Default is LEqual (draw objects in from or at the distance as existing objects; hide objects behind them).

将 ZTest 设置为任何其他选项(关闭、始终、greaterEqual 等)不会产生更好的结果。

如果我将渲染队列设置得更高 (3001),它将始终在场景视图中绘制渐变(在游戏视图中没有变化),而将其设置为 2999 仍会使其与它的前面(绿色方块),同时使它后面的蓝色方块透明。

当我在渐变前面只有绿色方块时,它会在某些地方打架,而在源图像没有任何像素的其他地方切掉绿色方块。

使用源图像的 alpha 或使用两种单独颜色的 alpha 也没有区别。

(gyazo) Example gif 战斗的变化取决于摄像机角度。

是什么导致了这种 z 冲突,为什么它只发生在场景视图中?

使用 Unity 2019.3.13f1,在 Windows 上的 2019.2、2019.1m 2018.4 LTS、2017 LTS 中结果相同。

尝试添加 ZWrite Off。对于着色器,开始(或至少查看)Unity's built-in shaders that is close to what you want.
In your case that would be UI-Default.shader.

之一可能会很有用