Маска для спрайта [2D]

При разработки двухмерной игрушки, порой может возникнуть необходимость обрезки спрайта по форме некой маски. Например, если игра с изометрическим видом и нужно показать, как допустим зомби выползает из ямы, в этой ситуации, использование маски будет очень удобным решением. Для реализации мы воспользуемся шейдерами, один для маски, а второй для спрайта, который должен взаимодействовать с маской. То бишь, у нас будет выбор, если на спрайте использовать стандартный шейдер, то это будет обычный спрайт, что крайне удобно. Представленные ниже шейдеры были найдены на просторах интернета, поэтому давайте разберемся, как их задействовать в игре.


Для начала создадим шейдеры.

Первый, для спрайта маски:

Shader "Custom/Sprites/Mask"
    {
        Properties
        {
            [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
            _Color("Tint", Color) = (1,1,1,1)
            [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
            [MaterialToggle] ShowTexture("Show Texture", Float) = 0
        }
     
            SubShader
            {
            Tags
            {
                "Queue" = "Transparent"
                "IgnoreProjector" = "True"
                "RenderType" = "Transparent"
                "PreviewType" = "Plane"
                "CanUseSpriteAtlas" = "True"
            }
     
            Cull Off
            Lighting Off
            ZWrite Off
            Blend One OneMinusSrcAlpha
     
            Pass
            {
                Stencil
                {
                    Ref 1
                    Comp always
                    Pass replace
                }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile _ PIXELSNAP_ON
                #pragma multi_compile _ SHOWTEXTURE_ON
                #include "UnityCG.cginc"
     
                struct appdata_t
                {
                    float4 vertex   : POSITION;
                    float4 color    : COLOR;
                    float2 texcoord : TEXCOORD0;
                };
     
                struct v2f
                {
                    float4 vertex   : SV_POSITION;
                    fixed4 color : COLOR;
                    half2 texcoord  : TEXCOORD0;
                };
     
                fixed4 _Color;
     
                v2f vert(appdata_t IN)
                {
                    v2f OUT;
                    OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                    OUT.texcoord = IN.texcoord;
                    #ifdef SHOWTEXTURE_ON
                    OUT.color = IN.color * _Color;
                    #else
                    OUT.color = IN.color * _Color;
                    OUT.color.rgb = 0;
                    #endif
                    #ifdef PIXELSNAP_ON
                    OUT.vertex = UnityPixelSnap(OUT.vertex);
                    #endif
     
                    return OUT;
                }
     
                sampler2D _MainTex;
     
                fixed4 frag(v2f IN) : SV_Target
                {
                    fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
                    if (c.a < 0.2) discard;
                    c.rgb *= c.a;
                    c.a = 0;
                    return c;
                }
            ENDCG
            }
        }
}

Далее, второй шейдер для взаимодействия с первым:

Shader "Custom/Sprites/Draw In Mask"
    {
        Properties
        {
            [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
            _Color("Tint", Color) = (1,1,1,1)
            [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
        }
     
        SubShader
        {
            Tags
            {
                "Queue" = "Transparent+1"
                "IgnoreProjector" = "True"
                "RenderType" = "Transparent"
                "PreviewType" = "Plane"
                "CanUseSpriteAtlas" = "True"
            }
     
            Cull Off
            Lighting Off
            ZWrite Off
            Blend One OneMinusSrcAlpha
     
            Pass
            {
                Stencil
                {
                    Ref 0
                    Comp Equal
                }
     
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile _ PIXELSNAP_ON
                #include "UnityCG.cginc"
     
                struct appdata_t
                {
                    float4 vertex   : POSITION;
                    float4 color    : COLOR;
                    float2 texcoord : TEXCOORD0;
                };
     
                struct v2f
                {
                    float4 vertex   : SV_POSITION;
                    fixed4 color : COLOR;
                    half2 texcoord  : TEXCOORD0;
                };
     
                fixed4 _Color;
     
                v2f vert(appdata_t IN)
                {
                    v2f OUT;
                    OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                    OUT.texcoord = IN.texcoord;
                    OUT.color = IN.color * _Color;
                    #ifdef PIXELSNAP_ON
                    OUT.vertex = UnityPixelSnap(OUT.vertex);
                    #endif
     
                    return OUT;
                }
     
                sampler2D _MainTex;
                sampler2D _AlphaTex;
                float _AlphaSplitEnabled;
     
                fixed4 SampleSpriteTexture(float2 uv)
                {
                    fixed4 color = tex2D(_MainTex, uv);
                    if (_AlphaSplitEnabled)
                        color.a = tex2D(_AlphaTex, uv).r;
     
                    return color;
                }
     
                fixed4 frag(v2f IN) : SV_Target
                {
                    fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;
                    c.rgb *= c.a;
                    return c;
                }
            ENDCG
            }
        }
}

Теперь, нам нужно создать два материала, Mask и DrawInMask и выбрать шейдеры.

Маска для спрайта [2D]

Собственно вот и всё.

Если нам нужна маска, то просто добавляем на спрайт соответствующий материал.


А для спрайтов которые нужно обрезать маской используем материал DrawInMask.

Скачать демо:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 5.3.5

Комментариев 4

Офлайн
Light 1 апреля 2018
TheFrankyDoll, тогда остается ассет стор, там поискать шейдеры.
Офлайн
TheFrankyDoll 1 апреля 2018
Light,
Да, но она не работает с альфа каналом и плавного перехода не получается, как не пытался.
Офлайн
Light 1 апреля 2018
TheFrankyDoll, полупрозрачные края? Не пробовал. Маска для спрайтов, щас уже встроена в Юнити 2017.
Офлайн
TheFrankyDoll 1 апреля 2018
А возможно ли при таком методе использовать маску с альфа каналом? Чтобы края получались плавными, а не резкими.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика