Unity学习-优化_图集归类以及Unity和texturepackter的动态批处理

(前面是废话,可以略过,分割线下面是内容)

前两天研究完了LOD 和 MipMap  感觉很简单,实现起来不用多久。

但是发现如果将某些功能运用在商业代码上,为了提高效率,要做很多前期工作。

这几天一直在学习游戏开发优化方面的技巧,感觉都很片面,实际的LOD 和 MipMap这些功能只有在一些需要大量摄像机移动的场景用的比较多

固定视角或者是锁死深度的游戏  其实这方面用的比较少,而目前市场上大部分都是锁死视角或者锁死深度的游戏。。

于是这两天重点去研究了下关于图集的优化。

优化图集的目的是为了降低DrawCall的额外产生,在设计UI框架的时候,就要考虑好文件结构和图集的处理方式了。

我目前工作的 项目采用的是通用作法,把每个模块单独打一个图集,特别大的背景图则单独加载。

在学习打图集的过程中,有一个很深刻的感受。。我发现了很多没听说过的技术,牵根连枝,拔一根萝卜带起一片泥那种。

我想学打图集以及图集的规划和设计,但是项目模块很多,跟UI,图片产生关系的工作量都非常的大。如果人工做这件事情需要消耗很大的精力

所以我在想学图集的时候,不得不学习怎么自动化打图集。于是看起了项目工程里面的TexturePacker工具。非常方便,于是也想做一个。

在学习TexturePacker的时候,又发现了一个问题,我想要批量打包,TexturePacker只能做到把碎图拼成一张整图,如果想要在项目里面方便的使用

远远不够,人力操作还有一大部分没有被提取出来。但是由于是试用期,很多代码没有公开给我,只能自己网上查办法了。

于是又找到了UnityEditor 自动化切图的办法。其实这两步是必不可少的,只是开始无知,想不上去。以为是那个软件自带的全面功能。。

然后我就从学习怎么自动切图开始了。

好了废话说完了,下面开始介绍自动化打包图集的流程

=======================================分割线===============================================

全自动打图集的流程:

美术规范:建议给碎图,因为我们需要用texturepacker来整合碎图,这个工具最方便的地方是提供了碎图的同时还提供了每个碎图在大图的具体坐标、大小信息

1:是使用texutrepacker 进行统一化整理和获取碎图的信息 是一个xx.png 和一个xxplist.txt的文本 文本采用json的方式方便我们读写,这里用批处理的方式将文件自动存放指定的文件夹

使用到的功能:

 Selection.GetFiltered(typeof(Object), SelectionMode.Assets)

获取我们想要的路劲。

然后使用C#的Process类,进行批处理操作,代替人工导出

        Process process = new Process();//创建一个进程
        ProcessStartInfo info = new ProcessStartInfo("texturepacker");     //设置进程信息
        string arguments = "Assets/Test/";//这里推荐安装好texturepacker的同学使用cmd命令行查看下他的使用参数,这里就是我们要填的api参数  这个代表我们选着导哪个文件夹的图片
        arguments += " --sheet " + path + "/"+selecteFileName+".png";//导出目录.png
        arguments += " --data "  + path+ "/"+selecteFileName+".txt"; //导出目录.txt
        arguments += " --format unity";  //选择格式(平台)
        arguments += " --max-size 1024"; //选择texture的maxsize
        arguments += " --disable-rotation";//关闭旋转,据说不关闭可能会碰到坑,还没研究这个参数
        info.Arguments = arguments;
        info.CreateNoWindow = false;//打开运行窗口(装逼用的 就是一个dos界面 和bat那种一样)
        UnityEngine.Debug.Log(info.Arguments);
        Process.Start(info);//开始执行

2:开始切分整图

这里面也是2个步骤

一个是解析json

一个是设置TextureImporter属性,因为自动化,就要取代所有的手动操作,所以每一步都需要用代码实现

这里涉及的就是TextureImporter这个类 和  SpriteMetaData 这个类了(如果不是我今天需求这个,这俩东西我听都没听说过 = =)

由于这里的代码比较多,就不贴局部代码了,下面我会贴整个代码的。

切分的时候有一个坑,因为texturepacker是用的左上角为坐标原点,而Unity的gui使用的是左下角为左边点,如果不做坐标系转换的话,切出来的东西根本不能用。

我想过很多种方式,目前好像只有这种方式涉及的代码量比较少,不过开销稍微大一点,不过考虑到编辑器只是开发人员会使用,也无关紧要啦~

如果要坐标转换的话,需要知道texture的原始大小。因为我们默认导入的比例都是1:1的,不会缩放。所以不用考虑缩放带来的误差。但是TextureImporter里面完全没有关于texture大小的属性

这时候我想过2种方案

第一种是不用获取texture大小, 在texture的面板上面是有EditorSprite这个功能的,这个可以根据alpha值做自动切分。本着Unity有的功能,必然会有API接口的想法,掘地三尺,还是没找到。

在以前的版本倒是有一个接口,但是现在已经弃用了。找了半天之后放弃了。

第二种是找到获取texture大小的办法,想了很多,最后使用AssetDatabase.LoadAssetAtPath<Texture2D>(path)这个方式来加载我想要的这个texture ,然后读他的size属性来取值。。

算是野路子了= =不过学习到了新的一种加载资源的方式,不过这个方式只能在editor模式使用。

接下来我们就可以做偏移  对齐小图片啦~

3:切分整图。根据项目需求创建prefab作为图集的载体

这样一来就可以大功告成啦!

其实代码不多,开发难度也不大,就是在Unity整个知识体系里面比较冷门(个人觉得),所以整个过程中大部分时间是在找资料。

因为完全是自己爬坑,没有去照着公司项目代码去做,所以遇到了非常多的问题,也都克服了,所以写的有点啰嗦。。

下面是完整代码,没有做安全判定,因为完全是测试流程而已。

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Threading;
using System.Diagnostics;

public class BuildAtlas : MonoBehaviour
{
    static string path;
    static object wwwLoad;
    [MenuItem("打包图集/打包")]
    static void CreatTexturePacker()
    {

        Object[] arrayList = Selection.GetFiltered(typeof(Object), SelectionMode.Assets);//获取用户选择的物体
        for (int i = 0; i < arrayList.Length; i++)
        {

            //用户如果选择多个文件夹路径则进行多次处理
            path = AssetDatabase.GetAssetPath(arrayList[i]);
            CallTexturePacker("test", path);
            if (path != "")
            {
                float offest = GetTextureHeight(path + "/json.png");
                TextureImporter textureImporter = AssetImporter.GetAtPath(path + "/json.png") as TextureImporter;
                textureImporter.textureType = TextureImporterType.Sprite;
                textureImporter.spriteImportMode = SpriteImportMode.Multiple;
                textureImporter.GetDefaultPlatformTextureSettings();
                WirteSpriteJsonToSheet(textureImporter, path + "/json.txt", offest);
                textureImporter.SaveAndReimport();
            }
        }
    }

    /// <summary>
    /// 获取目标texture的高度做偏移
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    static float GetTextureHeight(string path)
    {

        UnityEngine.Debug.Log(path);
        Texture2D texture2D = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
        return texture2D.width;
    }

    /// <summary>
    /// 读取json文件
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    static string GetJson(string path)
    {
        FileStream stream = new FileStream(path, FileMode.Open);

        StreamReader sr = new StreamReader(stream);

        string str = sr.ReadToEnd();
        sr.Dispose();
        sr.Close();
        return str;

    }

    /// <summary>
    /// 将TextureImprot按文本位置切分
    /// </summary>
    /// <param name="TIP"></param>
    /// <param name="txtPath"></param>
    /// <param name="offset"></param>
    static void WirteSpriteJsonToSheet(TextureImporter TIP, string txtPath, float offset)
    {
        string spriteInfoArry = GetJson(txtPath);
        Hashtable hashInfo = spriteInfoArry.hashtableFromJson();//转换成哈希表(很奇怪,转成arryList会返回空,可能是不太会用吧)

        Hashtable frames = (Hashtable)hashInfo["frames"];
        List<SpriteMetaData> Sprites = new List<SpriteMetaData>();
        foreach (DictionaryEntry item in frames)
        {
            SpriteMetaData sprite = new SpriteMetaData();
            Hashtable mTable = (Hashtable)item.Value; //每一步都要转成hashtable才能进行取值操作,得到的结果也要转成hashtable
            Hashtable frame = (Hashtable)mTable["frame"];//取到位置信息
            sprite.name = item.Key.ToString();

            //这里要注意,json提供的坐标文件 坐标系是左上角为原点 UNITY的gui坐标系是左下角为原点,所以我们要做坐标转换,左上和左下,只需要做Y轴的转换即可
            //转换的偏移量要和实际的texture对应,所以我们需要获取实际的Texture大小
            sprite.rect = new Rect((float)frame["x"], offset - (float)frame["y"] - (float)frame["h"], (float)frame["w"], (float)frame["h"]);//位置信息赋值
            Hashtable spriteSourceSize = (Hashtable)mTable["spriteSourceSize"];
            Hashtable pviot = (Hashtable)mTable["sourceSize"];
            sprite.border = new Vector4((float)spriteSourceSize["x"], (float)spriteSourceSize["y"], (float)spriteSourceSize["w"], (float)spriteSourceSize["h"]); //边框大小
            sprite.alignment = 6;//Center = 0, TopLeft = 1, TopCenter = 2, TopRight = 3, LeftCenter = 4, RightCenter = 5, BottomLeft = 6, BottomCenter = 7, BottomRight = 8, Custom = 9.
            sprite.pivot = new Vector2((float)pviot["w"], (float)pviot["h"]);
            Sprites.Add(sprite);
        }
        TIP.spritesheet = Sprites.ToArray();
        TIP.SaveAndReimport();
        UnityEngine.Debug.Log("转换成功");
    }

    static void CallTexturePacker(string selecteFileName,string path)
    {

        Process process = new Process();
        ProcessStartInfo info = new ProcessStartInfo("texturepacker");
        string arguments = "Assets/Test/";
        arguments += " --sheet " + path + "/"+selecteFileName+".png";
        arguments += " --data "  + path+ "/"+selecteFileName+".txt";
        arguments += " --format unity";
        arguments += " --pack-mode Best";
        arguments += " --algorithm MaxRects";
        arguments += " --max-size 1024";
        arguments += " --trim-mode None";
        arguments += " --disable-rotation";
        arguments += " --size-constraints  POT";
        info.Arguments = arguments;
        info.CreateNoWindow = false;
        UnityEngine.Debug.Log(info.Arguments);
        Process.Start(info);
    }
}

  

原文地址:https://www.cnblogs.com/leixuan111/p/10733436.html

时间: 2024-10-02 19:42:24

Unity学习-优化_图集归类以及Unity和texturepackter的动态批处理的相关文章

Unity学习-优化_卡顿原因定位以及优化方案

除了Unity的一些组件优化技巧之外,更多的细节处于代码层面上 最近学习优化,看到一篇文章,写的很详细,从底层原理到我们 的实际处理,都有一些非常好的建议,可以推荐给小伙伴们看看 https://www.jianshu.com/p/289de89a6609 ===========如何定位程序的哪一个环节产生了过大的开销============ 使用Uinty的Profiler工具,可以比较精准快速的定位程序的哪一个位置产生了大开销 首先在build setting里面勾选Autoconnect

Unity学习-优化_LOD技术

最近项目的需求被策划那边卡流程了,在大改,没什么事情做 于是开始自己找点不会的东西来学一下了 这里会记录我得学习经历,采用费曼学习法来提示自己 LOD Unity会根据摄像机的远近距离调整模型的显示效果 其中效果是需要我们去提供的 在给物体添加LOD Group组件之后  会出现有4块颜色不同的区域,这里就是告诉我们的层级权重关系 在scene视图下我们可以拖动上面的摄像机小图标可以预览实际效果 其中分为4个层级 1:LOD0 100% 权重显示 2:LOD1 60% 权重显示 3:LOD2 3

Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻译 Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译 Unity性能优化(3)-官方教程Optimizing garbage collection in Uni

Unity性能优化(2)-官方文档简译

本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 简介 如果游戏运行缓慢,卡顿,我们知道游戏存在性能问题.在我们尝试解决问题前,需要先知道引起问题的原因.不同问题需要不同的解决方案.如果我们靠猜测或者其他项目的经验去解决问题,那么我们可能会浪费很多时间,甚至使得问题更严重. 这时我们需要性能分析,性能分析程序测量游戏运行时的各个方面性能.通过性能分析工具,我们能够透过

Unity内存优化(贴图层面)

聊聊近况: 距离上一篇文章已经过了好久,主要原因是我懒了.公司项目也到了开始优化的阶段,上网找的资料,看过了就忘.还是想把它整理一下,写出来.其实我说的东西,网上都有,我只是搬运工而已. 贴图压缩: Android平台使用ETC1格式压缩. 目前主流的Android机型基本都支持ETC1格式压缩.但ETC1只能支持非Alpha通道的图片压缩. 所以一般把RGB和ALPHA分离出来,r值,g值,b值从RGB图获取,a值从Alpha图里获取. 随着OPENGL ES 3.0的发布,etc2也出了,支

Unity内存优化

对项目优化有很多,如:mesh合并,减少DrawCall和模型骨骼以及物理计算,合并材质球,优化代码等等. 优化: 1. 更新不透明贴图的压缩格式为ETC 4bit,因为android市场的手机中的GPU有多种,每家的GPU支持不同的压缩格式,但他们都兼容ETC格式. 2.对于透明贴图,我们只能选择RGBA 16bit 或者RGBA 32bit. 3.减少FPS 在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS

Unity内存优化技术测试案例

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解>电子工业出版社等. CSDN视频网址:http://edu.csdn.net/lecturer/144 Unity引擎优化技术,无非涉及到三点:CPU优化,GPU优化,内存优化. 先谈谈内存优化:大概可以分成三大部分: 1. Unity3D内部的内存 2. Mono的托管内存 3. 引入的DLL或者第

【Unity 3D】学习笔记二十八:unity工具类

unity为开发者提供了很多方便开发的工具,他们都是由系统封装的一些功能和方法.比如说:实现时间的time类,获取随机数的Random.Range( )方法等等. 时间类 time类,主要用来获取当前的系统时间. using UnityEngine; using System.Collections; public class Script_04_13 : MonoBehaviour { void OnGUI() { GUILayout.Label("当前游戏时间:" + Time.t

【Unity 3D】学习笔记二十六:unity游戏脚本(六)

在3D游戏世界中,任何一个游戏对象在创建的时候都会附带Transform(变换)组件,并且该组件是无法删除的,也不应该删除.在unity中,Transform面板一共有3个属性: Position  (位置) Rotation(旋转) Scale(缩放) 这三个值都是用来调整游戏对象在游戏界面中的位置,状态等相关参数. Position  (位置) 任何一个游戏对象的三维坐标都保存在Vector3容器中,该容器记录对象在X轴,Y轴,Z轴的坐标.一旦Vector33容器中的坐标发生变化,那么Sce