欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Unity中使用TexturePacker优化图集

发布时间:2024/3/26 编程问答 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Unity中使用TexturePacker优化图集 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

转自:https://blog.csdn.net/Happy_zailing/article/details/87190150

TexturePacker是一款非常牛逼的打图集软件,是一款收费软件。这是它的官网:https://www.codeandweb.com/texturepacker,大家可以下到最新版本。即便如此,网上还是有很多破解版的(虽然不是最新版的),但是已经够用了。 
其实Unity本身也有图集打包功能,但Unity并不想让开发者知道图集这个概念。开发的过程中,如果你不想知道图集的存在,Unity完全可以帮你隐藏得很深,但其实它还在帮你打图集。对于这种打图集方式,我很不放心。我还是想像传统那样的自己打图集,并且能看到打好的图集在哪里,长什么样,但又能被Unity所识别,即在Unity里能用。那TP就可以派上用场了。这是我用的3.0.3版本的TP。大家可以到这里下载 
:http://pan.baidu.com/s/1bgjlHs。关于TP的用法,本文并不做介绍。本文要做的就是利用TP的命令行来实现完全自动化的图集打包。 
打开命令行工具并CD到TexturePacker的安装目录,输入 TexturePacker –help,会出现该版本的TP的一些命令行参数。 

下面我们写代码来用上这些命令行参数。写代码之前先看看我们要打成图集的小图们:

好的,上代码:

  • #if UNITY_EDITOR

  • using UnityEngine;

  • using System.IO;

  • using UnityEditor;

  • using System.Text;

  • using System.Diagnostics;

  • public class CommandBuild : Editor

  • {

  •  
  • [MenuItem("Tools/SpritesPacker/CommandBuild")]

  • public static void BuildTexturePacker()

  • {

  • //选择并设置TP命令行的参数和参数值

  • string commandText = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode None --pack-mode Best --algorithm MaxRects --max-size 2048 --size-constraints POT --disable-rotation --scale 1 {2}" ;

  • string inputPath = string.Format ("{0}/Images", Application.dataPath);//小图目录

  • string outputPath = string.Format ("{0}/TexturePacker", Application.dataPath);//用TP打包好的图集存放目录

  • string[] imagePath = Directory.GetDirectories (inputPath);

  • for (int i = 0; i < imagePath.Length; i++)

  • {

  • UnityEngine.Debug.Log (imagePath [i]);

  • StringBuilder sb = new StringBuilder("");

  • string[] fileName = Directory.GetFiles(imagePath[i]);

  • for (int j = 0; j < fileName.Length; j++)

  • {

  • string extenstion = Path.GetExtension(fileName[j]);

  • if (extenstion == ".png")

  • {

  • sb.Append(fileName[j]);

  • sb.Append(" ");

  • }

  • UnityEngine.Debug.Log("fileName [j]:" + fileName[j]);

  • }

  • string name = Path.GetFileName(imagePath [i]);

  • string outputName = string.Format ("{0}/TexturePacker/{1}/{2}", Application.dataPath,name,name);

  • string sheetName = string.Format("{0}/SheetsByTP/{1}", Application.dataPath, name);

  • //执行命令行

  • processCommand("D:\\Program Files (x86)\\CodeAndWeb\\TexturePacker\\bin\\TexturePacker.exe", string.Format(commandText, sheetName, sheetName, sb.ToString()));

  • }

  • AssetDatabase.Refresh();

  • }

  •  
  • private static void processCommand(string command, string argument)

  • {

  • ProcessStartInfo start = new ProcessStartInfo(command);

  • start.Arguments = argument;

  • start.CreateNoWindow = false;

  • start.ErrorDialog = true;

  • start.UseShellExecute = false;

  •  
  • if(start.UseShellExecute){

  • start.RedirectStandardOutput = false;

  • start.RedirectStandardError = false;

  • start.RedirectStandardInput = false;

  • } else{

  • start.RedirectStandardOutput = true;

  • start.RedirectStandardError = true;

  • start.RedirectStandardInput = true;

  • start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;

  • start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;

  • }

  •  
  • Process p = Process.Start(start);

  • if(!start.UseShellExecute)

  • {

  • UnityEngine.Debug.Log(p.StandardOutput.ReadToEnd());

  • UnityEngine.Debug.Log(p.StandardError.ReadToEnd());

  • }

  •  
  • p.WaitForExit();

  • p.Close();

  • }

  •  
  • }

  • #endif


  • 运行 Tools/SpritesPacker/CommandBuild,并查看SheetsByTP目录下打包好的图集:

    发现得到了两个文件,一个就是打包好的大图,及一个XML格式的配置文件:


    但这样子的图集,unity并不能用,还需要做进一步的处理。这里先说下原理。在Unity里,一张图片的格式很多

    不同格式有着不同的用途(UGUI用的是Sprite的格式),当我们往Unity里导入图片时,这张图片是什么格式由TextureImporter类决定,大家可以去看看这个类的API。然后我们再在Unity里随便找到一张图片的 .meta文件,用你喜欢的文本编辑器打开它:

  • fileFormatVersion: 2

  • guid: 542eed357a373ac4186621aa69a5ae78

  • timeCreated: 1456884951

  • licenseType: Pro

  • TextureImporter:

  • fileIDToRecycleName: {}

  • serializedVersion: 2

  • mipmaps:

  • mipMapMode: 0

  • enableMipMap: 1

  • linearTexture: 0

  • correctGamma: 0

  • fadeOut: 0

  • borderMipMap: 0

  • mipMapFadeDistanceStart: 1

  • mipMapFadeDistanceEnd: 3

  • bumpmap:

  • convertToNormalMap: 0

  • externalNormalMap: 0

  • heightScale: .25

  • normalMapFilter: 0

  • isReadable: 0

  • grayScaleToAlpha: 0

  • generateCubemap: 0

  • cubemapConvolution: 0

  • cubemapConvolutionSteps: 8

  • cubemapConvolutionExponent: 1.5

  • seamlessCubemap: 0

  • textureFormat: -1

  • maxTextureSize: 2048

  • textureSettings:

  • filterMode: -1

  • aniso: -1

  • mipBias: -1

  • wrapMode: -1

  • nPOTScale: 1

  • lightmap: 0

  • rGBM: 0

  • compressionQuality: 50

  • allowsAlphaSplitting: 0

  • spriteMode: 0

  • spriteExtrude: 1

  • spriteMeshType: 1

  • alignment: 0

  • spritePivot: {x: .5, y: .5}

  • spriteBorder: {x: 0, y: 0, z: 0, w: 0}

  • spritePixelsToUnits: 100

  • alphaIsTransparency: 0

  • textureType: -1

  • buildTargetSettings: []

  • spriteSheet:

  • sprites: []

  • spritePackingTag:

  • userData:

  • assetBundleName:

  • assetBundleVariant:


  • 里边有个spriteSheet的项,在 TextureImporter的API里对应 


    发现是一个SpriteMetaData的数组。在看看SpriteMetaData有什么

    我们只要把这些信息填好就行。上代码:

  • #if UNITY_EDITOR

  • using UnityEngine;

  • using System;

  • using System.IO;

  • using UnityEditor;

  • using System.Collections.Generic;

  • using System.Xml;

  • public class MySpritesPacker : Editor

  • {

  • [MenuItem("Tools/SpritesPacker/TexturePacker")]

  • public static void BuildTexturePacker()

  • {

  • string inputPath = string.Format("{0}/SheetsByTP/", Application.dataPath);

  • string[] imagePath = Directory.GetFiles(inputPath);

  • foreach (string path in imagePath)

  • {

  • if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG")

  • {

  • string sheetPath = GetAssetPath(path);

  • Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(sheetPath);

  • Debug.Log(texture.name);

  • string rootPath = string.Format("{0}/TexturePacker/{1}", Application.dataPath,texture.name);

  • string pngPath = rootPath + "/" + texture.name + ".png";

  • TextureImporter asetImp = null;

  • Dictionary<string, Vector4> tIpterMap = new Dictionary<string,Vector4>();

  • if (Directory.Exists(rootPath))

  • {

  • if(File.Exists(pngPath))

  • {

  • Debug.Log("exite: " + pngPath);

  • asetImp = GetTextureIpter(pngPath);

  • SaveBoreder(tIpterMap, asetImp);

  • File.Delete(pngPath);

  • }

  • File.Copy(inputPath + texture.name + ".png", pngPath);

  • }

  • else

  • {

  • Directory.CreateDirectory(rootPath);

  • File.Copy(inputPath + texture.name + ".png", pngPath);

  • }

  • AssetDatabase.Refresh();

  • FileStream fs = new FileStream(inputPath + texture.name + ".xml", FileMode.Open);

  • StreamReader sr = new StreamReader(fs);

  • string jText = sr.ReadToEnd();

  • fs.Close();

  • sr.Close();

  • XmlDocument xml = new XmlDocument();

  • xml.LoadXml(jText);

  • XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");

  • WriteMeta(elemList, texture.name, tIpterMap);

  • }

  • }

  • AssetDatabase.Refresh();

  • }

  • //如果这张图集已经拉好了9宫格,需要先保存起来

  • static void SaveBoreder(Dictionary<string,Vector4> tIpterMap,TextureImporter tIpter)

  • {

  • for(int i = 0,size = tIpter.spritesheet.Length; i < size; i++)

  • {

  • tIpterMap.Add(tIpter.spritesheet[i].name, tIpter.spritesheet[i].border);

  • }

  • }

  •  
  • static TextureImporter GetTextureIpter(Texture2D texture)

  • {

  • TextureImporter textureIpter = null;

  • string impPath = AssetDatabase.GetAssetPath(texture);

  • textureIpter = TextureImporter.GetAtPath(impPath) as TextureImporter;

  • return textureIpter;

  • }

  •  
  • static TextureImporter GetTextureIpter(string path)

  • {

  • TextureImporter textureIpter = null;

  • Texture2D textureOrg = AssetDatabase.LoadAssetAtPath<Texture2D>(GetAssetPath(path));

  • string impPath = AssetDatabase.GetAssetPath(textureOrg);

  • textureIpter = TextureImporter.GetAtPath(impPath) as TextureImporter;

  • return textureIpter;

  • }

  • //写信息到SpritesSheet里

  • static void WriteMeta(XmlNodeList elemList, string sheetName,Dictionary<string,Vector4> borders)

  • {

  • string path = string.Format("Assets/TexturePacker/{0}/{1}.png", sheetName, sheetName);

  • Texture2D texture = AssetDatabase.LoadAssetAtPath <Texture2D>(path);

  • string impPath = AssetDatabase.GetAssetPath(texture);

  • TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;

  • SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];

  • for (int i = 0, size = elemList.Count; i < size; i++)

  • {

  • XmlElement node = (XmlElement)elemList.Item(i);

  • Rect rect = new Rect();

  • rect.x = int.Parse(node.GetAttribute("x"));

  • rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));

  • rect.width = int.Parse(node.GetAttribute("width"));

  • rect.height = int.Parse(node.GetAttribute("height"));

  • metaData[i].rect = rect;

  • metaData[i].pivot = new Vector2(0.5f, 0.5f);

  • metaData[i].name = node.GetAttribute("name");

  • if (borders.ContainsKey(metaData[i].name))

  • {

  • metaData[i].border = borders[metaData[i].name];

  • }

  • }

  • asetImp.spritesheet = metaData;

  • asetImp.textureType = TextureImporterType.Sprite;

  • asetImp.spriteImportMode = SpriteImportMode.Multiple;

  • asetImp.mipmapEnabled = false;

  • asetImp.SaveAndReimport();

  • }

  •  
  • static string GetAssetPath(string path)

  • {

  • string[] seperator = { "Assets" };

  • string p = "Assets" + path.Split(seperator, StringSplitOptions.RemoveEmptyEntries)[1];

  • return p;

  • }

  •  
  • }

  •  
  • internal class TextureIpter

  • {

  • public string spriteName = "";

  • public Vector4 border = new Vector4();

  • public TextureIpter() { }

  • public TextureIpter(string spriteName, Vector4 border)

  • {

  • this.spriteName = spriteName;

  • this.border = border;

  • }

  • }

  • #endif


  • 然后点击 Tools/SpritesPacker/TexturePacker,看看 TexturePacker文件夹,会发现

    这样Unity就用了,为了验证能用,我们把原来的小图和在TP里打包的图集都删掉,然后创建一些Image,用上我们打包好的图集里的图片。 


    到此就成功地在Unity用上了用TP打包好的图集了。 
    图片用到的九宫格信息也在这里哦!

    -----------------------------------------------------------修改相关bug-----------------------------------------------------

    在上文代码中

  • using System.IO;

  • using UnityEditor;

  • using System.Collections.Generic;

  • using System.Xml;

  • public class MySpritesPacker : Editor

  • {

  • [MenuItem("Tools/SpritesPacker/TexturePacker")]

  • public static void BuildTexturePacker()

  • {

  • string inputPath = string.Format("{0}/SheetsByTP/", Application.dataPath);

  • string[] imagePath = Directory.GetFiles(inputPath);

  • foreach (string path in imagePath)

  • {

  • if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG")

  • {

  • string sheetPath = GetAssetPath(path);

  • Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(sheetPath);

  • Debug.Log(texture.name);

  • string rootPath = string.Format("{0}/LuaFramework/Art/Atlas/{1}", Application.dataPath, texture.name);

  • string pngPath = rootPath + "/" + texture.name + ".png";

  • //TextureImporter asetImp = null;

  • Dictionary<string, Vector4> tIpterMap = new Dictionary<string, Vector4>();

  • if (Directory.Exists(rootPath))

  • {

  • if (File.Exists(pngPath))

  • {

  • Debug.Log("exite: " + pngPath);

  • //因为用TexturePacker打图集的时候软件并不会记录原图的九宫信息,所以保存的九宫信息都是默认的(0,0,0,0),此处注释掉,在生成图集meta文件的时候重新添加九宫信息

  • //asetImp = GetTextureIpter(pngPath);

  • //SaveBoreder(tIpterMap, asetImp);

  • File.Delete(pngPath);

  • }

  • File.Copy(inputPath + texture.name + ".png", pngPath);

  • }

  • else

  • {

  • Directory.CreateDirectory(rootPath);

  • File.Copy(inputPath + texture.name + ".png", pngPath);

  • }

  • 上文中保存的是打出图集的九宫切图,原图各个小图的九宫切图信息丢失

    故在生成图集的meta文件的时候去读取了原图的meta文件的九宫切图信息,添加到图集的meta文件中(图集的meta文件中有记录各个文件的信息的数组)

  • //写信息到SpritesSheet里

  • static void WriteMeta(XmlNodeList elemList, string sheetName, Dictionary<string, Vector4> borders)

  • {

  • string path = string.Format("Assets/LuaFramework/Art/Atlas/{0}/{1}.png", sheetName, sheetName);

  • Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);

  • string impPath = AssetDatabase.GetAssetPath(texture);

  • TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;

  • SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];

  • for (int i = 0, size = elemList.Count; i < size; i++)

  • {

  • XmlElement node = (XmlElement)elemList.Item(i);

  • Rect rect = new Rect();

  • rect.x = int.Parse(node.GetAttribute("x"));

  • rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));

  • rect.width = int.Parse(node.GetAttribute("width"));

  • rect.height = int.Parse(node.GetAttribute("height"));

  • metaData[i].rect = rect;

  • metaData[i].pivot = new Vector2(0.5f, 0.5f);

  • metaData[i].name = node.GetAttribute("name");

  • //读取源文件的meta文件,获取spriteBorder九宫信息,写进图集中

  • string _path = string.Format("{0}/LuaFramework/Art/{1}/{2}.png", Application.dataPath,sheetName, node.GetAttribute("name"));

  • Vector4 _border = GetTextureIpter(_path).spriteBorder;

  • //if (borders.ContainsKey(metaData[i].name))

  • //{

  • metaData[i].border = _border;

  • //}

  •  
  • }

  • asetImp.spritesheet = metaData;

  • asetImp.textureType = TextureImporterType.Sprite;

  • asetImp.spriteImportMode = SpriteImportMode.Multiple;

  • asetImp.mipmapEnabled = false;

  • asetImp.SaveAndReimport();

  • }

  • 下图是原图的九宫切图信息

    下图是图集meta文件中各个小图的信息

    总结

    以上是生活随笔为你收集整理的Unity中使用TexturePacker优化图集的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。