Sfoglia il codice sorgente

[unity] GetRepackedSkin allows to include normal maps (and other texture properties) during repacking via optional parameter. Closes #1519.

Harald Csaszar 6 anni fa
parent
commit
fc0a5df0db

+ 93 - 28
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs

@@ -310,16 +310,37 @@ namespace Spine.Unity.AttachmentTools {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
-		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time. No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
-		public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, bool useOriginalNonrenderables = true) {
-			return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource, useOriginalNonrenderables);
+		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
+		/// comprised of all the regions from the original skin.</summary>
+		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
+		/// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
+		/// <param name="additionalTexturePropertyIDsToCopy">Optional additional textures (such as normal maps) to copy while repacking.
+		/// To copy e.g. the main texture and normal maps, pass 'new int[] { Shader.PropertyToID("_BumpMap") }' at this parameter.</param>
+		/// <param name="additionalOutputTextures">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
+		/// this array will be filled with the resulting repacked texture for every property,
+		/// just as the main repacked texture is assigned to <c>outputTexture</c>.</param>
+		public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture,
+			int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
+			bool useOriginalNonrenderables = true, bool clearCache = false,
+			int[] additionalTexturePropertyIDsToCopy = null, Texture2D[] additionalOutputTextures = null) {
+
+			return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture,
+				maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource,
+				clearCache, useOriginalNonrenderables, additionalTexturePropertyIDsToCopy, additionalOutputTextures);
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
-		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time. No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
-		public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true) {
+		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
+		/// comprised of all the regions from the original skin.</summary>
+		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
+		/// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
+		public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture,
+			int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
+			Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true,
+			int[] additionalTexturePropertyIDsToCopy = null, Texture2D[] additionalOutputTextures = null) {
+
+			outputTexture = null;
+
 			if (o == null) throw new System.NullReferenceException("Skin was null");
 			if (o == null) throw new System.NullReferenceException("Skin was null");
 			var skinAttachments = o.Attachments;
 			var skinAttachments = o.Attachments;
 			var newSkin = new Skin(newName);
 			var newSkin = new Skin(newName);
@@ -333,7 +354,12 @@ namespace Spine.Unity.AttachmentTools {
 
 
 			// Collect all textures from the attachments of the original skin.
 			// Collect all textures from the attachments of the original skin.
 			var repackedAttachments = new List<Attachment>();
 			var repackedAttachments = new List<Attachment>();
-			var texturesToPack = new List<Texture2D>();
+			int numTextureParamsToRepack = 1 + (additionalTexturePropertyIDsToCopy == null ? 0 : additionalTexturePropertyIDsToCopy.Length);
+			additionalOutputTextures = (additionalTexturePropertyIDsToCopy == null ? null : new Texture2D[additionalTexturePropertyIDsToCopy.Length]);
+			List<Texture2D>[] texturesToPackAtParam = new List<Texture2D>[numTextureParamsToRepack];
+			for (int i = 0; i < numTextureParamsToRepack; ++i) {
+				texturesToPackAtParam[i] = new List<Texture2D>();
+			}
 			var originalRegions = new List<AtlasRegion>();
 			var originalRegions = new List<AtlasRegion>();
 			int newRegionIndex = 0;
 			int newRegionIndex = 0;
 
 
@@ -350,7 +376,10 @@ namespace Spine.Unity.AttachmentTools {
 						regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
 						regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
 					} else {
 					} else {
 						originalRegions.Add(region);
 						originalRegions.Add(region);
-						texturesToPack.Add(region.ToTexture()); // Add the texture to the PackTextures argument
+						for (int i = 0; i < numTextureParamsToRepack; ++i) {
+							Texture2D regionTexture = (i == 0 ? region.ToTexture() : region.ToTexture(texturePropertyId : additionalTexturePropertyIDsToCopy[i - 1]));
+							texturesToPackAtParam[i].Add(regionTexture); // Add the texture to the PackTextures argument
+						}
 						existingRegions.Add(region, newRegionIndex); // Add the region to the dictionary of known regions
 						existingRegions.Add(region, newRegionIndex); // Add the region to the dictionary of known regions
 						regionIndexes.Add(newRegionIndex); // Store the region index for the eventual new attachment.
 						regionIndexes.Add(newRegionIndex); // Store the region index for the eventual new attachment.
 						newRegionIndex++;
 						newRegionIndex++;
@@ -363,26 +392,37 @@ namespace Spine.Unity.AttachmentTools {
 				}
 				}
 			}
 			}
 
 
-			// Fill a new texture with the collected attachment textures.
-			var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
-			newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
-
-			if (texturesToPack.Count > 0) {
-				var sourceTexture = texturesToPack[0];
-				newTexture.CopyTextureAttributesFrom(sourceTexture);
-			}
-			newTexture.name = newName;
-			var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
-
 			// Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
 			// Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
 			var newMaterial = new Material(shader);
 			var newMaterial = new Material(shader);
 			if (materialPropertySource != null) {
 			if (materialPropertySource != null) {
 				newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
 				newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
 				newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
 				newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
 			}
 			}
-
 			newMaterial.name = newName;
 			newMaterial.name = newName;
-			newMaterial.mainTexture = newTexture;
+
+			Rect[] rects = null;
+			for (int i = 0; i < numTextureParamsToRepack; ++i) {
+				// Fill a new texture with the collected attachment textures.
+				var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
+				newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
+				var texturesToPack = texturesToPackAtParam[i];
+				if (texturesToPack.Count > 0) {
+					var sourceTexture = texturesToPack[0];
+					newTexture.CopyTextureAttributesFrom(sourceTexture);
+				}
+				newTexture.name = newName;
+				var rectsForTexParam = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
+				if (i == 0) {
+					rects = rectsForTexParam;
+					newMaterial.mainTexture = newTexture;
+					outputTexture = newTexture;
+				}
+				else {
+					newMaterial.SetTexture(additionalTexturePropertyIDsToCopy[i - 1], newTexture);
+					additionalOutputTextures[i - 1] = newTexture;
+				}
+			}
+
 			var page = newMaterial.ToSpineAtlasPage();
 			var page = newMaterial.ToSpineAtlasPage();
 			page.name = newName;
 			page.name = newName;
 
 
@@ -404,7 +444,6 @@ namespace Spine.Unity.AttachmentTools {
 			if (clearCache)
 			if (clearCache)
 				AtlasUtilities.ClearCache();
 				AtlasUtilities.ClearCache();
 
 
-			outputTexture = newTexture;
 			outputMaterial = newMaterial;
 			outputMaterial = newMaterial;
 			return newSkin;
 			return newSkin;
 		}
 		}
@@ -413,7 +452,16 @@ namespace Spine.Unity.AttachmentTools {
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 		}
 		}
 
 
-		static Dictionary<AtlasRegion, Texture2D> CachedRegionTextures = new Dictionary<AtlasRegion, Texture2D>();
+		struct IntAndAtlasRegionKey {
+			int i;
+			AtlasRegion region;
+
+			public IntAndAtlasRegionKey(int i, AtlasRegion region) {
+				this.i = i;
+				this.region = region;
+			}
+		}
+		static Dictionary<IntAndAtlasRegionKey, Texture2D> CachedRegionTextures = new Dictionary<IntAndAtlasRegionKey, Texture2D>();
 		static List<Texture2D> CachedRegionTexturesList = new List<Texture2D>();
 		static List<Texture2D> CachedRegionTexturesList = new List<Texture2D>();
 
 
 		public static void ClearCache () {
 		public static void ClearCache () {
@@ -426,19 +474,22 @@ namespace Spine.Unity.AttachmentTools {
 
 
 		/// <summary>Creates a new Texture2D object based on an AtlasRegion.
 		/// <summary>Creates a new Texture2D object based on an AtlasRegion.
 		/// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
 		/// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
-		public static Texture2D ToTexture (this AtlasRegion ar, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) {
+		public static Texture2D ToTexture (this AtlasRegion ar, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
+			int texturePropertyId = 0) {
+
 			Texture2D output;
 			Texture2D output;
 
 
-			CachedRegionTextures.TryGetValue(ar, out output);
+			IntAndAtlasRegionKey cacheKey = new IntAndAtlasRegionKey(texturePropertyId, ar);
+			CachedRegionTextures.TryGetValue(cacheKey, out output);
 			if (output == null) {
 			if (output == null) {
-				Texture2D sourceTexture = ar.GetMainTexture();
+				Texture2D sourceTexture = texturePropertyId == 0 ? ar.GetMainTexture() : ar.GetTexture(texturePropertyId);
 				Rect r = ar.GetUnityRect();
 				Rect r = ar.GetUnityRect();
 				int width = (int)r.width;
 				int width = (int)r.width;
 				int height = (int)r.height;
 				int height = (int)r.height;
 				output = new Texture2D(width, height, textureFormat, mipmaps) { name = ar.name };
 				output = new Texture2D(width, height, textureFormat, mipmaps) { name = ar.name };
 				output.CopyTextureAttributesFrom(sourceTexture);
 				output.CopyTextureAttributesFrom(sourceTexture);
 				AtlasUtilities.CopyTexture(sourceTexture, r, output);
 				AtlasUtilities.CopyTexture(sourceTexture, r, output);
-				CachedRegionTextures.Add(ar, output);
+				CachedRegionTextures.Add(cacheKey, output);
 				CachedRegionTexturesList.Add(output);
 				CachedRegionTexturesList.Add(output);
 			}
 			}
 
 
@@ -577,6 +628,20 @@ namespace Spine.Unity.AttachmentTools {
 			return material.mainTexture as Texture2D;
 			return material.mainTexture as Texture2D;
 		}
 		}
 
 
+		/// <summary>
+		/// Convenience method for getting any texture of the material of the page of the region by texture property name.</summary>
+		static Texture2D GetTexture (this AtlasRegion region, string texturePropertyName) {
+			var material = (region.page.rendererObject as Material);
+			return material.GetTexture(texturePropertyName) as Texture2D;
+		}
+
+		/// <summary>
+		/// Convenience method for getting any texture of the material of the page of the region by texture property id.</summary>
+		static Texture2D GetTexture (this AtlasRegion region, int texturePropertyId) {
+			var material = (region.page.rendererObject as Material);
+			return material.GetTexture(texturePropertyId) as Texture2D;
+		}
+
 		static void CopyTextureAttributesFrom(this Texture2D destination, Texture2D source) {
 		static void CopyTextureAttributesFrom(this Texture2D destination, Texture2D source) {
 			destination.filterMode = source.filterMode;
 			destination.filterMode = source.filterMode;
 			destination.anisoLevel = source.anisoLevel;
 			destination.anisoLevel = source.anisoLevel;