[unity] Added support for Unity's SpriteMask to SkeletonAnimation and SkeletonMecanim. All mask interaction modes supported. See #941.

This commit is contained in:
Harald Csaszar 2019-02-19 18:54:55 +01:00
parent 5c75b1cb31
commit 32ac918f80
17 changed files with 562 additions and 2 deletions

View File

@ -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<SpriteMask>()), 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);
}
}
}

View File

@ -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<MeshRenderer>();
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<MeshRenderer>();
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<Material>(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<Material>(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;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7c1b3a9ddacb550458bb86affdf77bf5
timeCreated: 1550564907
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -91,6 +91,32 @@ namespace Spine.Unity {
/// <summary>If true, tangents are calculated every frame and added to the Mesh. Enable this when using a shader that uses lighting that requires tangents.</summary>
public bool calculateTangents = false;
/// <summary>This enum controls the mode under which the sprite will interact with the masking system.</summary>
/// <remarks>Interaction modes with <see cref="UnityEngine.SpriteMask"/> components are identical to Unity's <see cref="UnityEngine.SpriteRenderer"/>,
/// see https://docs.unity3d.com/ScriptReference/SpriteMaskInteraction.html. </remarks>
public SpriteMaskInteraction maskInteraction = SpriteMaskInteraction.None;
[System.Serializable]
public class SpriteMaskInteractionMaterials {
/// <summary>Material references for switching material sets at runtime when <see cref="SkeletonRenderer.maskInteraction"/> changes to <see cref="SpriteMaskInteraction.None"/>.</summary>
public Material[] materialsMaskDisabled = new Material[0];
/// <summary>Material references for switching material sets at runtime when <see cref="SkeletonRenderer.maskInteraction"/> changes to <see cref="SpriteMaskInteraction.VisibleInsideMask"/>.</summary>
public Material[] materialsInsideMask = new Material[0];
/// <summary>Material references for switching material sets at runtime when <see cref="SkeletonRenderer.maskInteraction"/> changes to <see cref="SpriteMaskInteraction.VisibleOutsideMask"/>.</summary>
public Material[] materialsOutsideMask = new Material[0];
}
/// <summary>Material references for switching material sets at runtime when <see cref="SkeletonRenderer.maskInteraction"/> changes.</summary>
public SpriteMaskInteractionMaterials maskMaterials = new SpriteMaskInteractionMaterials();
/// <summary>Shader property ID used for the Stencil comparison function.</summary>
public static readonly int STENCIL_COMP_PARAM_ID = Shader.PropertyToID("_StencilComp");
/// <summary>Shader property value used as Stencil comparison function for <see cref="SpriteMaskInteraction.None"/>.</summary>
public const UnityEngine.Rendering.CompareFunction STENCIL_COMP_MASKINTERACTION_NONE = UnityEngine.Rendering.CompareFunction.Disabled;
/// <summary>Shader property value used as Stencil comparison function for <see cref="SpriteMaskInteraction.VisibleInsideMask"/>.</summary>
public const UnityEngine.Rendering.CompareFunction STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE = UnityEngine.Rendering.CompareFunction.LessEqual;
/// <summary>Shader property value used as Stencil comparison function for <see cref="SpriteMaskInteraction.VisibleOutsideMask"/>.</summary>
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;
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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]

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" }