unity ShaderLab 基础之【模板测试 StencilTest】StencilTest命令详解

模板测试 StencilTest

【说明】:模板测试,用于处理重合的像素该如何显示。与深度和透明测试不同的是,模板测试可以更自由跟独立的自定义显示。
【原理】:屏幕的每个像素都有一个stencil值,在同一个像素上,所有shader的stencil都共享这一个值,当有其他带有stencil值的像素与其重合时就能获取到该值,并根据自身的stencil值处理或。
【举例1】:典型的应用就是遮罩显示。你可以选择每次重合都增加1,然后再指定某个物体,当值达到某个数量级再显示。
【举例2】:比如,有个隐身的怪物,你只有使用圣水喷雾才能让他现行,但必须喷3次才行,这样,空中就存在了3次叠加的雾,透过这个3层雾就能看到怪物了。但你偏一下角度,透过两层雾就看不到。
【举例3】:红警、魔兽争霸、星际争霸中的迷雾系统。

模板测试与透明测试、深度测试的关系与区别

共同点:这三大测试都是用于决定 是否显示当前像素
不同点:深度测试是用于处理前后遮挡关系,透明测试用于处理透明阈值,而模板测试属于处理像素重合关系。虽然野可以说是遮挡关系,但模板测试并不像深度测试那样着重与前后顺序,模板只关注重叠及自定义触发条件。

Stencil完整语法:

stencil{
	Ref referenceValue //每个像素都有一个stencil值,在同一个像素上,所有shader的stencil都共享这一个值,当有其他带有遮罩像素与其重合时就能获取到该值,并根据自身的stencil值处理触发小狗
	ReadMask  readMask  //读遮罩
	WriteMask writeMask  //写遮罩
	Comp comparisonFunction   //条件判断  大于小于等触发
	Pass stencilOperation    //满足条件后,相应的处理办法   是替换值还是增长值等
	Fail stencilOperation    //没有通过模板测试怎么办
	ZFail stencilOperation    //通过了模板测试怎么办
}

模板语法

参数说明实例
Refref用来设定参考值(范围0-255)。这个值用来与stencilbuffer比较
ReadMaskReadMask 从字面意思的理解就是读遮罩,readMask将和referenceValue以及stencilBufferValue进行按位与(&)操作,readMask取值范围也是0-255的整数,默认值为255,二进制位11111111,即读取的时候不对referenceValue和stencilBufferValue产生效果,读取的还是原始值
WriteMaskWriteMask是当写入模板缓冲时进行掩码操作(按位与【&】),writeMask取值范围是0-255的整数,默认值也是255,即当修改stencilBufferValue值时,写入的仍然是原始值。
CompComp是定义参考值(referenceValue)与缓冲值(stencilBufferValue)比较的操作函数,默认值:always
PassPass是定义当模板测试(和深度测试)通过时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep
FailFail是定义当模板测试(和深度测试)失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep
ZFailZFail是定义当模板测试通过而深度测试失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep
模板对比
指令说明实例
Greater大于,只渲染大于该值的像素。alphatest greater [_alphaValue] //类似于抠图
Less小于,只渲染小于该值的像素。类似于反向抠图
GEqual大于等于
LEqual小于等于
Equal等于
NotEqual不等于
Always总是
Never永不
Off关闭alphatest Off
模板操作
指令说明实例
Keep保留当前缓冲中的内容,即stencilBufferValue不变
Zero将0写入缓冲,即stencilBufferValue值变为0。
Replace将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue。
IncrSatstencilBufferValue加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255。
DecrSatstencilBufferValue减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0。
Invert将当前模板缓冲值(stencilBufferValue)按位取反
IncrWrap当前缓冲的值加1,如果缓冲值超过255了,那么变成0,(然后继续自增)
DecrWrap当前缓冲的值减1,如果缓冲值已经为0,那么变成255,(然后继续自减) 。

实例:遮罩
将此shader付给遮罩物体

Shader "Custom/st1" {
	SubShader{
		Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1"}
			CGINCLUDE
				struct appdata {
					float4 vertex : POSITION;
				};
				struct v2f {
					float4 pos : SV_POSITION;
				};
				v2f vert(appdata v) {
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					return o;
				}
				half4 frag(v2f i) : SV_Target {
					return half4(1,1,0,1);
				}
			ENDCG
			Pass {
				ColorMask 0
				ZWrite Off
				Stencil
				{
					Ref 1
					Comp Always
					Pass Replace
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
				ENDCG
			}
	}
}

将此shader付给被遮罩物体

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "Custom/st2" {
	Properties{
	_MainTex("Base (RGB)", 2D) = "white" {}
	}
		SubShader{
			Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }
			LOD 100
			Pass {
				Stencil
				{
					Ref 2
					Comp Equal
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
					#pragma multi_compile_fog
					#include "UnityCG.cginc"
					struct appdata_t {
						float4 vertex : POSITION;
						float2 texcoord : TEXCOORD0;
					};
					struct v2f {
						float4 vertex : SV_POSITION;
						half2 texcoord : TEXCOORD0;
						UNITY_FOG_COORDS(1)
					};
					sampler2D _MainTex;
					float4 _MainTex_ST;
					v2f vert(appdata_t v)
					{
						v2f o;
						o.vertex = UnityObjectToClipPos(v.vertex);
						o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
						UNITY_TRANSFER_FOG(o,o.vertex);
						return o;
					}
					fixed4 frag(v2f i) : SV_Target
					{
						fixed4 col = tex2D(_MainTex, i.texcoord);
						UNITY_APPLY_FOG(i.fogCoord, col);
						UNITY_OPAQUE_ALPHA(col.a);
						return col;
					}
				ENDCG
			}
	}
}

即可完成

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千年奇葩

从来没受过打赏,这玩意好吃吗?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值