【Unity3d Shader】模板缓冲区(Stencil buffer)

模版缓冲区(stencil buffer),是在OpenGL三维绘图等计算机图像硬件中常见的除颜色缓冲区(color buffer或frame buffer)、深度缓冲区(depth buffer 或 z buffer )、累积缓冲区(accumulation buffer)之外另一种数据缓冲。

模版缓冲区通常是每像素 8 位。该值可以写入、递增或递减。后续绘制调用可以根据该值进行测试,以确定在运行像素着色器之前是否应丢弃像素。用于遮罩ugui中的遮罩就是通过模板缓冲区实现的。

模板测试在渲染管线中的位置:裁减测试---->透明度测试---->模板测试---->深度测试

比较方法

  //
    // 摘要:
    //     Depth or stencil comparison function.
    public enum CompareFunction
    {
        //
        // 摘要:
        //     Depth or stencil test is disabled.
        Disabled = 0,
        //
        // 摘要:
        //     Never pass depth or stencil test.
        Never = 1,
        //
        // 摘要:
        //     Pass depth or stencil test when new value is less than old one.
        Less = 2,
        //
        // 摘要:
        //     Pass depth or stencil test when values are equal.
        Equal = 3,
        //
        // 摘要:
        //     Pass depth or stencil test when new value is less or equal than old one.
        LessEqual = 4,
        //
        // 摘要:
        //     Pass depth or stencil test when new value is greater than old one.
        Greater = 5,
        //
        // 摘要:
        //     Pass depth or stencil test when values are different.
        NotEqual = 6,
        //
        // 摘要:
        //     Pass depth or stencil test when new value is greater or equal than old one.
        GreaterEqual = 7,
        //
        // 摘要:
        //     Always pass depth or stencil test.
        Always = 8
    }

模版像素操作

//
    // 摘要:
    //     Specifies the operation that's performed on the stencil buffer when rendering.
    public enum StencilOp
    {
        //
        // 摘要:
        //     Keeps the current stencil value.
        Keep = 0,
        //
        // 摘要:
        //     Sets the stencil buffer value to zero.
        Zero = 1,
        //
        // 摘要:
        //     Replace the stencil buffer value with reference value (specified in the shader).
        Replace = 2,
        //
        // 摘要:
        //     Increments the current stencil buffer value. Clamps to the maximum representable
        //     unsigned value.
        IncrementSaturate = 3,
        //
        // 摘要:
        //     Decrements the current stencil buffer value. Clamps to 0.
        DecrementSaturate = 4,
        //
        // 摘要:
        //     Bitwise inverts the current stencil buffer value.
        Invert = 5,
        //
        // 摘要:
        //     Increments the current stencil buffer value. Wraps stencil buffer value to zero
        //     when incrementing the maximum representable unsigned value.
        IncrementWrap = 6,
        //
        // 摘要:
        //     Decrements the current stencil buffer value. Wraps stencil buffer value to the
        //     maximum representable unsigned value when decrementing a stencil buffer value
        //     of zero.
        DecrementWrap = 7
    }

下面做一个Demo

1.以unlit shader为模板创建两个shader:SimpleMask.shader和SimpleObject.shader,创建两个材质SimpleMask.mat和SimpleObject.mat,并将shader拖到对应的材质上。SimpleMask.mat给一张红色贴图,SimpleObject.mat给一张蓝色贴图以区别显示

2.场景上创建两个cube:SimpleMask和SimpleObject,并引用对应的材质,调整位置(两个cube会交叉)

3.我们修改 SimpleMask.shader和SimpleObject.shader以使SimpleMask Cube遮罩SimpleObject Cube

SimpleMask.shader中加入以下代码:

Stencil
	   {
			Ref 1//参考值为1
			Comp Always//参考值与缓冲区的当前内容进行比较的函数  Always为始终比较
			Pass replace//如果模板测试(和深度测试)通过,如何处理缓冲区的内容  替换模板缓冲区中的数据为1
		}

SimpleObject.shader中加入以下代码:

Stencil
		{
			Ref 1//参考值为1
			Comp equal//和模板缓冲区中的数据是否相等
			Pass keep// 测试通过后不改变模板缓冲区中的内容,我不是模板,只负责被遮罩
		}

我们去场景中调整SimpleObject Cube发现效果如下(被红色遮罩的区域才会显示)

由于红色物体是遮罩物体,我们把它(红色物体)范围调大localscale改为2,并隐藏掉:

SimpleMask.shader中加入以下代码:

ColorMask 0
ZWrite off
ZTest off

再去场景中调整SimpleObject Cube发现效果如下(遮罩效果完成)

SimpleMask.shader

Shader "Unlit/SimpleMask"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

		ColorMask 0
		ZWrite off
		ZTest off

		Stencil
		{
			Ref 1//参考值为1
			Comp Always//参考值与缓冲区的当前内容进行比较的函数  Always为始终比较
			Pass replace//如果模板测试(和深度测试)通过,如何处理缓冲区的内容  替换模板缓冲区中的数据为1
		}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

SimpleObject.shader

Shader "Unlit/SimpleObject"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

		Stencil
		{
			Ref 1//参考值为1
			Comp equal//和模板缓冲区中的数据是否相等
			Pass keep// 测试通过后不改变模板缓冲区中的内容,我不是模板,只负责被遮罩
		}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

猜你喜欢

转载自blog.csdn.net/PangNanGua/article/details/106118482
今日推荐