diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7e775b4..d1f06f256 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -370,7 +370,8 @@ - Spine UI Toolkit UPM package now supports PMA atlas textures. At the `SpineVisualElement` expand `Blend Mode Materials` and hit `Detect Materials` to automatically assign the proper PMA or straight alpha material at `Normal Material`. Unity minimum version increased to 6000.3 which added support for UI Toolkit materials. - Spine UI Toolkit UPM package now supports all Spine blend modes via blend mode materials and multiple materials per skeleton. Enable `Multiple Materials` (enabled by default), expand `Blend Mode Materials` and hit `Detect Materials` to automatically assign the correct PMA or straight alpha blend mode materials. - Every Spine URP shader now has an `Outline` option to switch to the respective Outline shader variant. Uses multi-pass support of newer URP versions. Requires spine-unity core package version 4.3.44 or newer due to required modifications in custom Sprite Shader GUI. - - Added new variants of `GetRepackedSkin` and `GetRepackedAttachments` supporting blend modes. These new variants take a packing configuration input struct `RepackAttachmentsSettings` which provides optional `additiveMaterialSource`, `multiplyMaterialSource` and `screenMaterialSource` properties, enabling blend mode repacking when any is non-null. Create your `RepackAttachmentsSettings` from default settings via `RepackAttachmentsSettings.Default` and then customize settings as needed. + - Added new variants of `GetRepackedSkin` and `GetRepackedAttachments` supporting blend modes. These new variants take a packing configuration input struct `RepackAttachmentsSettings` which provides optional `additiveMaterialSource`, `multiplyMaterialSource` and `screenMaterialSource` properties, enabling blend mode repacking when any is non-null. Create your `RepackAttachmentsSettings` from default settings via `RepackAttachmentsSettings.Default` and then customize settings as needed. Uses new `RepackAttachmentsOutput` struct providing `DestroyGeneratedAssets` to easily destroy any previously generated assets. + - Updated example scenes to demonstrate new `GetRepackedSkin` variant usage. - **Deprecated** diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs index b6734a5eb..6e97f29f0 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs @@ -31,12 +31,10 @@ #define CONFIGURABLE_ENTER_PLAY_MODE #endif - using System; using System.Collections.Generic; using UnityEngine; - namespace Spine.Unity.AttachmentTools { public static class AtlasUtilities { @@ -266,6 +264,27 @@ namespace Spine.Unity.AttachmentTools { /// as main texture. /// Materials and textures returned behave like new Texture2D() and need to be destroyed. public Material outputScreenMaterial; + + /// + /// Destroys any assigned previously generated assets. If you decide to store + /// in a MonoBehaviour for re-use, call this method before each + /// or call, and also once in OnDestroy. + /// + public void DestroyGeneratedAssets () { + if (outputMaterial) { UnityEngine.Object.Destroy(outputMaterial); outputMaterial = null; } + if (outputTexture) { UnityEngine.Object.Destroy(outputTexture); outputTexture = null; } + if (additionalOutputTextures != null) { + for (int i = 0; i < additionalOutputTextures.Length; ++i) { + if (additionalOutputTextures[i]) { + UnityEngine.Object.Destroy(additionalOutputTextures[i]); + additionalOutputTextures[i] = null; + } + } + } + if (outputAdditiveMaterial) { UnityEngine.Object.Destroy(outputAdditiveMaterial); outputAdditiveMaterial = null; } + if (outputMultiplyMaterial) { UnityEngine.Object.Destroy(outputMultiplyMaterial); outputMultiplyMaterial = null; } + if (outputScreenMaterial) { UnityEngine.Object.Destroy(outputScreenMaterial); outputScreenMaterial = null; } + } } /// @@ -351,25 +370,63 @@ namespace Spine.Unity.AttachmentTools { public bool[] additionalTextureIsLinear; /// Default settings providing reasonable parameters, modify according to your needs. - public static RepackAttachmentsSettings Default = new RepackAttachmentsSettings { - materialPropertySource = null, - additiveMaterialSource = null, - multiplyMaterialSource = null, - screenMaterialSource = null, + public static RepackAttachmentsSettings Default = new RepackAttachmentsSettings(true); - newAssetName = "Repacked Attachments", + /// Hidden pseudo-default ctor, use instead. + private RepackAttachmentsSettings (bool _) { + newAssetName = DefaultTextureName; - maxAtlasSize = 1024, - padding = 2, - textureFormat = SpineTextureFormat, - mipmaps = UseMipMaps, - clearCache = false, + maxAtlasSize = 1024; + padding = 2; + textureFormat = SpineTextureFormat; + mipmaps = UseMipMaps; + clearCache = false; + useOriginalNonrenderables = true; - useOriginalNonrenderables = true, - additionalTexturePropertyIDsToCopy = null, - additionalTextureFormats = null, - additionalTextureIsLinear = null - }; + shader = null; + materialPropertySource = null; + additiveMaterialSource = null; + multiplyMaterialSource = null; + screenMaterialSource = null; + + additionalTexturePropertyIDsToCopy = null; + additionalTextureFormats = null; + additionalTextureIsLinear = null; + } + + /// + /// Default settings providing reasonable parameters, with source materials assigned according to the + /// provided . Modify according to your needs. + /// + /// Reference used to provide source + /// materials for all blend modes. + public RepackAttachmentsSettings (SkeletonDataAsset skeletonDataAsset) + : this(true) { + UseSourceMaterialsFrom(skeletonDataAsset); + } + + /// + /// Assigns source materials from the provided for all blend modes + /// including normal blend mode. + /// + public void UseSourceMaterialsFrom (SkeletonDataAsset skeletonDataAsset) { + materialPropertySource = skeletonDataAsset.atlasAssets[0].PrimaryMaterial; + UseBlendModeMaterialsFrom(skeletonDataAsset); + } + + /// + /// Assigns source materials from the provided for + /// additive, multiply and screen blend modes. + /// + public void UseBlendModeMaterialsFrom (SkeletonDataAsset skeletonDataAsset) { + BlendModeMaterials materials = skeletonDataAsset.blendModeMaterials; + if (materials.additiveMaterials.Count > 0) + additiveMaterialSource = materials.additiveMaterials[0].material; + if (materials.multiplyMaterials.Count > 0) + multiplyMaterialSource = materials.multiplyMaterials[0].material; + if (materials.screenMaterials.Count > 0) + screenMaterialSource = materials.screenMaterials[0].material; + } } private struct BlendModeAtlasPages { diff --git a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs index 31f7e9fc8..bfc2abfd2 100644 --- a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs +++ b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs @@ -43,8 +43,7 @@ namespace Spine.Unity.Examples { Spine.Skin equipsSkin; Spine.Skin collectedSkin; - public Material runtimeMaterial; - public Texture2D runtimeAtlas; + AtlasUtilities.RepackAttachmentsOutput repackingOutput; void Start () { equipsSkin = new Skin("Equips"); @@ -58,6 +57,11 @@ namespace Spine.Unity.Examples { RefreshSkeletonAttachments(); } + void OnDestroy () { + // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed + repackingOutput.DestroyGeneratedAssets(); + } + public void Equip (int slotIndex, string attachmentName, Attachment attachment) { equipsSkin.SetAttachment(slotIndex, attachmentName, attachment); skeletonAnimation.Skeleton.SetSkin(equipsSkin); @@ -72,13 +76,13 @@ namespace Spine.Unity.Examples { collectedSkin.AddSkin(equipsSkin); // 2. Create a repacked skin. - // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed - if (runtimeMaterial) - Destroy(runtimeMaterial); - if (runtimeAtlas) - Destroy(runtimeAtlas); - Skin repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, - out runtimeMaterial, out runtimeAtlas, maxAtlasSize: 1024, clearCache: false); + // Note: materials and textures returned by previous GetRepackedSkin() calls behave like 'new Texture2D()' + // and need to be destroyed. + repackingOutput.DestroyGeneratedAssets(); + AtlasUtilities.RepackAttachmentsSettings settings = AtlasUtilities.RepackAttachmentsSettings.Default; + settings.UseSourceMaterialsFrom(skeletonAnimation.SkeletonDataAsset); + settings.maxAtlasSize = 1024; + Skin repackedSkin = collectedSkin.GetRepackedSkin("repacked skin", settings, ref repackingOutput); collectedSkin.Clear(); // You can optionally clear the textures cache after each ore multiple repack operations are done. diff --git a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs index 9d2e4b39c..574f3d239 100644 --- a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs +++ b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs @@ -65,9 +65,8 @@ namespace Spine.Unity.Examples { Skin characterSkin; // for repacking the skin to a new atlas texture - public Material runtimeMaterial; - public Texture2D runtimeAtlas; - + AtlasUtilities.RepackAttachmentsOutput repackingOutput; + void Awake () { skeletonAnimation = this.GetComponent(); } @@ -77,6 +76,11 @@ namespace Spine.Unity.Examples { UpdateCombinedSkin(); } + void OnDestroy () { + // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed + repackingOutput.DestroyGeneratedAssets(); + } + public void NextHairSkin () { activeHairIndex = (activeHairIndex + 1) % hairSkins.Length; UpdateCharacterSkin(); @@ -136,12 +140,14 @@ namespace Spine.Unity.Examples { public void OptimizeSkin () { // Create a repacked skin. Skin previousSkin = skeletonAnimation.Skeleton.Skin; - // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed - if (runtimeMaterial) - Destroy(runtimeMaterial); - if (runtimeAtlas) - Destroy(runtimeAtlas); - Skin repackedSkin = previousSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas); + + // Note: materials and textures returned by previous GetRepackedSkin() calls behave like 'new Texture2D()' + // and need to be destroyed. + repackingOutput.DestroyGeneratedAssets(); + AtlasUtilities.RepackAttachmentsSettings settings = AtlasUtilities.RepackAttachmentsSettings.Default; + settings.UseSourceMaterialsFrom(skeletonAnimation.SkeletonDataAsset); + settings.maxAtlasSize = 1024; + Skin repackedSkin = previousSkin.GetRepackedSkin("repacked skin", settings, ref repackingOutput); previousSkin.Clear(); // Use the repacked skin. diff --git a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/MixAndMatch.cs b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/MixAndMatch.cs index 0291336e3..27f30f394 100644 --- a/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/MixAndMatch.cs +++ b/spine-unity/Assets/Spine/Samples~/Spine Examples/Scripts/MixAndMatch.cs @@ -55,9 +55,7 @@ namespace Spine.Unity.Examples { public bool repack = true; public BoundingBoxFollower bbFollower; - [Header("Do not assign")] - public Texture2D runtimeAtlas; - public Material runtimeMaterial; + AtlasUtilities.RepackAttachmentsOutput repackingOutput; #endregion Skin customSkin; @@ -75,6 +73,11 @@ namespace Spine.Unity.Examples { Apply(); } + void OnDestroy () { + // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed + repackingOutput.DestroyGeneratedAssets(); + } + void Apply () { SkeletonAnimation skeletonAnimation = GetComponent(); Skeleton skeleton = skeletonAnimation.Skeleton; @@ -124,12 +127,14 @@ namespace Spine.Unity.Examples { repackedSkin.AddSkin(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders) repackedSkin.AddSkin(customSkin); // Include your new custom skin. - // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed - if (runtimeMaterial) - Destroy(runtimeMaterial); - if (runtimeAtlas) - Destroy(runtimeAtlas); - repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin. + // Note: materials and textures returned by previous GetRepackedSkin() calls behave like 'new Texture2D()' + // and need to be destroyed. + repackingOutput.DestroyGeneratedAssets(); + AtlasUtilities.RepackAttachmentsSettings settings = AtlasUtilities.RepackAttachmentsSettings.Default; + settings.UseSourceMaterialsFrom(skeletonAnimation.SkeletonDataAsset); + settings.maxAtlasSize = 1024; + repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", settings, ref repackingOutput); // Pack all the items in the skin. + skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton. if (bbFollower != null) bbFollower.Initialize(true); } else { diff --git a/spine-unity/Assets/Spine/package.json b/spine-unity/Assets/Spine/package.json index 7ace57b2a..2c6d0ada0 100644 --- a/spine-unity/Assets/Spine/package.json +++ b/spine-unity/Assets/Spine/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-unity", "displayName": "spine-unity Runtime", "description": "This plugin provides the spine-unity runtime core and examples. Spine Examples can be installed via the Samples tab.", - "version": "4.3.45", + "version": "4.3.46", "unity": "2018.3", "author": { "name": "Esoteric Software",