unity3d shader控制渲染顺序,Queue,ZWrite,ZTest

Queue渲染队列:

按照渲染顺序,从先到后进行排序,队列数越小的,越先渲染,队列数越大的,越后渲染。

Background(1000) 最早被渲染的物体的队列。
Geometry (2000) 不透明物体的渲染队列。大多数物体都应该使用该队列进行渲染,也是Unity Shader中默认的渲染队列。
AlphaTest (2450) 有透明通道,需要进行Alpha Test的物体的队列,比在Geomerty中更有效。
Transparent(3000) 半透物体的渲染队列。一般是不写深度的物体,Alpha Blend等的在该队列渲染。
Overlay (4000) 最后被渲染的物体的队列,一般是覆盖效果,比如镜头光晕,屏幕贴片之类的。

ZTest深度测试:

就是针对当前对象在屏幕上(更准确的说是frame buffer)对应的像素点,将对象自身的深度值与当前该像素点缓存的深度值进行比较,如果通过了,本对象在该像素点才会将颜色写入颜色缓冲区,否则否则不会写入颜色缓冲。ZTest提供的状态较多。ZTest Less(深度小于当前缓存则通过, ZTest Greater(深度大于当前缓存则通过),ZTest LEqual(深度小于等于当前缓存则通过),ZTest GEqual(深度大于等于当前缓存则通过),ZTest Equal(深度等于当前缓存则通过),ZTest NotEqual(深度不等于当前缓存则通过),ZTest Always(不论如何都通过)。注意,ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。

ZWrite深度写入

ZWrite On(开启深度写入)和ZWrite Off(关闭深度写入)。当我们开启深度写入的时候,物体被渲染时针对物体在屏幕(更准确地说是frame buffer)上每个像素的深度都写入到深度缓冲区;反之,如果是ZWrite Off,那么物体的深度就不会写入深度缓冲区。但是,物体是否会写入深度,除了ZWrite这个状态之外,更重要的是需要深度测试通过,也就是ZTest通过,如果ZTest都没通过,那么也就不会写入深度了。就好比默认的渲染状态是ZWrite On和ZTest LEqual,如果当前深度测试失败,说明这个像素对应的位置,已经有一个更靠前的东西占坑了,即使写入了,也没有原来的更靠前,那么也就没有必要再去写入深度了。

系统中存在一个颜色缓冲区和一个深度缓冲区,分别存储颜色值和深度值,来决定画面上应该显示什么颜色。
深度值是物体在世界空间中距离摄像机的远近。距离越近,深度值越小;距离越远,深度值越大。

如果我们硬要远处的红块遮挡住近处的蓝块,很显然,我们应该改变或关闭深度测试,或者关闭深度写入(关闭了深度测试或者深度写入之后,物体颜色的遮挡关系就会和渲染队列一致,即排在后面的会挡住前面的)。

现在处理世界ui与模型之间的渲染顺序

世界ui显示在模型之前

如图所示
unity3d shader控制渲染顺序,Queue,ZWrite,ZTest_第1张图片
模型中间插入一个世界ui
最后游戏画面只显示了ui部分,模型的一半并没有挡住世界ui
unity3d shader控制渲染顺序,Queue,ZWrite,ZTest_第2张图片

使用如下shader

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "CustomUI/FirstImg"
{
    Properties
    {
        [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
    _Color("Tint", Color) = (1,1,1,1)

        //MASK SUPPORT ADD
        _StencilComp("Stencil Comparison", Float) = 8
        _Stencil("Stencil ID", Float) = 0
        _StencilOp("Stencil Operation", Float) = 0
        _StencilWriteMask("Stencil Write Mask", Float) = 255
        _StencilReadMask("Stencil Read Mask", Float) = 255
        _ColorMask("Color Mask", Float) = 15
        //MASK SUPPORT END
    }

        SubShader
    {
        Tags
    {
        "Queue" = "Overlay"
        "IgnoreProjector" = "True"
        "RenderType" = "Transparent"
        "PreviewType" = "Plane"
        "CanUseSpriteAtlas" = "True"
    }

        //MASK SUPPORT ADD
        Stencil
    {
        Ref[_Stencil]
        Comp[_StencilComp]
        Pass[_StencilOp]
        ReadMask[_StencilReadMask]
        WriteMask[_StencilWriteMask]
    }
        ColorMask[_ColorMask]
        //MASK SUPPORT END

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest Always
        Fog{ Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha
        //ColorMask[_ColorMask]

        Pass
    {
        CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

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

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

    fixed4 _Color;

    v2f vert(appdata_t IN)
    {
        v2f OUT;
        OUT.vertex = UnityObjectToClipPos(IN.vertex);
        OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
        OUT.vertex.xy += (_ScreenParams.zw - 1.0)*float2(-1,1);
#endif
        OUT.color = IN.color * _Color;
        return OUT;
    }

    sampler2D _MainTex;

    fixed4 frag(v2f IN) : SV_Target
    {
        half4 color = tex2D(_MainTex, IN.texcoord) * IN.color;
        return color;
    }
        ENDCG
    }
    }
}

模型显示在世界ui之前

如图所示
unity3d shader控制渲染顺序,Queue,ZWrite,ZTest_第3张图片
模型在世界ui的后面
最终游戏场景
unity3d shader控制渲染顺序,Queue,ZWrite,ZTest_第4张图片
世界ui类似天空盒一样显示在最后,即最先被渲染

使用shader

Shader "CustomUI/BgImg"
{
    Properties
    {
        [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
        _Color("Tint", Color) = (1,1,1,1)
        //MASK SUPPORT ADD
        _StencilComp("Stencil Comparison", Float) = 8
        _Stencil("Stencil ID", Float) = 0
        _StencilOp("Stencil Operation", Float) = 0
        _StencilWriteMask("Stencil Write Mask", Float) = 255
        _StencilReadMask("Stencil Read Mask", Float) = 255
        _ColorMask("Color Mask", Float) = 15
        //MASK SUPPORT END
    }

        SubShader
    {
        Tags
    {
        "Queue" = "Background"
        "IgnoreProjector" = "True"
        "RenderType" = "Transparent"
        "PreviewType" = "Plane"
        "CanUseSpriteAtlas" = "True"
    }
        //MASK SUPPORT ADD
        Stencil
    {
        Ref[_Stencil]
        Comp[_StencilComp]
        Pass[_StencilOp]
        ReadMask[_StencilReadMask]
        WriteMask[_StencilWriteMask]
    }
        ColorMask[_ColorMask]
        //MASK SUPPORT END

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest[unity_GUIZTestMode]
        Fog{ Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha
        //ColorMask[_ColorMask]

        Pass
    {
        CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

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

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

    fixed4 _Color;

    v2f vert(appdata_t IN)
    {
        v2f OUT;
        OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
        OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
        OUT.vertex.xy += (_ScreenParams.zw - 1.0)*float2(-1,1);
#endif
        OUT.color = IN.color * _Color;
        return OUT;
    }

    sampler2D _MainTex;

    fixed4 frag(v2f IN) : SV_Target
    {
                        half4 color = tex2D(_MainTex, IN.texcoord) * IN.color;
                        return color;
    }
        ENDCG
    }
    }
}

你可能感兴趣的:(Unity3D实用技术笔记,Unity3d,Shader,Unity3d,Shader)