NGUI所见即所得之UIAtlasMaker , UIAtlas (2)
本文的重点就是要将NGUI把多张图片打成一个图集(Atlas)的原理和过程研究下,学习下Unity提供的api和NGUI写的功能以及设计思想。
(原文链接)
其它链接:NGUI所见即所得之UIRoot
NGUI所见即所得之UIWidget , UIGeometry & UIDrawCall
NGUI所见即所得之UIFont , UIFontMaker
NGUI所见即所得之UISprite & UILabel
NGUI所见即所得之UICamera
NGUI所见即所得之UIPanel
NGUI所见即所得之UITweener
NGUI所见即所得之UIAnchor & UIStretch
NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理
UIAtlas
在介绍UIAtlasMaker之前先看下,先看下UIAtlasMaker的产物——UIAtlas,在创建Sprite的时候都要指定UIAtlas,下面先对UIAtlas的代码:
// Material used by this atlas. Name is kept only for backwards compatibility, it used to be public.
[HideInInspector][SerializeField] Material material; // List of all sprites inside the atlas. Name is kept only for backwards compatibility, it used to be public.
[HideInInspector][SerializeField] List<UISpriteData> mSprites = new List<UISpriteData>(); // Size in pixels for the sake of MakePixelPerfect functions.
[HideInInspector][SerializeField] float mPixelSize = 1f; // Replacement atlas can be used to completely bypass this atlas, pulling the data from another one instead.
[HideInInspector][SerializeField] UIAtlas mReplacement; // Whether the atlas is using a pre-multiplied alpha material. -1 = not checked. 0 = no. 1 = yes.
int mPMA = -;
可以很惊奇的发现UIAtlas的成员变量竟然极其精简,就只有:Material material; UISpriteDatat的List mSprites; 每个像素的大小 mPixelSize 这个跟UIWidget的像素大小应该是类似的, UIAtlas mReplacement; 这个目前只能望文生义,虽然知道是用来替换UIAtlas,但好像没有发现哪里会有用到,在UISprite的那里只是选择不同的UIAtlas而不是替换UIAtlas本身,就暂且搁置, 最后一个是mPMA这个是pre-multiplied的像素存储技术,大致了解下,好像是把alpha的值存储在每个颜色的RGB中去已达到节省存储空间的技术,想要了解更多可以自行google下。
接着看UIAtlas,接下来就是把属性的{get,set} 以及几个函数,也很简单,主要就是属性改变,就调用MakeAsDirty()函数,下面看下这个函数的前面一部分:
public void MarkAsDirty ()
{
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(gameObject);
#endif
if (mReplacement != null) mReplacement.MarkAsDirty(); UISprite[] list = NGUITools.FindActive<UISprite>(); for (int i = , imax = list.Length; i < imax; ++i)
{
UISprite sp = list[i]; if (CheckIfRelated(this, sp.atlas))
{
UIAtlas atl = sp.atlas;
sp.atlas = null;
sp.atlas = atl;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(sp);
#endif
}
}
……
}
可以看出这个函数其实就是更新以replacemet和this为UIAtlas的UISprite的UIAtlas,就是这么简单。
UISpriteData
在UIAtlas中有GetSprite()和GetListOfSprites(),其中GetSprite返回的UISpriteData,让人不得不猜想UISpriteData就是UISprite中的图片,但其实它只是一个结构体:
public class UISpriteData
{
public string name = "Sprite";
public int x = ;
public int y = ;
public int width = ;
public int height = ; public int borderLeft = ;
public int borderRight = ;
public int borderTop = ;
public int borderBottom = ; public int paddingLeft = ;
public int paddingRight = ;
public int paddingTop = ;
public int paddingBottom = ;
}
一看这些成员变量,就会感觉很熟悉,这不是就是UI组件的基本熟悉么,可以进一步看下UIInspectorEditor界面,就更加确信了,而且Border其实用在SliceSprite的,至于Padding就是空白不显示区域,而且x,y,width,height其实该图片就是在UIAtlas上Rect区域。

也就是说,UISpriteData根本没有实际记录图片的像素信息,而只是记录图片在UIAtlas生成的那张大图的坐标,宽度和高度,以及图片拉伸的一些信息(Border,Padding)。
UIAtlasMaker
从前面的分析,可以大概知道UIAtlasMaker的原理:把多张图片合并成一张大图,记录每张图片的在生成的大图的坐标和大小。下面将使用介绍算法那种思路把UIAtlasMakder的工作流程描述清楚。
在详细介绍之前,UIAtlasMakder定义了UISpriteEntry这个类:
class SpriteEntry : UISpriteData
{
// Sprite texture -- original texture or a temporary texture
public Texture2D tex; // Whether the texture is temporary and should be deleted
public bool temporaryTexture = false;
}
只是在UISpriteData基础上扩展了一个Texture2D tex的成员变量,那么这个类到底做什么用呢?通过分析代码可以知道:UISpriteEntry是UISpriteData和Texture2D的中间体,是Texture2D和UISpriteData转化的载体,就提过程下面会有引人。
UIAtlasMaker的工作流程:
1)选择图片or图集,函数:void OnSelectAtlas (Object obj) 和 List<Texture> GetSelectedTextures ()
2)导入选择图片的Texture2D,函数:static List<Texture2D> LoadTextures (List<Texture> textures)
3)将Texture2D转出UISpriteEntry,函数:static List<SpriteEntry> CreateSprites (List<Texture> textures) ,这个函数中包括了2)的步骤
3)打包成大图片并生成UISpriteData,函数:static bool PackTextures (Texture2D tex, List<SpriteEntry> sprites),这个函数提供两种打包方式:1.NGUI自己实现类UITextPacker,2.Unity3D提供的api
4)释放UISpriteEntry,函数:static void ReleaseSprites (List<SpriteEntry> sprites),主要是通过NGUITools.Destroy销毁纹理,最后调用Resources.UnloadUnusedAssets();,这个趁机告诉我们Unity中资源销毁的方法,一个不能少哈。
static void ReleaseSprites (List<SpriteEntry> sprites)
{
foreach (SpriteEntry se in sprites)
{
if (se.temporaryTexture)
{
NGUITools.Destroy(se.tex);
se.tex = null;
}
}
Resources.UnloadUnusedAssets();
}
差不多就是这样子,其他就是一些功能操作:add,replace,delete,udpate,extract。
这样看来,把UIAtlas分析清楚,掌握UIAtlasMaker的原理应该不难,当然里面有很多细节,使用很多api:AssetDatabase,Texture,SelectedObject以及NGUI自己封装的一些函数。
小结:
UIAtlas虽然在使用NGUI过程中用的太多了,但是经过上面的分析,其实不是很难,个人觉得还没有UIRoot(NGUI所见即所得之UIRoot)的难以驾驭,即使UIRoot很短很单一。这里说下D.S.Qiu的关于快速学习的一点体会:古人有云,“工欲善其事,必先利其器”,NGUI最为一个工具,要使用好它,就要充分掌握它, 换句话说就要懂它,当然还可以从中偷到很多师——功能的具体实现和代码逻辑的设计,其实一直觉得我对细节都不求甚解,会用就可以走路了,又不用自己写一个NGUI,当然细节都能掌握就更完美了。已经到凌晨一点了,先写这么多,有补充在加。
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
转载请在文首注明出处:http://dsqiu.iteye.com/blog/1967088
NGUI所见即所得之UIAtlasMaker , UIAtlas (2)的更多相关文章
- NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理
NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 之 ...
- NGUI的原理机制:深入剖析UIPanel,UIWidget,UIDrawCall底层原理
这是我去搜狐畅游面试时,面试官问的一个问题.问NGUI的机制原理是什么?就是这个插件是根据什么写出来的.当时没答上来,下面是我从转载过来的,可以研究研究. 之前项目中用的NGUI的版本是3.0.7 f ...
- iteye上总结的编程精华资源
原文:http://www.iteye.com/magazines/130 博客是记录学习历程.分享经验的最佳平台,多年以来,各路技术大牛在ITeye网站上产生了大量优质的技术文章,并将系列文章集结成 ...
- Unity3D-NGUI动态加载图片
NGUI提供了很方便的UIAtlas,其主要作用是改进DrawCall,把众多图片整合在一张贴图上,由于UNITY3D简单易用的好处,所以只是用原生的GUI很容易忽视DrawCall的问题,所以NGU ...
- NGUI出现Shader wants normals, but the mesh UIAtlas doesn't have them
NGUI出现Shader wants normals, but the mesh UIAtlas doesn't have them,没有网格法线,打开UI Root上 UIPanel组建上的 Nor ...
- Unity3d通用工具类之NGUI图集分解
---恢复内容开始--- Unity3d通用工具类之NGUI图集分解 由于最近需要一些美术资源吗,但是无奈自己不会制作UI,所以就打算去网上的项目中直接找几张可以使用的贴图资源. 但是发现这些资源已经 ...
- NGUI 之 不为人知的 NGUITools
static public float soundVolume该属性是全局音效播放音量,按照文档说是用于NGUITools.PlaySound(),那也就意味着我的游戏如果用NGUITools.Pla ...
- 【转】NGUI研究院之为什么打开界面太慢(十三)
NGUI打开界面太慢了,起初一直以为是unity的问题,最近经过我的全面测试我发现这和unity没有关系.一般一个比较复杂的界面大概需要150个GameObject 或者 UISprite .我用N ...
- NGUI Atlas, Atlas Type Reference
在NGUI中,通过创建图集及引用图集,实际使用时指定引用图集而非具体图集本身,可以创建多语言,或高配低配版本资源包. NGUI Atlashttp://www.cnblogs.com/answerwi ...
随机推荐
- Extjs3笔记 fbar
在项目中会遇到在grid右下角显示合计之类的显示. 之前使用过的方式: 1.用width强制顶过去. 2.利用css来控制. 弊端: 利用第一种方式:导致调整窗口大小时会导致合计不能根据窗体的大小变化 ...
- Java与Android开发环境配置以及遇到的问题解决
0 概述 所有文章涉及的下载地址在文章下方会有汇总,所有软件的版本最好与系统版本一致 建议安装安卓开发软件至一个目录中,以方便查找 1 Java环境配置 1.1 JDK下载: 据说JDK6用的比较多, ...
- -exec和|xargs
注意xargs会被空格割裂,所以遇到带有空格的文件名就不好办了,解决方法是使用-print0 例如:删除.目录下30天之前的.png文件 -type f -name rm 或者使用-exec:删除.目 ...
- 字符串 前篇 ---- sizeof()操作符和strlen()库函数
本文不是研究sizeof(), strlen() 的深奥定义和原理,我们不会在理论上太过钻牛角尖.希望读这篇文章的你,也不要太过抠概念(不要拘泥于语法).我们只做 实用意义 的介绍和讨论. 在介绍字符 ...
- java_object的具体使用--上帝
就我们所知道的,java中有子类和父类,子类由于继承父类而形成,那么父类还有没有父类呢?答案是有了,父类的父类就是object类,一切父类都继承了它,那么根据继承的属性,每一个子类都有一个object ...
- springmvc学习(二)——使用RequestMapper请求映射
本次内容是@RequestMapping,后面会有实例代码 Spring MVC 使用 @RequestMapping 注解为控制器指定可以处理哪些 URL 请求在控制器的类定义及方法定义处都可标注@ ...
- const char*、char*、char* const、char[]、string的区别
1.const char* p: p is a pointer to const char(char const* p 一样) 意思就是不能通过p指针来修改p指向的内容(但是内容可以修改). 2. ...
- Openjudge/Poj 1183 反正切函数的应用
1.链接地址: http://bailian.openjudge.cn/practice/1183 http://poj.org/problem?id=1183 2.题目: 总时间限制: 1000ms ...
- mysql show processlist 显示mysql查询进程
1.进入mysql/bin目录下输入mysqladmin processlist; 2.启动mysql,输入show processlist; 如果有 SUPER 权限,则可以看到全部的线程,否则,只 ...
- Mysql表操作
查看表结构: 可以使用describe或show create table语句查看表的结构: describe表名; Show create table 表名; 修改表名: Alter table 旧 ...