From 32ac918f8033f36713c75ae016843dcc11758005 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 19 Feb 2019 18:54:55 +0100 Subject: [PATCH] [unity] Added support for Unity's SpriteMask to SkeletonAnimation and SkeletonMecanim. All mask interaction modes supported. See #941. --- .../Editor/SkeletonRendererInspector.cs | 126 ++++++++- .../spine-unity/Editor/SpineMaskUtilities.cs | 243 ++++++++++++++++++ .../Editor/SpineMaskUtilities.cs.meta | 12 + .../Components/SkeletonRenderer.cs | 79 ++++++ .../Spine-Special-Skeleton-Ghost.shader | 8 + .../Shaders/Spine-Skeleton-Fill.shader | 8 + .../Shaders/Spine-Skeleton-Tint.shader | 8 + .../Spine-Special-Skeleton-Grayscale.shader | 8 + .../Shaders/Sprite/SpritesPixelLit.shader | 8 + .../Shaders/Sprite/SpritesUnlit.shader | 8 + .../Shaders/Sprite/SpritesVertexLit.shader | 8 + .../Spine-Skeleton-PMA-Additive.shader | 8 + .../Spine-Skeleton-PMA-Multiply.shader | 8 + .../Spine-Skeleton-PMA-Screen.shader | 8 + .../Shaders/Spine-Skeleton-TintBlack.shader | 8 + .../spine-unity/Shaders/Spine-Skeleton.shader | 8 + .../Shaders/Spine-SkeletonLit.shader | 8 + 17 files changed, 562 insertions(+), 2 deletions(-) create mode 100644 spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs create mode 100644 spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs index 021ba4ff0..f777addc4 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs @@ -54,14 +54,23 @@ namespace Spine.Unity.Editor { protected SerializedProperty initialFlipX, initialFlipY; protected SerializedProperty singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles; protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings + protected SerializedProperty maskInteraction; + protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside; protected SpineInspectorUtility.SerializedSortingProperties sortingProperties; protected bool isInspectingPrefab; protected bool forceReloadQueued = false; + protected bool setMaskNoneMaterialsQueued = false; + protected bool setInsideMaskMaterialsQueued = false; + protected bool setOutsideMaskMaterialsQueued = false; + protected bool deleteInsideMaskMaterialsQueued = false; + protected bool deleteOutsideMaskMaterialsQueued = false; protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent; protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, SingleSubmeshLabel; - protected GUIContent NormalsLabel, TangentsLabel; + protected GUIContent NormalsLabel, TangentsLabel, MaskInteractionLabel; + protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel; + protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel; const string ReloadButtonString = "Reload"; static GUILayoutOption reloadButtonWidth; @@ -104,6 +113,14 @@ namespace Spine.Unity.Editor { TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents."); TintBlackLabel = new GUIContent("Tint Black (!)", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock."); SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials."); + MaskInteractionLabel = new GUIContent("Mask Interaction", "SkeletonRenderer's interaction with a Sprite Mask."); + MaskMaterialsHeadingLabel = new GUIContent("Mask Interaction Materials", "Materials used for different interaction with sprite masks."); + MaskMaterialsNoneLabel = new GUIContent("Normal Materials", "Normal materials used when Mask Interaction is set to None."); + MaskMaterialsInsideLabel = new GUIContent("Inside Mask", "Materials used when Mask Interaction is set to Inside Mask."); + MaskMaterialsOutsideLabel = new GUIContent("Outside Mask", "Materials used when Mask Interaction is set to Outside Mask."); + SetMaterialButtonLabel = new GUIContent("Set", "Prepares material references for switching to the corresponding Mask Interaction mode at runtime. Creates the required materials if they do not exist."); + ClearMaterialButtonLabel = new GUIContent("Clear", "Clears unused material references. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly."); + DeleteMaterialButtonLabel = new GUIContent("Delete", "Clears unused material references and deletes the corresponding assets. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly."); var so = this.serializedObject; skeletonDataAsset = so.FindProperty("skeletonDataAsset"); @@ -117,6 +134,10 @@ namespace Spine.Unity.Editor { clearStateOnDisable = so.FindProperty("clearStateOnDisable"); tintBlack = so.FindProperty("tintBlack"); singleSubmesh = so.FindProperty("singleSubmesh"); + maskInteraction = so.FindProperty("maskInteraction"); + maskMaterialsNone = so.FindProperty("maskMaterials.materialsMaskDisabled"); + maskMaterialsInside = so.FindProperty("maskMaterials.materialsInsideMask"); + maskMaterialsOutside = so.FindProperty("maskMaterials.materialsOutsideMask"); separatorSlotNames = so.FindProperty("separatorSlotNames"); separatorSlotNames.isExpanded = true; @@ -139,7 +160,8 @@ namespace Spine.Unity.Editor { override public void OnInspectorGUI () { bool multi = serializedObject.isEditingMultipleObjects; DrawInspectorGUI(multi); - if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) { + if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current) || + AreAnyMaskMaterialsMissing()) { if (!Application.isPlaying) { if (multi) { foreach (var o in targets) EditorForceInitializeComponent((SkeletonRenderer)o); @@ -193,6 +215,33 @@ namespace Spine.Unity.Editor { } } + if (setMaskNoneMaterialsQueued) { + setMaskNoneMaterialsQueued = false; + foreach (var c in targets) + EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.None); + } + if (setInsideMaskMaterialsQueued) { + setInsideMaskMaterialsQueued = false; + foreach (var c in targets) + EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask); + } + if (setOutsideMaskMaterialsQueued) { + setOutsideMaskMaterialsQueued = false; + foreach (var c in targets) + EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask); + } + + if (deleteInsideMaskMaterialsQueued) { + deleteInsideMaskMaterialsQueued = false; + foreach (var c in targets) + EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask); + } + if (deleteOutsideMaskMaterialsQueued) { + deleteOutsideMaskMaterialsQueued = false; + foreach (var c in targets) + EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask); + } + #if NO_PREFAB_MESH if (isInspectingPrefab) { if (multi) { @@ -255,6 +304,8 @@ namespace Spine.Unity.Editor { // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); + if (maskInteraction != null) EditorGUILayout.PropertyField(maskInteraction, MaskInteractionLabel); + if (!valid) return; @@ -311,6 +362,21 @@ namespace Spine.Unity.Editor { if (tangents != null) EditorGUILayout.PropertyField(tangents, TangentsLabel); } + EditorGUILayout.Space(); + if (maskMaterialsNone.arraySize > 0 || maskMaterialsInside.arraySize > 0 || maskMaterialsOutside.arraySize > 0) { + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Mask Interaction Materials", SpineInspectorUtility.UnityIcon()), EditorStyles.boldLabel); + bool differentMaskModesSelected = maskInteraction.hasMultipleDifferentValues; + int activeMaskInteractionValue = differentMaskModesSelected ? -1 : maskInteraction.intValue; + + bool ignoredParam = true; + MaskMaterialsEditingField(ref setMaskNoneMaterialsQueued, ref ignoredParam, maskMaterialsNone, MaskMaterialsNoneLabel, + differentMaskModesSelected, allowDelete : false, isActiveMaterial : activeMaskInteractionValue == (int)SpriteMaskInteraction.None); + MaskMaterialsEditingField(ref setInsideMaskMaterialsQueued, ref deleteInsideMaskMaterialsQueued, maskMaterialsInside, MaskMaterialsInsideLabel, + differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleInsideMask); + MaskMaterialsEditingField(ref setOutsideMaskMaterialsQueued, ref deleteOutsideMaskMaterialsQueued, maskMaterialsOutside, MaskMaterialsOutsideLabel, + differentMaskModesSelected, allowDelete : true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleOutsideMask); + } + EditorGUILayout.Space(); if (valid && !isInspectingPrefab) { @@ -388,6 +454,38 @@ namespace Spine.Unity.Editor { } } + public void MaskMaterialsEditingField(ref bool wasSetRequested, ref bool wasDeleteRequested, + SerializedProperty maskMaterials, GUIContent label, + bool differentMaskModesSelected, bool allowDelete, bool isActiveMaterial) { + using (new EditorGUILayout.HorizontalScope()) { + + EditorGUILayout.LabelField(label, isActiveMaterial ? EditorStyles.boldLabel : EditorStyles.label, GUILayout.MinWidth(80f), GUILayout.MaxWidth(140)); + EditorGUILayout.LabelField(maskMaterials.hasMultipleDifferentValues ? "-" : maskMaterials.arraySize.ToString(), EditorStyles.miniLabel, GUILayout.Width(42f)); + + bool enableSetButton = differentMaskModesSelected || maskMaterials.arraySize == 0; + bool enableClearButtons = differentMaskModesSelected || (maskMaterials.arraySize != 0 && !isActiveMaterial); + + EditorGUI.BeginDisabledGroup(!enableSetButton); + if (GUILayout.Button(SetMaterialButtonLabel, EditorStyles.miniButtonLeft, GUILayout.Width(46f))) { + wasSetRequested = true; + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.BeginDisabledGroup(!enableClearButtons); + { + if (GUILayout.Button(ClearMaterialButtonLabel, allowDelete ? EditorStyles.miniButtonMid : EditorStyles.miniButtonRight, GUILayout.Width(46f))) { + maskMaterials.ClearArray(); + } + else if (allowDelete && GUILayout.Button(DeleteMaterialButtonLabel, EditorStyles.miniButtonRight, GUILayout.Width(46f))) { + wasDeleteRequested = true; + } + if (!allowDelete) + GUILayout.Space(46f); + } + EditorGUI.EndDisabledGroup(); + } + } + static bool UpdateIfSkinMismatch (SkeletonRenderer skeletonRenderer) { if (!skeletonRenderer.valid) return false; @@ -427,12 +525,36 @@ namespace Spine.Unity.Editor { if (component == null) return; if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; component.Initialize(true); + SpineMaskUtilities.EditorAssignSpriteMaskMaterials(component); component.LateUpdate(); } + bool AreAnyMaskMaterialsMissing() { + foreach (var o in targets) { + var component = (SkeletonRenderer)o; + if (!component.valid) + continue; + if (SpineMaskUtilities.AreMaskMaterialsMissing(component)) + return true; + } + return false; + } + static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) { return asset != null && asset.GetSkeletonData(quiet: true) != null; } + static void EditorSetMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) + { + if (component == null) return; + if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; + SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType); + } + + static void EditorDeleteMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) { + if (component == null) return; + if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; + SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType); + } } } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs new file mode 100644 index 000000000..9781bb0cc --- /dev/null +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs @@ -0,0 +1,243 @@ +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2019, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#pragma warning disable 0219 + +#define SPINE_SKELETONMECANIM + +#if UNITY_2017_2_OR_NEWER +#define NEWPLAYMODECALLBACKS +#endif + +#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER +#define NEW_PREFAB_SYSTEM +#endif + +#if UNITY_2018 || UNITY_2019 || UNITY_2018_3_OR_NEWER +#define NEWHIERARCHYWINDOWCALLBACKS +#endif + +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Linq; +using System.Reflection; + +namespace Spine.Unity.Editor { + + public class SpineMaskUtilities { + + private const string MATERIAL_FILENAME_SUFFIX_INSIDE_MASK = "_InsideMask"; + private const string MATERIAL_FILENAME_SUFFIX_OUTSIDE_MASK = "_OutsideMask"; + + public static void EditorAssignSpriteMaskMaterials(SkeletonRenderer skeleton) { + var maskMaterials = skeleton.maskMaterials; + var maskInteraction = skeleton.maskInteraction; + var meshRenderer = skeleton.GetComponent(); + + if (maskMaterials.materialsMaskDisabled.Length > 0 && maskMaterials.materialsMaskDisabled[0] != null && + maskInteraction == SpriteMaskInteraction.None) { + meshRenderer.materials = maskMaterials.materialsMaskDisabled; + } + else if (maskInteraction == SpriteMaskInteraction.VisibleInsideMask) { + if (maskMaterials.materialsInsideMask.Length == 0 || maskMaterials.materialsInsideMask[0] == null) + EditorInitSpriteMaskMaterialsInsideMask(skeleton); + meshRenderer.materials = maskMaterials.materialsInsideMask; + } + else if (maskInteraction == SpriteMaskInteraction.VisibleOutsideMask) { + if (maskMaterials.materialsOutsideMask.Length == 0 || maskMaterials.materialsOutsideMask[0] == null) + EditorInitSpriteMaskMaterialsOutsideMask(skeleton); + meshRenderer.materials = maskMaterials.materialsOutsideMask; + } + } + + public static bool AreMaskMaterialsMissing(SkeletonRenderer skeleton) { + var maskMaterials = skeleton.maskMaterials; + var maskInteraction = skeleton.maskInteraction; + + if (maskInteraction == SpriteMaskInteraction.None) { + return (maskMaterials.materialsMaskDisabled.Length == 0 || maskMaterials.materialsMaskDisabled[0] == null); + } + else if (maskInteraction == SpriteMaskInteraction.VisibleInsideMask) { + return (maskMaterials.materialsInsideMask.Length == 0 || maskMaterials.materialsInsideMask[0] == null); + } + else if (maskInteraction == SpriteMaskInteraction.VisibleOutsideMask) { + return (maskMaterials.materialsOutsideMask.Length == 0 || maskMaterials.materialsOutsideMask[0] == null); + } + return false; + } + + public static void EditorInitMaskMaterials(SkeletonRenderer skeleton, SkeletonRenderer.SpriteMaskInteractionMaterials maskMaterials, SpriteMaskInteraction maskType) { + if (maskType == SpriteMaskInteraction.None) { + EditorConfirmDisabledMaskMaterialsInit(skeleton); + } + else if (maskType == SpriteMaskInteraction.VisibleInsideMask) { + EditorInitSpriteMaskMaterialsInsideMask(skeleton); + } + else if (maskType == SpriteMaskInteraction.VisibleOutsideMask) { + EditorInitSpriteMaskMaterialsOutsideMask(skeleton); + } + } + + public static void EditorDeleteMaskMaterials(SkeletonRenderer.SpriteMaskInteractionMaterials maskMaterials, SpriteMaskInteraction maskType) { + Material[] targetMaterials; + if (maskType == SpriteMaskInteraction.VisibleInsideMask) { + targetMaterials = maskMaterials.materialsInsideMask; + } + else if (maskType == SpriteMaskInteraction.VisibleOutsideMask) { + targetMaterials = maskMaterials.materialsOutsideMask; + } + else { + Debug.LogWarning("EditorDeleteMaskMaterials: Normal materials are kept as a reference and shall never be deleted."); + return; + } + + for (int i = 0; i < targetMaterials.Length; ++i) { + var material = targetMaterials[i]; + if (material != null) { + string materialPath = UnityEditor.AssetDatabase.GetAssetPath(material); + UnityEditor.AssetDatabase.DeleteAsset(materialPath); + Debug.Log(string.Concat("Deleted material '", materialPath, "'")); + } + } + + if (maskType == SpriteMaskInteraction.VisibleInsideMask) { + maskMaterials.materialsInsideMask = new Material[0]; + } + else if (maskType == SpriteMaskInteraction.VisibleOutsideMask) { + maskMaterials.materialsOutsideMask = new Material[0]; + } + } + + private static void EditorInitSpriteMaskMaterialsInsideMask(SkeletonRenderer skeleton) { + var maskMaterials = skeleton.maskMaterials; + EditorInitSpriteMaskMaterialsForMaskType(skeleton, SkeletonRenderer.STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE, + ref maskMaterials.materialsInsideMask); + } + + private static void EditorInitSpriteMaskMaterialsOutsideMask(SkeletonRenderer skeleton) { + var maskMaterials = skeleton.maskMaterials; + EditorInitSpriteMaskMaterialsForMaskType(skeleton, SkeletonRenderer.STENCIL_COMP_MASKINTERACTION_VISIBLE_OUTSIDE, + ref maskMaterials.materialsOutsideMask); + } + + private static void EditorInitSpriteMaskMaterialsForMaskType(SkeletonRenderer skeleton, UnityEngine.Rendering.CompareFunction maskFunction, + ref Material[] materialsToFill) { + if (!EditorConfirmDisabledMaskMaterialsInit(skeleton)) + return; + + var maskMaterials = skeleton.maskMaterials; + var originalMaterials = maskMaterials.materialsMaskDisabled; + materialsToFill = new Material[originalMaterials.Length]; + for (int i = 0; i < originalMaterials.Length; i++) { + Material newMaterial = null; + + if (!Application.isPlaying) { + newMaterial = EditorCreateOrLoadMaskMaterialAsset(maskMaterials, maskFunction, originalMaterials[i]); + } + if (newMaterial == null) { + newMaterial = new Material(originalMaterials[i]); + newMaterial.SetFloat(SkeletonRenderer.STENCIL_COMP_PARAM_ID, (int)maskFunction); + } + materialsToFill[i] = newMaterial; + } + } + + private static bool EditorConfirmDisabledMaskMaterialsInit(SkeletonRenderer skeleton) { + var maskMaterials = skeleton.maskMaterials; + if (maskMaterials.materialsMaskDisabled.Length > 0 && maskMaterials.materialsMaskDisabled[0] != null) { + return true; + } + + var meshRenderer = skeleton.GetComponent(); + Material[] currentMaterials = meshRenderer.sharedMaterials; + + if (currentMaterials.Length == 0 || currentMaterials[0] == null) { + Debug.LogWarning("No materials found assigned at " + skeleton.name); + return false; + } + + // We have to be sure that there has not been a recompilation or similar events that led to + // inside- or outside-mask materials being assigned to meshRenderer.sharedMaterials. + string firstMaterialPath = UnityEditor.AssetDatabase.GetAssetPath(currentMaterials[0]); + if (firstMaterialPath.Contains(MATERIAL_FILENAME_SUFFIX_INSIDE_MASK) || + firstMaterialPath.Contains(MATERIAL_FILENAME_SUFFIX_OUTSIDE_MASK)) { + + maskMaterials.materialsMaskDisabled = new Material[currentMaterials.Length]; + for (int i = 0; i < currentMaterials.Length; ++i) { + string path = UnityEditor.AssetDatabase.GetAssetPath(currentMaterials[i]); + string correctPath = null; + if (path.Contains(MATERIAL_FILENAME_SUFFIX_INSIDE_MASK)) { + correctPath = path.Replace(MATERIAL_FILENAME_SUFFIX_INSIDE_MASK, ""); + } + else if (path.Contains(MATERIAL_FILENAME_SUFFIX_OUTSIDE_MASK)) { + correctPath = path.Replace(MATERIAL_FILENAME_SUFFIX_OUTSIDE_MASK, ""); + } + + if (correctPath != null) { + Material material = UnityEditor.AssetDatabase.LoadAssetAtPath(correctPath); + if (material == null) + Debug.LogWarning("No original ignore-mask material found for path " + correctPath); + maskMaterials.materialsMaskDisabled[i] = material; + } + } + } + else { + maskMaterials.materialsMaskDisabled = currentMaterials; + } + return true; + } + + public static Material EditorCreateOrLoadMaskMaterialAsset(SkeletonRenderer.SpriteMaskInteractionMaterials maskMaterials, + UnityEngine.Rendering.CompareFunction maskFunction, Material originalMaterial) { + string originalMaterialPath = UnityEditor.AssetDatabase.GetAssetPath(originalMaterial); + int posOfExtensionDot = originalMaterialPath.LastIndexOf('.'); + string materialPath = (maskFunction == SkeletonRenderer.STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE) ? + originalMaterialPath.Insert(posOfExtensionDot, MATERIAL_FILENAME_SUFFIX_INSIDE_MASK) : + originalMaterialPath.Insert(posOfExtensionDot, MATERIAL_FILENAME_SUFFIX_OUTSIDE_MASK); + + Material material = UnityEditor.AssetDatabase.LoadAssetAtPath(materialPath); + if (material != null) { + return material; + } + + material = new Material(originalMaterial); + material.SetFloat(SkeletonRenderer.STENCIL_COMP_PARAM_ID, (int)maskFunction); + + UnityEditor.AssetDatabase.CreateAsset(material, materialPath); + Debug.Log(string.Concat("Created material '", materialPath, "' for mask interaction based on '", originalMaterialPath, "'.")); + UnityEditor.EditorUtility.SetDirty(material); + UnityEditor.AssetDatabase.SaveAssets(); + return material; + } + } +} diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs.meta b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs.meta new file mode 100644 index 000000000..7d3b80bd3 --- /dev/null +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineMaskUtilities.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7c1b3a9ddacb550458bb86affdf77bf5 +timeCreated: 1550564907 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 83817e787..a57bab908 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -91,6 +91,32 @@ namespace Spine.Unity { /// If true, tangents are calculated every frame and added to the Mesh. Enable this when using a shader that uses lighting that requires tangents. public bool calculateTangents = false; + + /// This enum controls the mode under which the sprite will interact with the masking system. + /// Interaction modes with components are identical to Unity's , + /// see https://docs.unity3d.com/ScriptReference/SpriteMaskInteraction.html. + public SpriteMaskInteraction maskInteraction = SpriteMaskInteraction.None; + + [System.Serializable] + public class SpriteMaskInteractionMaterials { + /// Material references for switching material sets at runtime when changes to . + public Material[] materialsMaskDisabled = new Material[0]; + /// Material references for switching material sets at runtime when changes to . + public Material[] materialsInsideMask = new Material[0]; + /// Material references for switching material sets at runtime when changes to . + public Material[] materialsOutsideMask = new Material[0]; + } + /// Material references for switching material sets at runtime when changes. + public SpriteMaskInteractionMaterials maskMaterials = new SpriteMaskInteractionMaterials(); + + /// Shader property ID used for the Stencil comparison function. + public static readonly int STENCIL_COMP_PARAM_ID = Shader.PropertyToID("_StencilComp"); + /// Shader property value used as Stencil comparison function for . + public const UnityEngine.Rendering.CompareFunction STENCIL_COMP_MASKINTERACTION_NONE = UnityEngine.Rendering.CompareFunction.Disabled; + /// Shader property value used as Stencil comparison function for . + public const UnityEngine.Rendering.CompareFunction STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE = UnityEngine.Rendering.CompareFunction.LessEqual; + /// Shader property value used as Stencil comparison function for . + public const UnityEngine.Rendering.CompareFunction STENCIL_COMP_MASKINTERACTION_VISIBLE_OUTSIDE = UnityEngine.Rendering.CompareFunction.Greater; #endregion #region Overrides @@ -373,6 +399,10 @@ namespace Spine.Unity { // STEP 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. =========== meshFilter.sharedMesh = currentMesh; currentSmartMesh.instructionUsed.Set(currentInstructions); + + if (meshRenderer != null) { + AssignSpriteMaskMaterials(); + } } public void FindAndApplySeparatorSlots (string startsWith, bool clearExistingSeparators = true, bool updateStringArray = false) { @@ -435,5 +465,54 @@ namespace Spine.Unity { } } + private void AssignSpriteMaskMaterials() + { + if (maskMaterials.materialsMaskDisabled.Length > 0 && maskMaterials.materialsMaskDisabled[0] != null && + maskInteraction == SpriteMaskInteraction.None) { + this.meshRenderer.materials = maskMaterials.materialsMaskDisabled; + } + else if (maskInteraction == SpriteMaskInteraction.VisibleInsideMask) { + if (maskMaterials.materialsInsideMask.Length == 0 || maskMaterials.materialsInsideMask[0] == null) { + if (!InitSpriteMaskMaterialsInsideMask()) + return; + } + this.meshRenderer.materials = maskMaterials.materialsInsideMask; + } + else if (maskInteraction == SpriteMaskInteraction.VisibleOutsideMask) { + if (maskMaterials.materialsOutsideMask.Length == 0 || maskMaterials.materialsOutsideMask[0] == null) { + if (!InitSpriteMaskMaterialsOutsideMask()) + return; + } + this.meshRenderer.materials = maskMaterials.materialsOutsideMask; + } + } + + private bool InitSpriteMaskMaterialsInsideMask() + { + return InitSpriteMaskMaterialsForMaskType(STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE, ref maskMaterials.materialsInsideMask); + } + + private bool InitSpriteMaskMaterialsOutsideMask() + { + return InitSpriteMaskMaterialsForMaskType(STENCIL_COMP_MASKINTERACTION_VISIBLE_OUTSIDE, ref maskMaterials.materialsOutsideMask); + } + + private bool InitSpriteMaskMaterialsForMaskType(UnityEngine.Rendering.CompareFunction maskFunction, ref Material[] materialsToFill) + { + #if UNITY_EDITOR + if (!Application.isPlaying) { + return false; + } + #endif + + var originalMaterials = maskMaterials.materialsMaskDisabled; + materialsToFill = new Material[originalMaterials.Length]; + for (int i = 0; i < originalMaterials.Length; i++) { + Material newMaterial = new Material(originalMaterials[i]); + newMaterial.SetFloat(STENCIL_COMP_PARAM_ID, (int)maskFunction); + materialsToFill[i] = newMaterial; + } + return true; + } } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ghost/Shaders/Spine-Special-Skeleton-Ghost.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ghost/Shaders/Spine-Special-Skeleton-Ghost.shader index 235d76cb8..bd529e3fc 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ghost/Shaders/Spine-Special-Skeleton-Ghost.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ghost/Shaders/Spine-Special-Skeleton-Ghost.shader @@ -7,6 +7,8 @@ Shader "Spine/Special/SkeletonGhost" { _Color ("Main Color", Color) = (1,1,1,1) [NoScaleOffset] _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {} _TextureFade ("Texture Fade Out", Range(0,1)) = 0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { Tags { @@ -18,6 +20,12 @@ Shader "Spine/Special/SkeletonGhost" { Blend One OneMinusSrcAlpha ZWrite Off Cull Off + + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } Pass { CGPROGRAM diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader index 1fc6da2a7..12001cd57 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader @@ -9,6 +9,8 @@ Shader "Spine/Skeleton Fill" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {} _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } @@ -17,6 +19,12 @@ Shader "Spine/Skeleton Fill" { ZWrite Off Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader index 0cba285cb..638e09c6f 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader @@ -11,6 +11,8 @@ Shader "Spine/Skeleton Tint" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -22,6 +24,12 @@ Shader "Spine/Skeleton Tint" { Blend One OneMinusSrcAlpha Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Special-Skeleton-Grayscale.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Special-Skeleton-Grayscale.shader index 112c46ebb..80f30d38a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Special-Skeleton-Grayscale.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Special-Skeleton-Grayscale.shader @@ -8,6 +8,8 @@ Shader "Spine/Special/Skeleton Grayscale" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {} _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } @@ -16,6 +18,12 @@ Shader "Spine/Special/Skeleton Grayscale" { ZWrite Off Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesPixelLit.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesPixelLit.shader index fca34de2f..8ee4d2c09 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesPixelLit.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesPixelLit.shader @@ -44,6 +44,8 @@ Shader "Spine/Sprite/Pixel Lit" [HideInInspector] _DstBlend ("__dst", Float) = 0.0 [HideInInspector] _RenderQueue ("__queue", Float) = 0.0 [HideInInspector] _Cull ("__cull", Float) = 0.0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader @@ -51,6 +53,12 @@ Shader "Spine/Sprite/Pixel Lit" Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" "CanUseSpriteAtlas"="True" "IgnoreProjector"="True" } LOD 200 + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { Name "FORWARD" diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesUnlit.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesUnlit.shader index 807a4c270..56521c4ee 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesUnlit.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesUnlit.shader @@ -26,6 +26,8 @@ Shader "Spine/Sprite/Unlit" [HideInInspector] _DstBlend ("__dst", Float) = 0.0 [HideInInspector] _RenderQueue ("__queue", Float) = 0.0 [HideInInspector] _Cull ("__cull", Float) = 0.0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader @@ -33,6 +35,12 @@ Shader "Spine/Sprite/Unlit" Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" "CanUseSpriteAtlas"="True" "IgnoreProjector"="True" } LOD 100 + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { Blend [_SrcBlend] [_DstBlend] diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesVertexLit.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesVertexLit.shader index 7137b0d32..7e7ebe415 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesVertexLit.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Sprite/SpritesVertexLit.shader @@ -44,12 +44,20 @@ Shader "Spine/Sprite/Vertex Lit" [HideInInspector] _DstBlend ("__dst", Float) = 0.0 [HideInInspector] _RenderQueue ("__queue", Float) = 0.0 [HideInInspector] _Cull ("__cull", Float) = 0.0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" "CanUseSpriteAtlas"="True" "IgnoreProjector"="True" } LOD 150 + + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } Pass { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Additive.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Additive.shader index 0e83f229f..0b79b5364 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Additive.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Additive.shader @@ -11,6 +11,8 @@ Shader "Spine/Blend Modes/Skeleton PMA Additive" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -23,6 +25,12 @@ Shader "Spine/Blend Modes/Skeleton PMA Additive" { Blend One One Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Multiply.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Multiply.shader index ffd84418c..3d16848c6 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Multiply.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Multiply.shader @@ -11,6 +11,8 @@ Shader "Spine/Blend Modes/Skeleton PMA Multiply" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -23,6 +25,12 @@ Shader "Spine/Blend Modes/Skeleton PMA Multiply" { Blend DstColor OneMinusSrcAlpha Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Screen.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Screen.shader index 5c3322c33..1a1dfbf1c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Screen.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/BlendModes/Spine-Skeleton-PMA-Screen.shader @@ -11,6 +11,8 @@ Shader "Spine/Blend Modes/Skeleton PMA Screen" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -23,6 +25,12 @@ Shader "Spine/Blend Modes/Skeleton PMA Screen" { Blend One OneMinusSrcColor Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-TintBlack.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-TintBlack.shader index 1e5c040c7..f67810e52 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-TintBlack.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-TintBlack.shader @@ -13,6 +13,8 @@ Shader "Spine/Skeleton Tint Black" { [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -25,6 +27,12 @@ Shader "Spine/Skeleton Tint Black" { Blend One OneMinusSrcAlpha Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton.shader index 661f279c3..3050d089c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton.shader @@ -3,6 +3,8 @@ Shader "Spine/Skeleton" { _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -14,6 +16,12 @@ Shader "Spine/Skeleton" { Blend One OneMinusSrcAlpha Lighting Off + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } + Pass { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-SkeletonLit.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-SkeletonLit.shader index a4f9b34d6..228a41566 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-SkeletonLit.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-SkeletonLit.shader @@ -7,6 +7,8 @@ Shader "Spine/Skeleton Lit" { _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 + [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } SubShader { @@ -16,6 +18,12 @@ Shader "Spine/Skeleton Lit" { Cull Off ZWrite Off Blend One OneMinusSrcAlpha + + Stencil { + Ref[_StencilRef] + Comp[_StencilComp] + Pass Keep + } // Pass { // Tags { "LightMode"="Vertex" }