ShadersRoom - Stencil Buffer

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

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);
        }

到这里就差不多啦~~~

git仓库:https://github.com/Looooooong/ShadersRoom

最后附上完整的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"
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容