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