模板测试的细节

1、简介

 

在Unity中一个像素会有多个缓存信息,模版缓存(其实Stencil不应该被翻译成模版,但网上都这么写)是其中之一。模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值,通过一些比较来改变当前像素区域模版缓冲的值,从而改变深度关系,似乎UGUI的Mask也是通过其实现的,延迟光照中Stencil有一些限制,具体看unity的文档,这里只介绍正向光照中的使用。

 

Stencil所在的渲染管线中的顺序位置:

模板测试的细节_第1张图片

 

Stencil的所有参数如下:

Stencil
{
    Ref 1//Reference Value ReadMask 255 WriteMask 255 Comp Always //Comparison Function  Pass Replace
    Fail Keep
    ZFail Replace
}

 

Ref 就是参考值,当参数允许赋值时,会把参考值赋给当前像素

 

ReadMask 对当前参考值和已有值进行mask操作,默认值255,一般不用

 

WriteMask 写入Mask操作,默认值255,一般不用

 

Comp 比较方法。是拿Ref参考值和当前像素缓存上的值进行比较。默认值always

  • Greater - 大于
  • GEqual - 大于等于
  • Less - 小于
  • LEqual - 小于等于
  • Equal - 等于
  • NotEqual - 不等于
  • Always - 永远通过
  • Never - 永远通不过

 

Pass 当模版测试和深度测试都通过时,进行处理

 

Fail 当模版测试和深度测试都失败时,进行处理

 

ZFail 当模版测试通过而深度测试失败时,进行处理

 

pass,Fail,ZFail都属于Stencil操作,他们参数统一如下:

  • Keep 保持(即不把参考值赋上去,直接不管)
  • Zero 归零
  • Replace 替换(拿参考值替代原有值)
  • IncrSat 值增加1,但不溢出,如果到255,就不再加
  • DecrSat 值减少1,但不溢出,值到0就不再减
  • Invert 反转所有位,如果1就会变成254
  • IncrWrap 值增加1,会溢出,所以255变成0
  • DecrWrap 值减少1,会溢出,所以0变成255

 

2、实践

 

下面结合案例,说一下Stencil的使用

模板测试的细节_第2张图片

 

现在有一个球和面片,通过Stencil模版测试把stencil值一致的物体渲染为蓝色。

为了更直观使用了两个shader,面片是Panel,球是Sphere。

注意:

球如果是优先渲染的话,会导致深度值无法比较。所以本案例:面片先渲染,并且设置好stencil的值;球后渲染,并且判断stencil的值。

文件结构:

 

Shader "Stencil/Panel"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }
        Stencil
        {
            Ref 1
            Comp Always
            Pass Replace
        }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                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);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(1,1,1,1);
            }
            ENDCG
        }
    }
}
MaskTest2

 

Stencil里,比较条件设置为总通过,通过操作设置为替换Ref值;

这样球部分的像素Stencil值就是1

Stencil
{
    Ref 1
    Comp Always
    Pass Replace
}
Shader "Stencil/Sphere"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+1" }
        Stencil
        {
            Ref 1
            Comp equal
        }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                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);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(0,0,1,1);
            }
            ENDCG
        }
    }
}

 

Stencil里,比较条件是和Ref值一致时,才会执行渲染。

否则跳出

Stencil
{
    Ref 1
    Comp equal
}

 

蓝色是片段shader里写好的

fixed4 frag (v2f i) : SV_Target
{
    return fixed4(0,0,1,1);
}

你可能感兴趣的:(Unity)