用depth mask给裂缝模型做着色,包裹住小兵使其可以整体或局部不可见。裂缝开启后加上一些粒子效果,做出小兵从裂缝中走出来的登场方式。
实现思路
用MAYA做了个盒子模型,挖一个浅槽,浅槽左右两边弄得曲折以模拟裂缝。分3个材质来着色:盒子外壳,浅槽里面的平面,浅槽侧壁。
盒子前后加了两处“骨骼”。前面骨骼控制裂缝的顶点,使得可以用动画控制裂缝的开合程度;后面骨骼控制盒子背部平面,使得可以延伸盒子的遮盖范围。
做一个通用的可配置的unlit shader取名做UnlitCustom,盒子的三个材质都使用UnlitCustom,但分别给它们设置不同的参数。
Shader "MyAct/UnlitCustom"{ Properties{ _Color ("Tint", Color) = (0, 0, 0, 1) [Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 2 //"Back" [Enum(Off,0,On,1)] _ZWrite("ZWrite", Float) = 0 //"Off" [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4 //"LessEqual" [Enum(None, 0, Alpha, 1, Blue, 2, Green, 4, Red, 8, All, 15)]_ColorWriteMask("ColorWriteMask", Float) = 15 //"All" [Header(Stencil State)] [IntRange] _StencilRef ("Stencil Reference Value", Range(0,255)) = 0 [Enum(UnityEngine.Rendering.CompareFunction)] _StencilTest("StencilTest", Float) = 0 //"Disabled" [Enum(UnityEngine.Rendering.StencilOp)] _StencilOp("StencilOp", Float) = 0 //"Keep" [Header(Blend State)] [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("SrcBlend", Float) = 1 //"One" [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("DestBlend", Float) = 0 //"Zero" } SubShader{ Tags{ "RenderType"="Opaque" "Queue"="Geometry"} Stencil{ Ref [_StencilRef] Comp [_StencilTest] Pass [_StencilOp] } Pass{ Cull[_Cull] Blend[_SrcBlend][_DstBlend] ZWrite [_ZWrite] ZTest [_ZTest] ColorMask [_ColorWriteMask] CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag struct appdata{ float4 vertex : POSITION; }; struct v2f{ float4 position : SV_POSITION; }; fixed4 _Color; v2f vert(appdata v){ v2f o; //calculate the position in clip space to render the object o.position = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag(v2f i) : SV_TARGET{ return _Color; } ENDCG } } }
盒子外壳材质
- ZWrite开启,稍后作为DepthMask使用
- ColorWriteMask设为None,不渲染任何颜色
- ZTest维持默认,当作一般的场景物品来处理深度
- RenderQueue取值AlphaTest+1,确保被盒子挡住的场景能正常渲染
浅槽平面和浅槽侧壁材质
- 浅槽平面的材质关闭ZWrite,使得即使是“浅”槽,也无法遮挡盒子里面的物体
- RenderQueue要比外壳大,取值2452,使得可以读取到外壳形成的DepthMask,AlphaTest不通过的点直接被丢掉,起到裁剪作用
- “裂缝”中的物体RenderQueue要比浅槽更大,取值2453,使其可以“完全”覆盖在浅槽平面上,而因为DepthMask的关系,盒子里面的部分会被AlphaTest裁掉
RenderQueue的取值起关键作用,为了突出“裂缝”效果,裂缝中的物体的渲染顺序要放在最后,一来是保证读到DepthMask,二来保证覆盖掉“浅”槽的平面
TRICK
增强透视感
盒子内部的地面上外加一个平面用来凸显透视,用回之前的Fire2DShader
Color Mask Enum
为了方便在Inspector中选取ColorMask,于是在shader的Properties结构体中给ColorMask预定义Enum。在UnityEngineApi中有ColorWriteMask的Enum可用,但是这个Enum却不包含None,于是手动写一个包含None值的Enum,用十进制来表示二进制的Mask值。
Properties{ ... [Enum(None, 0, Alpha, 1, Blue, 2, Green, 4, Red, 8, All, 15)]_ColorWriteMask("ColorWriteMask", Float) = 15 //"All" ... }