tag打图下的图集预览

因为新的项目(Unity4.7的版本环境)使用UI2DSprite的缘故,Atlas的build方式改成了tag的方式,图集也不再实时可见,每次打图优化图集的时间成本变得比较高,没办法,懒癌又起。。。

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Linq;

public class PreviewTextureAtlasWinEditor : EditorWindow
{
	private SortedDictionary<string, List<string>> texTagPathMap = new SortedDictionary<string, List<string>>();
	private List<Texture2D> texLst = new List<Texture2D>();
	private string textureAtlasTagToPreview = "";
	private bool needRefresh = false;
	private float scaleRate = 1f;

	private float minScaleRate = 0.3f;
	private float maxScaleRate = 2f;

	private static PreviewTextureAtlasWinEditor win;
	[MenuItem("AtlasOptimize/图集预览 %#p", false, 10)]
	public static void PreviewTextureAtlas()
	{
		win = GetWindow<PreviewTextureAtlasWinEditor>(true, "预览图集", true);
		win.Show();

		win.refreshTagMap();
	}

	private int lastSelectedIndex = 0;
	private string[] tagArr;
	private bool useTag;
	void OnGUI()
	{
		EditorGUILayout.BeginHorizontal();
		needRefresh = EditorGUILayout.Toggle("ForceRefresh:", needRefresh);
		useTag = EditorGUILayout.Toggle("UseTag:", useTag);

		if(useTag && tagArr != null && tagArr.Length != 0)
		{
			lastSelectedIndex = EditorGUILayout.Popup("AtlasTag", lastSelectedIndex, tagArr);
			textureAtlasTagToPreview = tagArr[lastSelectedIndex];
		}
		else
		{
			textureAtlasTagToPreview = EditorGUILayout.TextField("当前搜索图集:", textureAtlasTagToPreview);
		}

		EditorGUILayout.EndHorizontal();

		if (GUILayout.Button("预览图集")) 
		{
			findEnd = false;
			findTexWithTag(textureAtlasTagToPreview);
		}
		if(findEnd)
		{
			float tLeft = 0f;
			float tTop = 70f;
			int tWidth = Mathf.IsPowerOfTwo(previewAtlas.width) ? previewAtlas.width : Mathf.NextPowerOfTwo(previewAtlas.width);
			int tHeight = Mathf.IsPowerOfTwo(previewAtlas.height) ? previewAtlas.height : Mathf.NextPowerOfTwo(previewAtlas.height);
			EditorGUI.DrawTextureTransparent(new Rect(tLeft, tTop, tWidth * scaleRate, tHeight * scaleRate), previewAtlas);

			EditorGUILayout.BeginHorizontal();

			EditorGUILayout.BeginHorizontal();
			EditorGUILayout.LabelField("Width:", GUILayout.Width(45));
			EditorGUILayout.LabelField(tWidth.ToString(), GUILayout.Width(60));
			EditorGUILayout.EndHorizontal();

			EditorGUILayout.Space();

			EditorGUILayout.BeginHorizontal();
			EditorGUILayout.LabelField("Height:", GUILayout.Width(45));
			EditorGUILayout.LabelField(tHeight.ToString(), GUILayout.Width(60));
			EditorGUILayout.EndHorizontal();

			EditorGUILayout.Space();

			EditorGUILayout.BeginHorizontal();
			EditorGUILayout.LabelField("图元数:", GUILayout.Width(45));
			EditorGUILayout.LabelField(rectArr.Length.ToString(), GUILayout.Width(60));
			EditorGUILayout.EndHorizontal();
			
			EditorGUILayout.Space();

			scaleRate = EditorGUILayout.Slider("Scale", scaleRate, minScaleRate, maxScaleRate);
			EditorGUILayout.EndHorizontal();

			if (Event.current.type == EventType.MouseDown)
			{
				var tMousePos = Event.current.mousePosition;
				var tWinPos = win.position;
				Vector2 tPos = new Vector2((tMousePos.x - tLeft) / (tWidth * scaleRate), 1f - (tMousePos.y - tTop) / (tHeight * scaleRate));	//屏幕坐标系与uv坐标系

				for(int i = 0; i < rectArr.Length; i++)
				{
					if(rectArr[i].Contains(tPos))
					{
						var tAssetPath = texTagPathMap[textureAtlasTagToPreview][i];
						//EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(tAssetPath, typeof(Texture)));
						Selection.activeObject = AssetDatabase.LoadAssetAtPath(tAssetPath, typeof(Texture));
						break;
					}
				}
			}
			if (Event.current.type == EventType.ScrollWheel)
			{
				float tDeltaScale = Event.current.delta.y / 150f;
				scaleRate += tDeltaScale;
				if(scaleRate < minScaleRate)
				{
					scaleRate = minScaleRate;
				}
				if(scaleRate > maxScaleRate)
				{
					scaleRate = maxScaleRate;
				}
				win.Repaint();
			}
		}

		if (Event.current.type == EventType.KeyDown && tagArr != null && tagArr.Length != 0)
		{
			if(Event.current.keyCode == KeyCode.LeftArrow)
			{
				lastSelectedIndex--;
				if(lastSelectedIndex < 0)
				{
					lastSelectedIndex = tagArr.Length + lastSelectedIndex;
				}

				findEnd = false;
				win.Repaint();
			}
			else if(Event.current.keyCode == KeyCode.RightArrow)
			{
				lastSelectedIndex++;
				if(lastSelectedIndex >= tagArr.Length)
				{
					lastSelectedIndex = lastSelectedIndex - tagArr.Length;
				}

				findEnd = false;
				win.Repaint();
			}
		}
	}

	private void refreshTagMap()
	{
		var tAllTextureAssetsGUID = AssetDatabase.FindAssets("t:Texture").ToList<string>();
		string tAssetPath;
		TextureImporter tTexImporter;
		
		for(int i = 0; i < tAllTextureAssetsGUID.Count; i++)	//过滤
		{
			tAssetPath = AssetDatabase.GUIDToAssetPath(tAllTextureAssetsGUID[i]);
			for(int m = 0; m < filterString.Count; m++)
			{
				if(tAssetPath.Contains(filterString[m]))
				{
					tAllTextureAssetsGUID.RemoveAt(i);
					i--;
					break;
				}
			}
		}
		
		if(needRefresh || texTagPathMap.Count == 0)
		{
			needRefresh = false;
			texTagPathMap.Clear();
			
			//缓存
			for (int i = 0; i < tAllTextureAssetsGUID.Count; ++i) 
			{
				tAssetPath = AssetDatabase.GUIDToAssetPath(tAllTextureAssetsGUID[i]);
				tTexImporter = TextureImporter.GetAtPath(tAssetPath) as TextureImporter;
				
				if(string.IsNullOrEmpty(tTexImporter.spritePackingTag))
				{
					continue;
				}
				if(!texTagPathMap.ContainsKey(tTexImporter.spritePackingTag))
				{
					texTagPathMap[tTexImporter.spritePackingTag] = new List<string>();
				}
				texTagPathMap[tTexImporter.spritePackingTag].Add(tAssetPath);
				
				if (EditorUtility.DisplayCancelableProgressBar("CacheTagPathing", tAssetPath, ((i + 1) * 1.0f) / tAllTextureAssetsGUID.Count))
				{
					EditorUtility.ClearProgressBar();
					return;
				}
			}
			EditorUtility.ClearProgressBar();
			
			tagArr = texTagPathMap.Keys.ToArray();
		}
	}

	private bool findEnd = false;
	IList<string> filterString = new List<string>()
	{
		"Resources", "Editor",  "Plugins", //各种带过滤插件等
	};
	private void findTexWithTag(string _tag)
	{
		string tAssetPath;
		TextureImporter tTexImporter;

		refreshTagMap();

		if(texTagPathMap.ContainsKey(textureAtlasTagToPreview))
		{
			texLst.Clear();
			int tCount = texTagPathMap[textureAtlasTagToPreview].Count;
			bool[] tReadableArr = new bool[tCount];	//状态备份
			for(int i = 0; i < tCount; i++)
			{
				tAssetPath = texTagPathMap[textureAtlasTagToPreview][i];

				tTexImporter = TextureImporter.GetAtPath(tAssetPath) as TextureImporter;
				tReadableArr[i] = tTexImporter.isReadable;
				tTexImporter.isReadable = true;
				AssetDatabase.SaveAssets();
				AssetDatabase.ImportAsset(tAssetPath);	//强制刷新

				var tTex2D = AssetDatabase.LoadAssetAtPath(tAssetPath, typeof(Texture2D)) as Texture2D;
				texLst.Add(tTex2D);

				if (EditorUtility.DisplayCancelableProgressBar("PreviewAtlasing", tAssetPath, ((i + 1) * 1.0f) / tCount))
				{
					EditorUtility.ClearProgressBar();
					return;
				}
			}
			PackAtlas(texLst.ToArray());

			EditorUtility.ClearProgressBar();
			findEnd = true;

			//状态还原
			for(int i = 0; i < tCount; i++)
			{
				tAssetPath = texTagPathMap[textureAtlasTagToPreview][i];
				
				tTexImporter = TextureImporter.GetAtPath(tAssetPath) as TextureImporter;
				tTexImporter.isReadable = tReadableArr[i];
				AssetDatabase.SaveAssets();
				AssetDatabase.ImportAsset(tAssetPath);
			}
		}
	}

	private Texture2D previewAtlas = new Texture2D(1, 1);
	private Rect[] rectArr;
	public void PackAtlas(Texture2D[] _texArr, int _maxAtlasSize = 2048, int _padding = 0)
	{
		previewAtlas.Resize(1, 1);
		rectArr = previewAtlas.PackTextures(_texArr, _padding, _maxAtlasSize);
	}
}

  其中,做预览时,迫不得已,考虑到工程的股友问题已经成型,策划、美术对项目的修改标准已经稍乱,年底的时间,项目推进度、改bug,无奈,考虑到各种svn的状态修改与提交成本,只好先做状态备份预还原(此时时间会有所消耗),只好待项目版本告一段落,再开项目总结会议,重新再压一遍标准,标准若能严格执行,则又可省时一大步了。

  考虑到美术或策划或下面的某执行程序可能再增加新的资源时,希望预览到新增美术资源的打图效果及图集大小,于是再进一步:

public class PreviewTextureAtlasByHandWinEditor : EditorWindow
{
	private SortedDictionary<string, List<string>> texTagPathMap = new SortedDictionary<string, List<string>>();
	private List<Texture2D> texLst = new List<Texture2D>();
	private List<string> texPathLst = new List<string>();
	private float scaleRate = 1f;
	
	private float minScaleRate = 0.3f;
	private float maxScaleRate = 2f;
	
	private static PreviewTextureAtlasByHandWinEditor win;
	[MenuItem("AtlasOptimize/预览图集ByHand", false, 11)]
	public static void PreviewTextureAtlas()
	{
		win = GetWindow<PreviewTextureAtlasByHandWinEditor>(true, "预览图集", true);
		win.Show();
	}

	private Texture2D previewAtlas = new Texture2D(64, 64);
	private Rect[] rectArr = new Rect[0];
	public void PackAtlas(Texture2D[] _texArr, int _maxAtlasSize = 2048, int _padding = 0)
	{
		previewAtlas.Resize(1, 1);
		rectArr = previewAtlas.PackTextures(_texArr, _padding, _maxAtlasSize);
	}

	private Vector2 lastMousePos = Vector2.zero;
	private string selectAssetPath;
	void OnGUI()
	{
		float tLeft = 0f;
		float tTop = 20f;
		int tWidth = Mathf.IsPowerOfTwo(previewAtlas.width) ? previewAtlas.width : Mathf.NextPowerOfTwo(previewAtlas.width);
		int tHeight = Mathf.IsPowerOfTwo(previewAtlas.height) ? previewAtlas.height : Mathf.NextPowerOfTwo(previewAtlas.height);
		var tRect = new Rect(tLeft, tTop, tWidth * scaleRate, tHeight * scaleRate);
		EditorGUI.DrawTextureTransparent(tRect, previewAtlas);
		
		EditorGUILayout.BeginHorizontal();
		
		EditorGUILayout.BeginHorizontal();
		EditorGUILayout.LabelField("Width:", GUILayout.Width(45));
		EditorGUILayout.LabelField(tWidth.ToString(), GUILayout.Width(60));
		EditorGUILayout.EndHorizontal();
		
		EditorGUILayout.Space();
		
		EditorGUILayout.BeginHorizontal();
		EditorGUILayout.LabelField("Height:", GUILayout.Width(45));
		EditorGUILayout.LabelField(tHeight.ToString(), GUILayout.Width(60));
		EditorGUILayout.EndHorizontal();
		
		EditorGUILayout.Space();
		
		EditorGUILayout.BeginHorizontal();
		EditorGUILayout.LabelField("图元数:", GUILayout.Width(45));
		EditorGUILayout.LabelField(rectArr.Length.ToString(), GUILayout.Width(60));
		EditorGUILayout.EndHorizontal();
		
		EditorGUILayout.Space();
		
		scaleRate = EditorGUILayout.Slider("Scale", scaleRate, minScaleRate, maxScaleRate);
		EditorGUILayout.EndHorizontal();
		
		if (Event.current.type == EventType.MouseDown)
		{
			var tMousePos = Event.current.mousePosition;
			var tWinPos = win.position;
			Vector2 tPos = new Vector2((tMousePos.x - tLeft) / (tWidth * scaleRate), 1f - (tMousePos.y - tTop) / (tHeight * scaleRate));	//屏幕坐标系与uv坐标系
			
			for(int i = 0; i < rectArr.Length; i++)
			{
				if(rectArr[i].Contains(tPos))
				{
					selectAssetPath = texPathLst[i];
					//EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(selectAssetPath, typeof(Texture)));
					Selection.activeObject = AssetDatabase.LoadAssetAtPath(selectAssetPath, typeof(Texture));
					break;
				}
			}
		}
		if(!string.IsNullOrEmpty(selectAssetPath) && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Delete)
		{
			packTex(false, selectAssetPath);
			selectAssetPath = "";
			win.Repaint();
		}
		if (Event.current.type == EventType.ScrollWheel)
		{
			float tDeltaScale = Event.current.delta.y / 150f;
			scaleRate += tDeltaScale;
			if(scaleRate < minScaleRate)
			{
				scaleRate = minScaleRate;
			}
			if(scaleRate > maxScaleRate)
			{
				scaleRate = maxScaleRate;
			}
			win.Repaint();
		}

		if (Event.current.type == EventType.DragUpdated)	//DragExited触发时,鼠标位置会突变,暂未定位原因
		{
			lastMousePos = Event.current.mousePosition;
			DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
		}
		if (Event.current.type == EventType.DragExited)		//动态拖入添加,删除texture
		{
			if(!tRect.Contains(lastMousePos))
			{
				return;
			}
			if (DragAndDrop.paths != null && DragAndDrop.paths.Length > 0)
			{
				packTex(true, DragAndDrop.paths);		//todo: 过滤非texture、文件夹
				win.Repaint();
			}
		}
	}

	private void packTex(bool _isAppend, params string[] _assetPath)
	{
		bool tIsDirty = false;
		if(_isAppend)
		{
			for(int i = 0; i < _assetPath.Length; i++)
			{
				if(texPathLst.Contains(_assetPath[i]))
				{
					continue;
				}
				texPathLst.Add(_assetPath[i]);
				tIsDirty = true;
			}
		}
		else
		{
			for(int i = 0; i < _assetPath.Length; i++)
			{
				if(!texPathLst.Contains(_assetPath[i]))
				{
					continue;
				}
				texPathLst.Remove(_assetPath[i]);
				tIsDirty = true;
			}
		}
		if(!tIsDirty)
		{
			return;
		}

		bool[] tReadableState = new bool[texPathLst.Count];
		TextureImporter tTexImporter;
		texLst.Clear();
		for(int i = 0; i < texPathLst.Count; i++)
		{
			tTexImporter = TextureImporter.GetAtPath(texPathLst[i]) as TextureImporter;
			tReadableState[i] = tTexImporter.isReadable;    //状态备份
			tTexImporter.isReadable = true;
			AssetDatabase.SaveAssets();
			AssetDatabase.ImportAsset(texPathLst[i]);

			var tTex2D = AssetDatabase.LoadAssetAtPath(texPathLst[i], typeof(Texture2D)) as Texture2D;
			texLst.Add(tTex2D);
		}

		PackAtlas(texLst.ToArray());
		
		//还原状态
		for(int i = 0; i < texPathLst.Count; i++)
		{
			tTexImporter = TextureImporter.GetAtPath(texPathLst[i]) as TextureImporter;
			tTexImporter.isReadable = tReadableState[i];
			AssetDatabase.SaveAssets();
			AssetDatabase.ImportAsset(texPathLst[i]);
		}
	}
}

  为方便定位图集中的每个图元,两种工具都添加了图集到图元的索引(与unity自带的spritepacker相反,可以适当配合使用),都只是做了简单的预览优化之用,未突破unit已提供的不同打图选项设置。目前初版而已,待稍后标准重建,效率自然不成问题。

原文地址:https://www.cnblogs.com/wayland/p/8287171.html