Unity 之 TexturePacker(TP) 的应用

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文件中各个小图的信息

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: TexturePacker是一个常用的纹理打包工具,可用于将多个小图标或纹理合并到一个大的纹理图集中,并生成相应的元数据和配置。UnityPackage是Unity游戏引擎的一种打包文件格式,可以包含游戏资源、脚本、场景等。 当我们使用TexturePacker创建纹理图集后,可以将生成的文件保存为UnityPackage格式,以便在Unity中轻松导入和使用。这个导入器UnityPackage是一种用于将TexturePacker文件导入到Unity项目中的工具。 使用TexturePacker导出的UnityPackage文件可以包含纹理图集的图片文件以及与之相关的配置、元数据等。导入UnityPackage时,Unity会自动解析并展示出这些资源,方便我们在游戏中使用。 通过导入器UnityPackage,我们可以一键导入TexturePacker生成的图集资源到Unity项目中,省去了手动添加、配置的繁琐过程。导入后,我们可以在Unity编辑器中直接引用这些纹理图集,用于设置游戏的界面、角色、地图等。同时,由于TexturePacker图集制作工具通常会自动优化纹理,减小纹理的内存占用和渲染性能消耗,因此使用TexturePacker导入的图集也能为我们的游戏性能提供一定的优化。 总而言之,texturepacker importer unitypackage是一个用于将TexturePacker生成的纹理图集资源导入到Unity项目中的工具,可以方便地使用TexturePacker提供的纹理打包功能,并优化游戏性能。 ### 回答2: TexturePacker Importer UnityPackage是一种Unity引擎中的插件,用于导入纹理图集Texture Atlas)制作工具TexturePacker生成的文件。TexturePacker是一款广泛使用的纹理图集制作工具,它可以将多个小纹理合并成一个大纹理,并且在文件中记录了每个小纹理的位置和大小等信息。 通过使用TexturePacker Importer UnityPackage,我们可以将TexturePacker生成的文件轻松导入到Unity项目中。一旦导入成功,我们就可以在Unity中使用TexturePacker生成的纹理图集。 使用TexturePacker Importer UnityPackage有以下几个优点: 1. 减少内存占用:通过将多个小纹理合并成一个大纹理图集,可以减少游戏加载时所需的内存占用,提高游戏的性能。 2. 提高渲染效率:在游戏中使用纹理图集可以减少渲染调用次数,提高游戏的渲染效率。 3. 管理方便:通过导入TexturePacker生成的文件,我们可以在Unity中直接使用纹理图集,并且可以很方便地管理和更新纹理。 使用TexturePacker Importer UnityPackage的步骤如下: 1. 下载和安装TexturePacker Importer UnityPackage插件。 2. 将TexturePacker生成的文件拖放到Unity项目的Assets文件夹中。 3. 在Unity项目中选择导入的文件,并设置导入的属性。 4. 导入成功后,我们可以在Unity的资源管理器中看到导入的纹理图集文件,可以在游戏中使用它。 总之,TexturePacker Importer UnityPackage是一个非常有用的插件,可以方便地导入和使用TexturePacker生成的纹理图集,提高游戏的性能和渲染效率。 ### 回答3: TexturePacker是一款功能强大的纹理打包软件,它可以将多张纹理打包成一张大的纹理集,以减少游戏中的纹理数量,优化游戏性能。Importer UnityPackage是Unity游戏引擎中的一种导入方式,可以将其他软件创建的资源文件以Unity可识别的格式导入到Unity项目中。 TexturePacker Importer UnityPackage就是将TexturePacker打包好的纹理集以UnityPackage的方式导入到Unity项目中使用。这样做的好处是可以方便地管理纹理资源,减少项目中的文件数量,并且可以提高游戏的运行效率。 使用TexturePacker Importer UnityPackage的方法很简单。首先,将TexturePacker导出的纹理集文件保存为UnityPackage格式。然后,在Unity编辑器中选择“Assets”菜单下的“Import Package”选项,从弹出的对话框中选择导入的UnityPackage文件,点击“Import”按钮进行导入。 导入完成后,可以在Unity项目中看到导入的纹理集资源。可以将这个纹理集应用到游戏对象的材质上,也可以在脚本中通过代码使用纹理集中的纹理。在使用纹理集的过程中,可以根据需求进行调整纹理的显示方式,例如裁剪、平铺、重复等。 TexturePacker Importer UnityPackage的使用可以大大简化游戏开发过程中的纹理处理工作,减少纹理资源的浪费和加载开销,提高游戏的性能和画面质量。因此,在开发Unity游戏时,推荐使用TexturePacker Importer UnityPackage来管理和使用纹理资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值