除了透明测试和混合透明外,Unity 还提供了了另一种实现透明效果的方法:模板测试 Stencil Test
, 通过模板测试可以达到逐像素保留或者丢弃像素的目的.
# 所以
就是给物体一个模板值 m, 物体本身有个参照值 n, 可以对模板值进行操作,根据比较方法 (大于,小于。等于等等) 决定该像素是否丢弃
# 语法
1 2 3 4 5 6 7 8 9 10
| Stencil{ Ref referenceValue ReadMask readMask WriteMask writeMask Comp comparisonFunction Pass stencilOperation Fail stencilOperation ZFail stencilOperation }
|
- Ref referenceValue : 用来与缓存中已经存在的模板值进行比较的数值,被称为参照值,当比较符合某些设定条件,这个证书可以被写进缓存,数值的范围是【0~255】
- ReadMask readMask : 是一个范围 0~255 的整数,8 位二进制 11111111, 当读取参照值与模板支可以使用的时候,模板会指定哪些位的数值可以读取,默认为 255,也就是所有位都可以读取。
- WriteMask writeMask : 同样也是 8 位二进制,当往缓存中写入的时候可以使用,模板会指定那些值允许写入,当 WriteMask 为 0 时,表示的是没有数值会被写入缓存,而不是将 0 写入。默认位数为 255,也就是所有位都可以写入
- Comp comparisionFunction : 参照值与模板值比较的方法,默认为 always
- Pass stencilOperation : 如果模板测试和深度测试都通过,缓存中的模板值如何处理,默认为 keep
- Fail stencilOperation : 如果没有通过,缓存中的模板值如何处理,默认为 keep
- ZFail stencilOperation : 如果模板测试通过,但是深度测试没通过,缓存中的数值如何处理,默认为 keep
# 比较方法
- Greater
- GEqual
- Less
- LEqual
- Equal
- NotEqual
- Always
- Never
P128
# 效果
# 代码
墙的 Shader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| Shader "Custom/StencilTestB" { Properties { _MainTex ("Texture", 2D) = "white" {} _MainColor ("Main Color",Color) =(1,1,1,1) } SubShader { Tags { "Queue" = "Geometry" }
Pass { Tags { "LightMode" = "ForwardBase" }
//设置模板测试状态 Stencil{ Ref 1 Comp NotEqual Pass Keep }
CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "UnityLightingCommon.cginc"
struct v2f { float4 pos : SV_POSITION; float4 worldPos : TEXCOORD0; float3 worldNormal : TEXCOORD1; float2 texcoord : TEXCOORD2; };
sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor;
v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld, v.vertex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal); o.worldNormal = normalize(worldNormal); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o; }
fixed4 frag(v2f i) : SV_Target{ float3 worldLight = UnityWorldSpaceLightDir(i.worldPos.xyz); worldLight = normalize(worldLight);
fixed NdotL = saturate(dot(i.worldNormal, worldLight));
fixed4 color = tex2D(_MainTex, i.texcoord); color.rgb *= _MainColor * NdotL * _LightColor0.rgb; color.rgb += unity_AmbientSky.rgb;
return color; } ENDCG } } }
|
遮挡剔除的 Shader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Shader "Custom/StencilTestA" { SubShader { //墙上打洞思路: 球体先渲染, //Geometry-1 => 最先渲染 Tags { "Queue" = "Geometry-1"} Pass{ //设置模板测试的状态 //模板值为1 //始终比较 //把参考值写入缓存之中 Stencil{ Ref 1 Comp Always Pass Replace }
//禁止绘制任何色彩 ColorMask 0 ZWrite Off
CGPROGRAM #pragma vertex vert #pragma fragment frag
float4 vert(in float4 vertex:POSITION) : SV_POSITION { float4 pos = UnityObjectToClipPos(vertex); return pos; }
void frag(out fixed4 color : SV_Target) { color = fixed4(0,0,0,0); } ENDCG } } }
|