美文网首页Unity
【Unity】打包(二)

【Unity】打包(二)

作者: hellokazhang | 来源:发表于2018-09-14 21:34 被阅读60次

    Assets,Objects序列化

    这是涵盖Assets,Resources和资源管理的一列文章中的第二篇。

    这篇文章涵盖了Unity序列化系统的内部原理和Unity是如何在不同的Objects间保持健壮的引用的,包括Unity编辑器与运行时。也讨论了Objects和Assets在技术上的区别。这里涉及的主题对理解如何高效地加载和卸载Unity资源起到很重要的作用。合适的资源管理的关键是hi保持短的加载时间和较低的内存使用。

    1.1内部Assets和Objects

    为了明白Unity是如何合理地管理数据的,了解Unity是如何标识和序列化数据是很重要的。第一个关键点就是区分Assets和UnityEngine.Objects。

    Asset就是硬盘的上的一个文件,存储在Unity工程的Assets文件夹。Textures,3d模型或音频都是常见的Assets类型。一些Assets包含了Unity的内部数据类型,如材质,而另一些Assets需要处理成Unity内部数据类型,如FBX文件。

    UnityEngine.Object或具有大写'O'的对象,是描述特定资源实例的一组集合。可以是Unity使用的任何资源类型,比如mesh,sprite,AudioClip或AnimationClip。所有这些Objects都是继承自UnityEngine.Object

    虽然大多数类型都是内置的,但有两种特殊类型:

    1. ScriptableObject 提供了便利的系统让开发者定义他们的自定义类型。这些类型可以被Unity序列化和反序列化,在Unity的Editor Inspector窗口也能操作。
    2. MonoBehaviour 提供了链接到MonoScript的包装器。MonoScript是一种内部类型,Unity使用它在特定程序集和命名空间保保存对特定脚本的引用。MonoScript不包含任何实际的可执行代码。

    Assets和Objects是一对多的关系,也就是说任何给定的Asset文件包含一到多个的Objects。

    1.2 Objects间的引用

    所有的nityEngine.Objects可以引用其他UnityEngine.Objects。这些Objects可能是在同一个Asset文件,也可能从其他Asset文件引入。比如一个材质通常引用一个或多个Texture Objects。这些Texture Objects通常从一个或多个texture Asset文件引入(比如Pngs,Jpgs)。

    当序列化的时候,这些引用由两个独立的数据组成:File GUID和Local ID。File GUID标识目标Asset文件保存在哪里。局部唯一的Local ID标识Asset文件内的每个Object,因为Asset可能包含多个Objects。

    File GUID保存在.meta文件。这些.meta文件是在Unity引入Asset的时候生成的,并且存储在和Asset同一个目录下。

    以上的标识码和引用关系可以通过文本编辑查看:创建一个新的UnityObject,修改Editor Setting暴露显示Mate文件,序列化Assets为text。创建一个material,然后导入texture到工程。把这个material指认给一个场景中的cube并保存。

    使用文本编辑器打开跟上满material关联的.meta文件,靠近顶部会出现标记为"guid"的信息。这一行定义了material Asset's文件的GUID。而查找Local ID需要使用文本编辑器打开material文件。material Object's 的定义是这样的:



    在上面的例子中,&之后的数据就是material的Local ID。如果这个material Object在Asset中GUID标识为"abcdefg",可以将material 对象唯一地标识为文件GUID "abcdefg"的组合,Local ID为"2100000"。

    1.3为什么需要GUIDs和Local IDs?

    为什么需要Unity的File GUID和Local ID? 回答的坚定的,因为它提供了一个灵活的、不依赖平台的工作流。

    文件GUID为文件特定路径提供了抽象描述。只要一个特定的文件GUID与特定的文件关联起来,那么文件在磁盘的路径变得无关紧要了。文件可以自由移动,而不需要更新所有引用这个文件的Objects。

    任何一个Asset可能包含(或通过import产生)多个UnityEngine.Object 资源,这个时候需要Local ID明确的区分不同的Object。

    如果一个File GUID关联的Asset文件丢失了,对该Asset的所有对象的引用也会丢失。所以.meta文件必须要保存在跟它关联的同名文件目录下,这很重要。注:Unity会重新生成删除的或丢失的.meta文件。

    Unity Editor有Paths到GUIDs的映射表。无论Asset加载还是引入,都会记录在映射表。映射表由Asset指定路径链接到Asset File GUID。如果Unity Editor打开的状态下,.meta文件丢失,并且Asset路径没有变化,Editor能够确保Asset保留相同的File GUID。

    如果Unity Editor在关闭状态下丢失了.meta文件,或者Asset路径变化了但.meta没有跟着移动,那么所有引用该Asset的Objects都会被破坏。

    1.4混合的Assets和导入器

    在1.1内部Assets和Objects章节说过,非Unity原生Asset类型必须导入到Unity。这是通过asset导入器来完成的。虽然这些导入器通常自动调用,但它们也可以通过AssetImport API暴露接口。比如,TextureImporter API在导入单个texture Assets(如PNG文件)提供了访问设置的接口。

    导入的结果就是引入一个或多个UnityEngine.Objects。这些Objects在Unity Editor是可见的,以父Asset下有多个子Asset形式显示,比如多个sprites嵌套在一个texture Asset,会当成sprite图集导入。其中这些每个Object共享一个File GUID,因为他们的源数据保存在相同的Asset文件。它们将通过导入的texture Asset内部的Local ID进行区分。

    导入进程会将源Asset转化为适合所选择目标平台的Asset。导入进程可能包含了一些重要的操作,比如texture压缩。因为导入进程通常是一个耗时的进程,被导入的Asset缓存到Library文件夹,避免下次启动Editor又重新导入Assets。

    切确的说,导入后的内容存储在以对应Asset的File GUID前两位数字命名的文件夹中。这个文件夹存储在Library/metadata/文件夹中。Asset中单个的Objects被序列化到一个名字与Asset的File GUID相同的二进制文件中。

    导入进程对所有的Assets有效,不仅仅对非原生Assets。原生assets不需要漫长的转换过程或重新序列化。

    1.5 序列化与实例

    File GUIDs和Local IDs都是健壮性比较好的,但GUID比较慢,运行时需要消耗更多性能。Unity内部维护一个缓存,它将File GUIDs和Local IDs转化成简单的,唯一的整数。当新的Objects在缓存注册的时候,会被分配一个简单的,单调递增的整数,这就叫Instance ID。

    缓存维护了给定的Instance ID,File GUID和定义Object源数据位置的Local ID与 Object在内存中的instance(如果有的话)之间的映射。解析Instance ID可以快速返回Instance ID代表的加载Object。如果目标Object还没有加载,File GUID和Local ID可以解析到Object源数据,可以让Unity及时加载出Object。

    项目启动的时候,Instance ID缓存初始化所有的Objects(如场景中的引用),只要这些Objects在Resources文件夹。另外,当新的assets在运行时导入进来或从AssetBundle加载Objects时,Instance ID会加进缓存中。当提供访问指定File GUID和Local ID的AssetBundle卸载(uploaded)时,Instance ID才会从缓存中移除。发生这种情况的时候,Instance ID,File GUID,Local ID之间的映射会被删除(节约内存)。如果这个AssetBundle重新加载了,会从这个重新加载的AssetBundle为加载出来的每个Object创建一个新的Instance ID。

    深度讨论AssetBundles卸载的含义,这看Managing Loaded Assets章节和AssetBundle Usage Patterns文章。

    在一些平台上,一些事件可以强制让Objects强制从内存中移除。比如,当IOS app暂停的时候,图形Assets会从图形内存中卸载。如果这些Objects是从AssetBundle加载出来的就会被卸载掉,并且Unity不能够重新加载这些源数据。任何现存的引用这些Objects的对象视为无效。前面的这种情况,场景中可能出现不可见的meshes或紫红色的图片。

    实践Tips:运行时,上述控制流并非字面上那么精确。当运行时,有大量大量加载操作的时候,File GUIDs和Local IDs表现没有那么好。当创建一个Unity项目的时候,File GUIDs和Local IDs切确地映射成了一种更简单的格式。

    相关文章

      网友评论

        本文标题:【Unity】打包(二)

        本文链接:https://www.haomeiwen.com/subject/rpxrgftx.html