美文网首页Shader
ShadersRoom - Stencil Buffer

ShadersRoom - Stencil Buffer

作者: 雨天到处晃 | 来源:发表于2019-11-20 12:09 被阅读0次

    老规矩,先上一张效果图:

    Stencil.gif

    这个功能效果的核心点是模板缓存Stencil buffer,和深度缓存类似,模板缓存可以为屏幕上的每个像素点保存一个无符号整数值(通常的话是个8位整数,范围0-255),通过比较这个数值可以控制是否需要更新当前像素的颜色缓存,这个过程叫做模板测试,默认情况下,总是测试通过的,可以通过以下参数来控制这个过程:

    • Ref 自定义数值,用来和模板缓冲中的值进行比较,范围0-255,默认值是0
    • ReadMask 对当前参考值和已有值进行mask操作,默认值255;
    • WriteMask 写入Mask操作,默认值255;
    • Comp 比较方法,Ref定义的值和当前像素缓存上的值进行比较,有以下参数,默认值always:
        Greater - 大于
        GEqual - 大于等于
        Less - 小于
        LEqual - 小于等于
        Equal - 等于
        NotEqual - 不等于
        Always - 永远通过
        Never - 永远通不过
    • Pass 模版测试和深度测试都通过时,进行的操作
    • Fail 模版测试和深度测试都失败时,进行的操作
    • ZFail 模版测试通过而深度测试失败时,进行的操作
        Pass,Fail,ZFail 默认值都是Keep,可使用的参数如下:
        Keep 保持(即不做处理)
        Zero 归零
        Replace 替换(参考值替换原有值)
        IncrSat 增加1,最大到255
        DecrSat 减少1,最小到0
        Invert 反转所有位
        IncrWrap 值增加1,大于255时,变成0.
        DecrWrap 值减少1,小于0时,变成255

    好了,有了上述的介绍,再回到场景中,场景分为3个部分,蓝色的区域,黑色的区域和连接两个区域的门,
    首先是门,负责显示玩家可以进入的场景,所以门主要的功能就是:把屏幕上对应位置的Ref值刷新为进入的场景的Ref值,本身不需要显示任何颜色;
    然后是两个场景,分别有不同的Ref值(黑色场景的Ref为1,蓝色场景的Ref为2)。

    下面开始具体的实现,以玩家处于蓝色场景,将要进入黑色场景为例,首先新建3个Surface Shader分别对应蓝色场景,黑色场景,门:

    • 蓝色场景是需要显示出来的,所以场景中的模板测试是需要通过的,即Comp Alawys,这样场景就可以显示出来;
    //在SubShader中添加
            stencil
            {
                ref 2
                comp Always
            }
    

    ·

    • 黑色场景只需要在门中看到,其他的地方是不需要显示的,它的比较方式就是 Comp Equal.
    //在SubShader中添加
            stencil
            {
                ref 1
                comp Equal
            }
    

    ·

    • 门需要刷新的Ref值就是黑色场景的Ref值.
    //在SubShader中添加
            Zwrite off   //关闭写入深度,防止在深度测试中将门后的场景覆盖
            Cull off     //开启双面显示
            Colormask 0  //屏蔽颜色的输出
            stencil
            {
                Ref 1
                Comp Alawys
                Pass replace  //测试通过则将stencilBufferValue刷新为1
            }
    

    到这一步,就实现了一个静态的效果:从蓝色场景看到门中的黑色场景。

    1.png

    接下来是动态的实现,穿越了门后,黑色场景全部显示,而蓝色场景则可以从门中看到:

    • 门shader的属性Properties中新增2个属性,方便在c#脚本中动态的赋值:
            //新增属性
            _RefValue("Ref",range(0,255)) = 0
            [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comp",float) = 3
    
            //修改stencil
            stencil
            {
                ref [_RefValue]    //替换成修改后的属性
                comp [_StencilComp]   //替换成修改后的属性
                pass replace
            }
    
    • 场景shader的属性Properties新增一个属性
             //新增属性
            [Enum(UnityEngine.Rendering.CompareFunction)]_RefValue("Ref Valus",int) = 3
    
            stencil
            {
                ref 2
                comp [_RefValue]    //替换成新增属性
            }
    
    
    • 在c#脚本中动态的控制这些属性,关键代码如下:
    if(cameraPostionInPortalSpace.z < -0.3) //表示在scene2这边
            {
                scene2Mat.SetInt("_RefValue", (int)CompareFunction.Always);
                scene1Mat.SetInt("_RefValue", (int)CompareFunction.Equal);
                portalMat.SetInt("_RefValue", 1);
            }
            else if (cameraPostionInPortalSpace.z >0.3) //表示在scene1这边
            {
                scene2Mat.SetInt("_RefValue", (int)CompareFunction.Equal);
                scene1Mat.SetInt("_RefValue", (int)CompareFunction.Always);
                portalMat.SetInt("_RefValue", 2);
            }
            else    //这里表示在门口附近,两边场景都需要显示
            {
                scene2Mat.SetInt("_RefValue", (int)CompareFunction.Always);
                scene1Mat.SetInt("_RefValue", (int)CompareFunction.Always);
            }
    

    最后附上完整的shader:
    ·

    Shader "ShadersRoom/StencilPortal" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
    
            _RefValue("Ref",range(0,255)) = 0
            [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comp",float) = 3
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
            zwrite off
            cull off
            colormask 0
    
    
            stencil
            {
                ref [_RefValue]
                comp [_StencilComp]
                pass replace
            }
    
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Standard fullforwardshadows
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
            sampler2D _MainTex;
    
            struct Input {
                float2 uv_MainTex;
            };
    
            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
    
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // Albedo comes from a texture tinted by color
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                // Metallic and smoothness come from slider variables
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    
    Shader "ShadersRoom/Scene1" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
            [Enum(UnityEngine.Rendering.CompareFunction)]_RefValue("Ref Valus",int) = 1
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
    
            stencil
            {
                ref 1
                comp [_RefValue]
            }
    
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Standard fullforwardshadows
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
            sampler2D _MainTex;
    
            struct Input {
                float2 uv_MainTex;
            };
    
            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
    
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // Albedo comes from a texture tinted by color
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                // Metallic and smoothness come from slider variables
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    
    Shader "ShadersRoom/Scene2" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
            [Enum(UnityEngine.Rendering.CompareFunction)]_RefValue("Ref Valus",int) = 3
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
    
            stencil
            {
                ref 2
                comp [_RefValue]
            }
    
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Standard fullforwardshadows
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
            sampler2D _MainTex;
    
            struct Input {
                float2 uv_MainTex;
            };
    
            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
    
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // Albedo comes from a texture tinted by color
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                // Metallic and smoothness come from slider variables
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    

    相关文章

      网友评论

        本文标题:ShadersRoom - Stencil Buffer

        本文链接:https://www.haomeiwen.com/subject/upinqqtx.html