unity学习-优化_图集归类以及unity和texturepackter的动态批处理(代码片段)

leixuan111 leixuan111     2023-03-15     133

关键词:

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

前两天研究完了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);
    

  

 

图集优化

  听说UGUI使用比较方便,今天特地来学习一下。用过NGUI的都知道,在2D界面添加图片背景,是不可以直接将资源里面的图片拖给对象做为背景的,需要先将图片资源打成图集,然后从图集里面去选择自己的图标。但是在UGUI里... 查看详情

unity_ugui学习图集与使用

   UGUI的Atlas和NGUI的Atlas的区别,NGUI是必须先打出图集然后才能开始做界面。这一点很烦,因为始终都要去考虑你的UI图集。比如图集会不会超1024,图集该如何来规划等等。而UGUI的原理则是,让开发者彻底模糊... 查看详情

[unity优化]unity性能优化

...围内。Q:粒子系统的Prewarm主要用来做什么的,这个怎么优化呢?ParticleSystem.Prewarm的出现表示当前加载、激活或者首次渲染的粒子系统开启了"Prewarm"选项,而开启该选项的粒子系统在加载后会立即执行一次完整的模拟。... 查看详情

unity之图集属性详解和代码示例--拓展一键自动打包图集工具(代码片段)

Unity之图集属性详解和代码示例--拓展一键自动打包图集工具一,图集的相关概念1.1图集的定义1.2图集的意义二,图集的属性介绍2.1属性面板2.2格式处理2.3代码操作三,拓展--打包图集工具3.1图片存放策略3.2图集打包逻... 查看详情

unity之图集属性详解和代码示例--拓展一键自动打包图集工具(代码片段)

Unity之图集属性详解和代码示例--拓展一键自动打包图集工具一,图集的相关概念1.1图集的定义1.2图集的意义二,图集的属性介绍2.1属性面板2.2格式处理2.3代码操作三,拓展--打包图集工具3.1图片存放策略3.2图集打包逻... 查看详情

unity自定义atlas图集实现加载图集中的小图

Unity没有提供加载图集里面小图的API,下面是我学习框架课程(因为这个框架课程没有封装LoadAllAsset的方法)所学到的加载方法。1.封装UIAtlas类,保存序列化的图集 /******************* * Title:CW_FrameWark * Author:CW *&... 查看详情

unity学习笔记:如何设置tilemap碰撞体,以及如何优化碰撞体计算bychutianbo

我们在用Tilemap场景搭建时,常常需要某些Tile具有碰撞的功能,那么我们该怎么实现这个功能呢?我们先得给Tilemap一个专门的Collider组件,即TilemapCollider2D:然后我们在TilePalette中找到对应的Tile对象,将需... 查看详情

带有一些旋转元素的 Unity 导入图集

】带有一些旋转元素的Unity导入图集【英文标题】:Unityimportatlaswithsomerotatedelements【发布时间】:2022-01-1912:01:17【问题描述】:我有一个精灵图集,其中包含从1到10的数字图像,但7和8是水平旋转的。我如何才能正常地统一导入... 查看详情

unity学习-优化_lod技术

...于是开始自己找点不会的东西来学一下了这里会记录我得学习经历,采用费曼学习法来提示自己 LODUnity会根据摄像机的远近距离调整模型的显示效果其中效果是需要我们去提供的 在给物体添加LODGroup组件之后 会出现... 查看详情

unity图集方案对比

查看详情

unity-spriteatlas图集(代码片段)

title:unity-SpriteAtlas图集categories:Unity3dtags:[unity,图集]date:2022-01-1014:29:00comments:falsemathjax:truetoc:trueunity-SpriteAtlas图集前篇SpriteAtlas-https://docs.unity3d.com/cn/2018.4/Manual/class-Spri 查看详情

关于unity中的ugui优化,你可能遇到这些问题

...用NGUI时,我们通常会将很多小图打成一个大的图集,以优化内存和DrawCall。而在UGUI时代,UI所使用的Image必须是Sprite;Unity提供了SpritePacker。它的工作流程和UGUIAtlasPaker有较大的差别。在UnityAsset中,我们压根看不到图集的存在。... 查看详情

unity图集资源引用查找(代码片段)

图集使用TexturePacker打出来的,图集用的时间旧了,不确定哪些资源是被prefab引用,哪些是不需要用的,最近查看unity工具顺便写了个简单脚本,检测图集资源被prefab引用情况原理很简单,图集中的每个子对... 查看详情

unity图集资源引用查找(代码片段)

图集使用TexturePacker打出来的,图集用的时间旧了,不确定哪些资源是被prefab引用,哪些是不需要用的,最近查看unity工具顺便写了个简单脚本,检测图集资源被prefab引用情况原理很简单,图集中的每个子对... 查看详情

unity优化篇|优化专栏《导航帖》,全面学习unity优化技巧,让我们的unity技术上升一个档次(代码片段)

文章目录📢前言🎬Unity实用优化技巧专栏《导航帖》1️⃣优化的基本概念/意义2️⃣脚本代码优化策略3️⃣UI常规优化逻辑4️⃣物理引擎优化篇5️⃣图形渲染优化篇6️⃣批处理的优势7️⃣艺术类资源优化8️⃣内存管... 查看详情

siki_unity_2-4_ugui_unity5.1ui案例学习(代码片段)

Unity2-4UGUIUnity5.1UI案例学习任务1:UGUI简介什么是GUI:  游戏的开始菜单  RPG游戏的菜单栏、侧边栏和功能栏(比如背包系统、任务列表等)  设计用来控制移动的虚拟杆和攻击按钮UGUI:  Unity内置  GUI也可以用第三方... 查看详情

unity协程运行时的监控和优化

我是快乐的搬运工:http://gulu-dev.com/post/perf_assist/2016-12-20-unity-coroutine-optimizing#toc_0------------------------------------------------------------------------分割线------------------------------------ 查看详情

unity2019有啥新特性?怎么激活unity2019最新版

...网络插件)制作独立游戏。参考技术AUnity对于个人开发者学习和使用都是免费的,建议注册后使用会更方便,其商店里的众多免费资源也需要登录后才能下载使用。作为个人开发者我们更重要的是如何去进行更有效的学习,建议... 查看详情