首页 > 编程语言 > 详细

Unity资源Tree-资源组织

时间:2020-07-30 21:06:44      阅读:59      评论:0      收藏:0      [点我收藏+]

1 Assets

资产、资源。从Unity工程角度来讲Assets是程序工作目录;从产品最终呈现角度讲美术资源。

1.1 Assets目录

创建一项Unity工程时,各版本必然包含以下三个目录Assets、Libray、ProjectSetting。Packages是2018以后新增的。

技术分享图片

  • Assets
Unity工程实际的资源目录,所有项目用到的资源、代码、配置、库等原始资源只有放置在这个文件夹才会被Unity认可和处理。也有许多默认文件夹
 Editor:所有文件夹及其子目录都可以包含Editor并会被识别
 Editor default resources:编辑器用到的一些资源放在这里
 Gizmos:编辑器用到的一些资源放在这里。这俩个相似
 Plugins:一般放dll、so、sdk什么的
 Resources:工程打包会自动包含且不会压缩资源
 Standard Assets:在这个文件夹中的脚本会最先被编译,生成Assembly-CSharp-firstpass.dll
 StreamingAssets:打包会被拷贝进包体内,使用Application.streamingAssetsPath
 隐藏文件夹:以.开头的文件夹,编辑器不会识别。
 长时间不需要改动的脚本代码(比如各种插件代码)放入到Standard Assets文件夹下,会提升代码编译速度

  • Libray

存放了Unity编译后的信息。挑几个说明一下

技术分享图片

1 metadata存放了所有文件的序列化信息

技术分享图片

2 PackageCache存放了所有需要下载的Packages,这里与默认目录Packages不同,不同见下。

技术分享图片

3 PlayerDataCache存放的是Unity工程的界面布局、默认场景等信息

4 ScriptAssemblies这个好理解了,存放了所有编译后的脚本。其中Assembly-CSharp-firstpass.dll是当Assets目录下有Standard Assets且有脚本时就会生成

技术分享图片

5 ShaderCache这个好理解,每次启动场景时或者工程打包时会把依赖来的shader编译缓存

6 StateCache缓存了编辑器打开过的场景的配置序列化信息:技术分享图片技术分享图片

7 Temp一般是工程脚本版本升级、降级的缓存

8 assetDatabase3文件序列化了所有资源及其依赖。对于编辑器脚本AssetDataBase。


  • ProjectSetting
这个目录用于存放Unity的各种项目设定。

技术分享图片


  • Packages
这个目录是2018新增的,Unity自动生成的C#project是不能直接对这里进行管理和修改的。同时,Unity的引擎在工作目录里也是没法对它进行操作的,是一个只读的目录。

  只是存放了技术分享图片json文件,再工程启动会自动从外网下载。

因此,对于上面这种初次启动需要编译,最好对于各个平台都单独建立一个工程目录,切换不至于耗时等待太长时间。

1.2 Assets资产

也称为unity资产、美术资源。从外部导入unity工程,必然会经过一次序列化编译。任何一种资产导入Unity都给出一个回调及导入资源类型:

技术分享图片

技术分享图片

例如FBX文件,对应ModelImpoter。这样代码就可以用工具制定导入时资源配置,不至于人工手动修改。

2 Assets的类型及引用

Assets有非常多的类型:material材质球、texture纹理贴图、audio音频文件、FBX模型文件、animation各种动画、xml或json或lua文件等等。我们通常习惯于在Unity里进行增删改查拽甚至变更目录等各式各样的操作,但不管你在Unity引擎里如何操作(不包括删除),那些相关的引用都不会丢失。这是为什么呢?

2.1 Assets和Objects

Assets是Unity资产,指的是在Porject窗口人眼所见的各种文件;而Objects资产是对于程序代码而言:继承自UnityEngine.Object的对象,它是可序列化的数据,它是用以描述Asset资源的实例,它可以代表Mesh、Sprite、AudioClip or AnimationClip等等。注意有一种资源除外

  • ScriptableObject
用来提供给开发者进行自定义数据格式的类型。从该类继承的格式,都可以像Unity的原生类型一样进行序列和反序列化,并且可以从Unity的Inspector窗口进行操作。所有值类型、所有带Serializable属性类类型都可以序列化。也是另一种数据资产文件。

技术分享图片 技术分享图片 技术分享图片

Assets和Objects之间是一对多的关系。比如一个在磁盘的Prefab文件它就是Asset,但是在游戏场景中它可以多个Object实例。

2.2 File GUID和Local ID、Instance ID

GUID:UnityEngine.Objects之间是可以互相引用的,例如一个UIPrefab引用了一张图集SpriteAtlas里面的Sprite。这些互相引用的Objects有可能是在同一个Asset里,也有可能是在不同的Assets里,这要求Unity必须提供健壮的资源标识,能稳定地处理不同资源的引用关系。除此之外,Unity还必须考虑这些资源标识应该与平台无关,不能让开发者在切换平台的时候还需要关注资源的引用关系,毕竟它自己是一个跨平台部署的引擎。

File GUID是Unity内部算法,针对Asset资产而言生成的全工程唯一标识符。与Asset同目录同名,后缀是xxx.meta文件,如图。

技术分享图片

  • 第一次导入资源的时候Unity会自动生成。
  • 在Unity的面板里移动位置,Unity会自动同步.meta文件。
  • 在Unity打开的情况下单独删除.meta,刷新Unity可以确保重新生成的GUID和删除前的一样。 前面的metadata缓存文件夹帮忙了。
  • 在Unity关闭的情况下移动或者删除.meta文件,Unity无法恢复到原有的GUID,也就是说引用会丢失。 因为它会走第一次导入资源的步骤。

LocalID:是Object资产id唯一标识。技术分享图片(相同Asset在不同Object序列化的local ID不一样),Cube1与Cube2先分别生成各自.meta的GUID,然后在Object实例序列化后生成各自的localID。Cube1的children是Cube2的localId技术分享图片,localID又指向Cube2自身的GUID技术分享图片,这样就可以通过二者组合快速找到对应的引用技术分享图片

同时Unity也有获取映射关系的API:

string AssetDatabase.AssetPathToGUID(string path);
string AssetDatabase.GUIDToAssetPath(string guid);

同时Unity在导入资源时也有一次缓存信息:Libray/metadata,取GUID前两位进行命名的文件夹

技术分享图片

技术分享图片

Instance ID:是Unity在编辑器运行或APP运行,动态实例化生成对象的ID(也就是Instantiate),是递增的整数。这是由Unity引擎内部PersistentManager维护的,只要动态加载或生成一个实例对象就能生成一个Instance ID,而该实例对象Instance ID又映射了LocalID,LocalID又映射了源资源GUID。举个例子:比如要加载Cube1,但是Cube1依赖Cube2,这时系统解析到内存中Cube2没有被加载,那么根据Cube1中依赖的Cube2的Local ID和File GUID也可以快速地定位到Cube2的Asset资源从而即时进行资源加载

更更更详细的可以查看《Unity文件、文件引用、Meta详解》

3 Asset生命周期

3.1 Object加载

当Unity应用启动时,PersistentManager的缓存系统会立刻初始化,会对项目要用到的数据、Resources文件夹内的Objects进行初始化。就是运行时加载或下载Asset Bundle实例化时都会产生新的InstanceID。这里有可能就会产生问题:

1、某个Object的InstanceID被间接引用产生的问题:如果该Object被单独删除卸载了,会出现引用丢失的问题

2、Object当前没有被加载进内存:该Object没有被加载就直接实例化会报错,也会使依赖该Object的实例对象丢失引用

总之,缓存系统大致流程是:若依赖一个Object就会去查找该Object的InstanceID是否存在,没有InstanceID就要根据LocalID和GUID去加载;有InstanceID时要检查对应的Object是否被卸载,若被卸载那么该InstanceID就无效,就要重新加载其引用的LocalID和GUID对应的资源。

3.2 Object卸载

1、当没有使用的Asset在执行清理的时候,会自动卸载对应的Object。一般是由切场景或者手动调用了Resources.UnloadUnusedAssets的API的时候触发的。但是这个过程只会卸载那些没有任何引用的Objects。

2、从Resources目录下加载的Objects可以通过调用Resources.UnloadAsset API进行显式的卸载。但这些Objects的Instance ID会保持有效,并且仍然会包含有效的File GUID 和LocalID。当任何Mono的变量或者其它Objects持有了被Resources.UnloadAsset卸载的Objects的引用之后,这个Object在被直接或者间接引用之后会马上被加载。

3、从AssetBundles里得到的Objects在执行了AssetBundle.Unload(true) API之后,会立刻自动的被卸载,并且这会立刻让这些Objects的File GUID、Local ID以及Instance ID立马失效。任何试图访问它的操作都会触发一个NullReferenceException。但如果调用的是AssetBundle.Unload(false)API,那么生命周期内的Objects不会随着AssetBundle一起被销毁,但是Unity会中断File GUID 、Local ID和对应Object的Instance IDs之间的联系,也就是说,如果这些Objects在未来的某些时候被销毁了,那么当再次对这些Objects进行引用的时候,是没法再自动进行重加载的。另外,如果Objects中断了它和源AssetBundle的联系之后,那么再次加载相同Asset,Unity也不会复用先前加载的Objects,而是会重新创建Instance ID,也就是说内存里会有多份冗余的资源。

4 Assets文件夹分类

好的规范分类可以解决大部分问题,有序、统一、共识能使团队工作起来更顺心。

《分类规则》

Unity资源Tree-资源组织

原文:https://www.cnblogs.com/baolong-chen/p/13405463.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!