rainyeve
  • 首页
  • 编程
  • 涂鸦
  • 其他
  • 关于
2020年2月7日
编程

【Unity Shader】裂缝效果

【Unity Shader】裂缝效果
2020年2月7日
编程

用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"
        ...
}

Post Views: 4,850

modeling shader unity3d

上一篇【Unity SRP】模糊的菜单背景下一篇 【Unity网格编程】切开网格

发表评论 取消回复

邮箱地址不会被公开。 必填项已用*标注

分类目录

  • 其他 (2)
  • 旅行 (1)
  • 涂鸦 (6)
  • 编程 (28)
Email: wuch441692@163.com