Unity3D Shader Stencil模版测试学习

官方文档地址:

https://docs.unity3d.com/Manual/SL-Stencil.html

 

参考博客:

http://blog.csdn.net/onafioo/article/details/53943264

http://blog.csdn.net/u013833399/article/details/47340447

(因表述的内容都大致一样,一些内容直接引用自原作者)

 

 

1.简介

在Unity中一个像素会有多个缓存信息,模版缓存(其实Stencil不应该被翻译成模版,但网上都这么写)是其中之一。

模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值,

通过一些比较来改变当前像素区域模版缓冲的值,从而改变深度关系,似乎UGUI的Mask也是通过其实现的

 

 

延迟光照中Stencil有一些限制,具体看unity的文档,这里只介绍正向光照中的使用

 

 

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

 

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的使用

 

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

为了更直观使用了两个shader,面片是shader1,球是shader2

球肯定是优先渲染,并且设置好stencil的值,面片后渲染,并且判断stencil的值

 

文件结构:

 

MaskTest2是球的shader

Shader "Unlit/MaskTest2"
{
    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
}

 

 

MaskTest1是面片的Shader

Shader "Unlit/MaskTest1"
{
    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
        }
    }
}
View Code

 

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

否则跳出

Stencil
{
    Ref 1
    Comp equal
}

 

蓝色是片段shader里写好的

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

 

 

这样就可以达到上述效果。

 


 测试工程文件下载:https://files.cnblogs.com/files/hont/StencilMaskTest.zip

posted @ 2017-03-19 11:57  HONT  阅读(7384)  评论(0编辑  收藏  举报