• Unity
  • Add Soft Mask support to Spine Shader

  • Изменено
Related Discussions
...

I'm trying to add Soft Mask support to our Spine Shader.

Here's the documentation for adding Soft Mask support to shaders:
https://docs.google.com/document/d/1mFEml0JWhR968GG1gVBBTLsJ8ubf_oraW5MBbrvkrb0/edit

Here's our Spine Shader with the Soft Mask additions:

// This is a premultiply-alpha adaptation of the built-in Unity shader "UI/Default" in Unity 5.6.2 to allow Unity UI stencil masking.

Shader "Spine/SkeletonGraphic SoftMask (Premultiply Alpha)"
{
   Properties
   {
      [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
      _Color ("Tint", Color) = (1,1,1,1)
      
  _StencilComp ("Stencil Comparison", Float) = 8
  _Stencil ("Stencil ID", Float) = 0
  _StencilOp ("Stencil Operation", Float) = 0
  _StencilWriteMask ("Stencil Write Mask", Float) = 255
  _StencilReadMask ("Stencil Read Mask", Float) = 255

  _ColorMask ("Color Mask", Float) = 15
  
  _SoftMask ("Mask", 2D) = "white" {}

  [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
   }

   SubShader
   {
      Tags
      { 
         "Queue"="Transparent" 
         "IgnoreProjector"="True" 
         "RenderType"="Transparent" 
         "PreviewType"="Plane"
         "CanUseSpriteAtlas"="True"
      }
      
  Stencil
  {
     Ref [_Stencil]
     Comp [_StencilComp]
     Pass [_StencilOp] 
     ReadMask [_StencilReadMask]
     WriteMask [_StencilWriteMask]
  }

  Cull Off
  Lighting Off
  ZWrite Off
  ZTest [unity_GUIZTestMode]
  Fog { Mode Off }
  Blend One OneMinusSrcAlpha
  ColorMask [_ColorMask]

  Pass
  {
  CGPROGRAM
     #pragma vertex vert
     #pragma fragment frag
     #pragma target 2.0

     #include "UnityCG.cginc"
     #include "UnityUI.cginc"
     #include "Assets/ThirdParty/SoftMask/Shaders/SoftMask.cginc"

     #pragma multi_compile __ UNITY_UI_ALPHACLIP
     #pragma multi_compile __ SOFTMASK_SIMPLE SOFTMASK_SLICED SOFTMASK_TILED

     struct VertexInput {
        float4 vertex   : POSITION;
        float4 color    : COLOR;
        float2 texcoord : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
     };

     struct VertexOutput {
        float4 vertex   : SV_POSITION;
        fixed4 color    : COLOR;
        half2 texcoord  : TEXCOORD0;
        float4 worldPosition : TEXCOORD1;
        SOFTMASK_COORDS(2)
        UNITY_VERTEX_OUTPUT_STEREO
     };

     fixed4 _Color;
     fixed4 _TextureSampleAdd;
     float4 _ClipRect;

     VertexOutput vert (VertexInput IN) {
        VertexOutput OUT;

        UNITY_SETUP_INSTANCE_ID(IN);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);

        OUT.worldPosition = IN.vertex;
        OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
        OUT.texcoord = IN.texcoord;

        #ifdef UNITY_HALF_TEXEL_OFFSET
        OUT.vertex.xy += (_ScreenParams.zw-1.0) * float2(-1,1);
        #endif

        OUT.color = IN.color * _Color;
        SOFTMASK_CALCULATE_COORDS(OUT, IN.vertex);
        return OUT;
     }

     sampler2D _MainTex;

     fixed4 frag (VertexOutput IN) : SV_Target
     {
        half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

        color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect) * SOFTMASK_GET_MASK(IN);

        #ifdef UNITY_UI_ALPHACLIP
        clip (color.a - 0.001);
        #endif

        return color;
     }
  ENDCG
  }
   }
}

Please see the attached image for the current results. The semi-transparent parts outside the rounded rectangle are supposed to be fully transparent.

I've seen this unwanted additive symptom related to transparency when adjusting a parent Canvas Group, which is well detailed in the following thread:
http://en.esotericsoftware.com/forum/CanvasGroup-s-alpha-does-not-affect-SkeletonGraphic-9467

I feel like this could be related? The final reply in that thread shows a CanvasGroup Compatible setting in the latest Spine, so it appears there could be a shader fix. I'm hoping we can apply that fix to the shader above, as we are currently running a pretty old version of Spine (3.6.x.x). We hope to update this soon.

Anyway, any help getting Soft Mask to work with our Spine Shader would be greatly appreciated!

Spine shaders always use Premultiplied Alpha (PMA) blending on the output. So you need to not only multiply color.a by the mask value but also color.rgb.

color.a *= SOFTMASK_GET_MASK(IN); // this is not sufficient, rgb values need adjustment
color *= SOFTMASK_GET_MASK(IN); // this is correct

Ahh, that makes sense. Works great! Thanks for the quick reply! 🙂

You're welcome, glad you've figured it out! 🙂