Unity资源管理读书笔记Assets, Objects and serialization

英文网页地址https://unity3d.com/de/learn/tutorials/topics/best-practices/assets-objects-and-serialization

1.1首先要理解Assets和 UnityEngine.Object.是两种不同的事物

Assets是磁盘上的文件,比如纹理,材质,FBX文件。

UnityEngine.Objects是一个Unity引擎使用的一个数据对象,代表资源的实例。比如网格,sprite,动画剪辑。前述每一个资源都是一个内置类型,继承自UnityEngine.Object。还有用户自定义的资源,就是 ScriptableObject ,  MonoBehaviour 。MonoBehaviour 引用一个MonoScript。

 

1.2 对象间的引用

每个资源都可能引用到其它资源。序列化时,每个引用都由两部分构成,文件GUID和本地ID。

文件GUID是资产文件的唯一标识,存在.meta文件中,当一个资产文件导入引擎时生成。

本地ID是用来区分一个Assets中的多个Objects的标识。

 

1.3为什么有文件GUID和本地ID

文件GUID实现了资产文件和磁盘位置的无关性。这样无论资产文件如何移动,只要让它的meta和它一起移动,那么引用都不会错乱

unity在一次运行中维护了一个路径到文件GUID的map。该map的每一项的生成是Assets加载或导入时生成。 Editor没有关闭的情况下,如果.meta掉了而Assets文件本身没有挪动,那么unity会生成一个一模一样的.meta。

如果.meta掉了而Editor没有开着,或者Assets文件路径变化了,但没有一起移动相应的.meta文件,那么Editor将为Assets生成出不一样的文件GUID。引用就丢失了。

 

1.4组合的Assets和importers

非原生的资源必须通过importers导入引擎。这些importers都在导入时被自动调用。

导入处理后,就会生成一个或多个UnityEngine.Objects。在编辑器中就可以展开一个父资产看到许多子资产。比如一个Texture下面可以看到很多的sprite。

导入过程会转资源格式到目标平台,并且会进行纹理压缩等操作。

导入后的资源存到了Library目录下。按文件GUID的前两位区分的子目录 Library/metadata/ folder


1.5序列化和实例

虽然有文件GUID和本地ID的机制,但并不好用,比如要比较查找这些ID时并不高效。因此unity在运行时生成了实例ID,即Instance ID。Unity维护了一个从文件GUID和本地ID到Instance ID的映射缓存.当一个Object加载到内存后,它们之间的引用是通过Instance ID来表示的.通过Instance ID来得到一个资源对象时,如果它已经在内存中,那么就直接返回这个资源对象,如果不在内存中,那么再通过文件GUID和本地ID去磁盘加载.

开始时Instance ID的映射缓存只包含场景引用的资源对象,以及Resources目录下的 所有对象.运行时导入新资源或从AssetBundles加载了对象,都会相应增加Instance ID缓存的条目.

卸载AssetBundle 时会删除掉Instance ID缓存中对应的条目.再次加载AssetBundle 时,unity会为其中的资源生成新的InstanceID.

 

注意在iOS下应用切后台时,如果资源对象所属的AssetBundle 被卸载了,那么unity可能就无法恢复这些资源.因为iOS可能会释放掉这部分内存.

 

1.6MonoScripts

MonoBehaviour 引用一个MonoScript。

而MonoScript包含三部分信息:程序集,类名,名字空间.


1.7 资源生命周期

UnityEngine.Object有两种方式被加载:一是被间接引用到了.另一种是被API显示加载,比如AssetBundle.LoadAsset.

加载后,Unity会为把任何文件GUID和本地ID的引用翻译成以Instance ID表示的引用.

在下面两个情况都满足的条件下,一次对Instance ID的引用会导致对象加载动作产生:

1. Instance ID引用的对象目前没有被加载

2. Instance ID对应的文件GUID和本地ID是有效的.

 

在三种情况下对象会被卸载:

1.  用Application.LoadLevel 强切场景(非additive 模式).或调用Resources.UnloadUnusedAssets.此时只会对非引用的对象进行卸载,被脚本引用或被其它对象引用的对象不会被卸载.

2.调用 Resources.UnloadAsset API.此时Instance ID缓存数据还在.任何对对象的引用都会导致资源对象重新加载.

3. 调用  AssetBundle.Unload(true)API.这是对来自于AssetBundle的资源的强力卸载.因为它会删除Instance ID缓存数据

 

4. 调用  AssetBundle.Unload(false)API.unity对已经加载的资源对象不销毁,但是它会删除Instance ID缓存数据,因此如果这些对象不在内存后(比如iOS系统行为),unity不能根据引用自动地加载它们.只能重新加载AssetBundle.

 

1.8 加载复杂层次结构的GameObject

加载复杂层次结构的GameObject时,CPU时间消耗主要以下四点:

1.读磁盘

2.建立Transforms的父子关系

3.初始化GameObject和组件

4.调用Awake

 

生成一个GameObject有两种方式,要么读盘加载,要么直接从内存复制出一个对象.这两种方式来说,2,3,4点的消耗都一样.只有第1条的消耗不同.而如果一个GameObject的层次结构越复杂,它从磁盘加载的速度越慢.因此,要优化加载速度,可以简化GameObject的层次结构,然后对于重复的节点可以通过在内存中复制来生成.

 

在unity5.4中,生成一个GameObject时引擎会立即设置父节点.因此我们最好调用可设置父节点的GameObject.Instantiate重载函数来实例化,这可能会节约5~10%的时间

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值