Unity手册-资源工作流

资源数据库

对于大多数类型的资源,Unity 需要将资源的源文件中的数据转换为可用于游戏或实时应用程序的格式。这些转换后的文件及其关联的数据会存储在资源数据库 (Asset Database) 中。

由于大多数文件格式都经过优化来节省存储空间,所以需要执行转换过程,而在游戏或实时应用程序中,资源数据需要采用可用于硬件(例如 CPU、显卡或音频硬件)的格式才能立即使用。例如,Unity 将 .png 图像文件导入为纹理时,在运行时不会使用原始的 .png 格式数据。而在导入纹理时,Unity 将以另一种格式创建图像的新表示形式,并将其存储在项目的 Library 文件夹中。Unity 引擎中的 Texture 类会使用此导入版本,然后 Unity 将其上传到 GPU 以进行实时显示。

如果随后修改资源已导入的源文件(或更改其任何依赖项),Unity 会重新导入该文件并更新导入版本的数据。
资源数据库还提供了 AssetDatabase API 来访问资源以及控制或自定义导入过程。

资源数据库 (AssetDatabase) 是允许您访问工程中的资源的 API。此外,其提供方法供您查找和加载资源,还可创建、删除和修改资源。Unity 编辑器 (Editor) 在内部使用资源数据库 (AssetDatabase) 追踪资源文件,并维护资源和引用资源的对象之间的关联。Unity 需要追踪工程文件夹发生的所有变化,如需访问或修改资源数据,您应始终使用资源数据库 (AssetDatabase) API,而非文件系统。 资源数据库 (AssetDatabase) 接口仅适用于编辑器,不可用于内置播放器。和所有其他编辑器类一样,其只适用于置于编辑器 (Editor) 文件夹中的脚本(只在主要的资源 (Assets) 文件夹中创建名为“编辑器”的文件夹(不存在该文件夹的情况下))

  • 资源缓存

资源缓存是 Unity 存储导入版本的资源的位置。由于 Unity 始终可以从源资源文件及其依赖项重新创建这些导入的版本,所以这些导入的版本被视为预先计算的数据的缓存。在使用 Unity 时,此缓存可节省时间。因此,应该从版本控制系统中排除资源缓存中的文件。
默认情况下,Unity 使用本地缓存,这意味着导入版本的资源将缓存在本地计算机上项目文件夹的 Library 文件夹中。应该使用 ignore file 从版本控制中排除此文件夹。
但是,如果您是团队成员并且使用版本控制系统,最好也使用 Unity Accelerator,它可以跨 LAN 共享资源缓存。

  • 源资源和 Artifact

Unity 在 Library 文件夹中保留两个数据库文件,它们统称为资源数据库。这两个数据库可以跟踪有关源资源文件和 Artifact(这是有关导入结果的信息)的信息。
1、源资源数据库包含有关源资源文件的元数据信息,Unity 将这些信息用来确定文件是否被修改,从而决定是否应该重新导入文件。这些信息中包括诸如上次修改日期、文件内容哈希、GUID 和其他元数据信息之类的信息。位置:Library\SourceAssetDB
2、Artifact 是导入过程的结果。Artifact 数据库包含有关每个源资源的导入结果的信息。每个 Artifact 都包含导入依赖项信息、Artifact 元数据信息和 Artifact 文件列表。位置:Library\ArtifactDB

  • 刷新资源数据库

1、Unity Editor 重新获得焦点时(如果已在 Preferences 窗口中启用 Auto-Refresh)
2、从菜单中选择 Assets > Refresh 时
3、从 C# 调用 AssetDatabase.Refresh 时

有关资源数据库更详细的信息,请参考官方文档:https://docs.unity3d.com/cn/2020.1/Manual/AssetDatabase.html

AssetBundle

AssetBundle 是一个存档文件,包含可在运行时由 Unity 加载的特定于平台的非代码资源(比如模型、纹理、预制件、音频剪辑甚至整个场景)。为了提高通过网络传输的效率,可以根据用例要求(LZMA 和 LZ4)选用内置算法选择来压缩 AssetBundle。同时AssetBundle也在某种意义上对资源进行了加密
AssetBundle 可用于可下载内容(DLC),减小初始安装大小,加载针对最终用户平台优化的资源,以及减轻运行时内存压力。

1、AssetBundle 存档是一个容器,就像文件夹一样,可以在其中包含其他文件。这些附加的文件包含两种类型:系列化文件和资源文件
2、AssetBundle也可以指代通过代码进行交互以便从特定 AssetBundle 存档加载资源的实际 AssetBundle 对象。该对象包含您添加到此存档文件的资源的所有文件路径的映射。

  • 构建 AssetBundle
using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";
        if(!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, 
                                        BuildAssetBundleOptions.None, 
                                        BuildTarget.StandaloneWindows);
    }
}
  • 加载 AssetBundle 和资源
public class LoadFromFileExample : MonoBehaviour {
    function Start() {
        var myLoadedAssetBundle 
            = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
        if (myLoadedAssetBundle == null) {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
        Instantiate(prefab);
    }
}
  • 加载 AssetBundle清单
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); //传递想要依赖项的捆绑包的名称。
foreach(string dependency in dependencies)
{
    AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}

其他加载AssetBundle方式请参考api:https://docs.unity3d.com/cn/2020.1/Manual/AssetBundles-Native.html

  • AssetBundle 资源分组规则
    1、逻辑实体分组
    逻辑实体分组是指根据资源所代表的项目功能部分将资源分配给 AssetBundle。这包括各种不同部分,比如用户界面、角色、环境以及在应用程序整个生命周期中可能经常出现的任何其他内容。逻辑实体分组非常适合于可下载内容 (DLC),因为通过这种方式将所有内容隔离后,可以对单个实体进行更改,而无需下载其他未更改的资源。
    2、类型分组
    根据此策略,可以将相似类型的资源(例如音频轨道或语言本地化文件)分配到单个 AssetBundle。要构建供多个平台使用的 AssetBundle,类型分组是最佳策略之一。
    3、并发内容分组
    并发内容分组是指将需要同时加载和使用的资源捆绑在一起。可以将这些类型的捆绑包用于基于关卡的游戏(其中每个关卡包含完全独特的角色、纹理、音乐等)。有时可能希望确保其中一个 AssetBundle 中的资源与该捆绑包中的其余资源同时使用。依赖于并发内容分组捆绑包中的单个资源会导致加载时间显著增加。您将被迫下载该单个资源的整个捆绑包。并发内容分组捆绑包最常见的用例是针对基于场景的捆绑包。在此分配策略中,每个场景捆绑包应包含大部分或全部场景依赖项。

无论遵循何种策略,下面这些额外提示都有助于掌控全局:
1、将频繁更新的对象与很少更改的对象拆分到不同的 AssetBundle 中
2、将可能同时加载的对象分到一组。例如模型及其纹理和动画
3、如果发现多个 AssetBundle 中的多个对象依赖于另一个完全不同的 AssetBundle 中的单个资源,请将依赖项移动到单独的 AssetBundle。如果多个 AssetBundle 引用其他 AssetBundle 中的同一组资源,一种有价值的做法可能是将这些依赖项拉入一个共享 AssetBundle 来减少重复。
4、如果不可能同时加载两组对象(例如标清资源和高清资源),请确保它们位于各自的 AssetBundle 中。
5、如果一个 AssetBundle 中只有不到 50% 的资源经常同时加载,请考虑拆分该捆绑包
6、考虑将多个小型的(少于 5 到 10 个资源)但经常同时加载内容的 AssetBundle 组合在一起
7、如果一组对象只是同一对象的不同版本,请考虑使用 AssetBundle 变体

  • 构建 AssetBundle参数

BuildAssetBundleOptions
1、BuildAssetBundleOptions.None:此捆绑包选项使用 LZMA 格式压缩,这是一个压缩的 LZMA 序列化数据文件流。LZMA 压缩要求在使用捆绑包之前对整个捆绑包进行解压缩。此压缩使文件大小尽可能小,但由于需要解压缩,加载时间略长。值得注意的是,在使用此 BuildAssetBundleOptions 时,为了使用捆绑包中的任何资源,必须首先解压缩整个捆绑包。
解压缩捆绑包后,将使用 LZ4 压缩技术在磁盘上重新压缩捆绑包,这不需要在使用捆绑包中的资源之前解压缩整个捆绑包。最好在包含资源时使用,这样,使用捆绑包中的一个资源意味着将加载所有资源。这种捆绑包的一些用例是打包角色或场景的所有资源。
由于文件较小,建议仅从异地主机初次下载 AssetBundle 时才使用 LZMA 压缩(内容分发网络 (CDN) 上下载的首选格式)。通过 UnityWebRequestAssetBundle 加载的 LZMA 压缩格式 Asset Bundle 会自动重新压缩为 LZ4 压缩格式并缓存在本地文件系统上。如果 Caching.compressionEnabled 设置为 false,Unity 在将 AssetBundle 写入磁盘时不会应用压缩。如果通过其他方式下载并存储捆绑包,则可以使用 AssetBundle.RecompressAssetBundleAsync API 对其进行重新压缩。

2、BuildAssetBundleOptions.UncompressedAssetBundle:此捆绑包选项采用使数据完全未压缩的方式构建捆绑包。未压缩的缺点是文件下载大小增大。但是,下载后的加载时间会快得多。

3、BuildAssetBundleOptions.ChunkBasedCompression:此捆绑包选项使用称为 LZ4 的压缩方法,因此压缩文件大小比 LZMA 更大,但不像 LZMA 那样需要解压缩整个包才能使用捆绑包。LZ4 使用基于块的算法,允许按段或“块”加载 AssetBundle。解压缩单个块即可使用包含的资源,即使 AssetBundle 的其他块未解压缩也不影响。

BuildTarget
BuildTarget.Standalone:这里我们告诉构建管线,我们要将这些 AssetBundle 用于哪些目标平台。可以在关于 BuildTarget 的脚本 API 参考中找到可用显式构建目标的列表。但是,如果不想在构建目标中进行硬编码,请充分利用 EditorUserBuildSettings.activeBuildTarget,它将自动找到当前设置的目标构建平台,并根据该目标构建 AssetBundle。

  • AssetBundle 依赖项

如果 AssetBundle 中包含依赖项,则在加载尝试实例化的对象之前,务必加载包含这些依赖项的捆绑包。Unity 不会尝试自动加载依赖项。
参考以下示例,Bundle 1 中的材质引用了 Bundle 2 中的纹理:
在此示例中,在从 Bundle 1 加载材质之前,需要将 Bundle 2 加载到内存中。加载 Bundle 1 和 Bundle 2 的顺序无关紧要,重要的是在从 Bundle 1 加载材质之前应加载 Bundle 2。在下一部分,我们将讨论如何使用我们在上一部分介绍的 AssetBundleManifest 对象在运行时确定并加载依赖项。

  • AssetBundle 缓存

为了使用 WWW 或 UnityWebRequest (UWR) 来优化 LZMA AssetBundle 的提取、再压缩和版本控制,Unity 有两种缓存:

1、内存缓存:以 UncompressedRuntime 格式将 AssetBundle 存储在 RAM 中。

2、磁盘缓存:将提取的 AssetBundle 以下文描述的压缩格式存储在可写介质中。

将 AssetBundle 加载到内存缓存中会耗用大量的内存。除非您特别希望频繁且快速地访问 AssetBundle 的内容,否则内存缓存的性价比可能不高。因此,应改用磁盘缓存。

如果向 UWR API 提供版本参数,Unity 会将 AssetBundle 数据存储在磁盘缓存中。如果没有提供版本参数,Unity 将使用内存缓存。版本参数可以是版本号或哈希。

最初加载缓存的 LZMA AssetBundle 所花费的时间更长,因为 Unity 必须将存档重新压缩为目标格式。随后的加载将使用缓存版本。

AssetBundle.LoadFromFile 或 AssetBundle.LoadFromFileAsync 始终对 LZMA AssetBundle 使用内存缓存,因此您应该使用 UWR API。如果无法使用 UWR API,您可以使用 AssetBundle.RecompressAssetBundleAsync 将 LZMA AssetBundle 重写到磁盘中。

内部测试表明,使用磁盘缓存而不是内存缓存在 RAM 使用率方面至少存在一个数量级的差异。因此,必须在内存影响、增加的磁盘空间要求以及应用程序的资源实例化时间之间进行权衡。

  • 使用 AssetBundle 的项目中常见的几个问题

资源重复
1、确保构建到不同 AssetBundle 中的对象不共享依赖项。任何共享依赖项的对象都可以放在同一个 AssetBundle 中,而不会复制它们的依赖项。
2、对 AssetBundle 进行分段,确保不会同时加载两个共享依赖项的 AssetBundle。
3、确保所有依赖项资源都构建到自己的 AssetBundle 中。这样可以完全消除重复资源的风险,但也带来了复杂性。应用程序必须跟踪 AssetBundle 之间的依赖关系,并确保在调用任何 AssetBundle.LoadAsset API 之前加载了正确的 AssetBundle。可使用 AssetDatabase.GetDependencies 查找特定对象或资源的所有直接依赖项。

精灵图集重复
任何自动生成的精灵图集都将与生成精灵图集的精灵对象一起分配到同一个 AssetBundle。如果精灵对象被分配给多个 AssetBundle,则精灵图集将不会被分配给 AssetBundle 并且将被复制。如果精灵对象未分配给 AssetBundle,则精灵图集也不会分配给 AssetBundle。

为了确保精灵图集不重复,请确保标记到相同精灵图集(packing tag)的所有精灵都被分配到同一个 AssetBundle

Android 纹理
由于 Android 生态系统中存在严重的设备碎片,因此通常需要将纹理压缩为多种不同的格式。虽然所有 Android 设备都支持 ETC1,但 ETC1 不支持具有 Alpha 通道的纹理。如果应用程序不需要 OpenGL ES 2 支持,解决该问题的最简单方法是使用所有 Android OpenGL ES 3 设备都支持的 ETC2。

大多数应用程序需要在不支持 ETC2 的旧设备上发布。解决这个问题的一种方法是使用 Unity 5 的 AssetBundle 变体。
要使用 AssetBundle 变体,必须将无法使用 ETC1 完全压缩的所有纹理隔离到仅包含纹理的 AssetBundle 中。接下来,使用供应商特有的纹理压缩格式(如 DXT5、PVRTC 和 ATITC),创建这些 AssetBundle 的足够多变体来支持 Android 生态系统中不支持 ETC2 的部分。对于每个 AssetBundle 变体,应将包含的纹理的 TextureImporter 设置更改为适合变体的压缩格式。

在运行时,可以使用 SystemInfo.SupportsTextureFormat API 检测对不同纹理压缩格式的支持情况。应使用此信息来选择和加载含有以受支持格式压缩的纹理的 AssetBundle 变体。

  • 管理已加载的 AssetBundle

从活动场景中删除对象时,Unity 不会自动卸载对象。资源清理在特定时间触发,也可以手动触发。

了解何时加载和卸载 AssetBundle 非常重要。不正确地卸载 AssetBundle 会导致在内存中复制对象或其他不良情况,例如缺少纹理。

关于 AssetBundle 管理最重要的事情就是何时调用

AssetBundle.Unload(bool); 以及应该将 true 还是 false 传递给函数调用。Unload 是一个非静态函数,可用于卸载 AssetBundle。此 API 会卸载正在调用的 AssetBundle 的标头信息。该参数指示是否还要卸载通过此 AssetBundle 实例化的所有对象。

AssetBundle.Unload(true) 卸载从 AssetBundle 加载的所有游戏对象(及其依赖项)。这不包括复制的游戏对象(例如实例化的游戏对象),因为它们不再属于 AssetBundle。发生这种情况时,从该 AssetBundle 加载的纹理(并且仍然属于它)会从场景中的游戏对象消失,因此 Unity 将它们视为缺少纹理。

假设材质 M 是从 AssetBundle AB 加载的,如下所示。

如果调用 AB.Unload(true),活动场景中的任何 M 实例也将被卸载并销毁。

如果改作调用 AB.Unload(false),那么将会中断 M 和 AB 当前实例的链接关系。

如果稍后再次加载 AB 并且调用 AB.LoadAsset(),则 Unity 不会将现有 M 副本重新链接到新加载的材质。而是将加载 M 的两个副本。

通常,使用 AssetBundle.Unload(false) 不会带来理想情况。大多数项目应该使用 AssetBundle.Unload(true) 来防止在内存中复制对象。

大多数项目应该使用 AssetBundle.Unload(true) 并采用一种方法来确保对象不会重复。两种常用方法是:

1、在应用程序生命周期中具有明确定义的卸载瞬态 AssetBundle 的时间点,例如在关卡之间或在加载屏幕期间。

2、维护单个对象的引用计数,仅当未使用所有组成对象时才卸载 AssetBundle。这允许应用程序卸载和重新加载单个对象,而无需复制内存。

如果应用程序必须使用 AssetBundle.Unload(false),则只能以两种方式卸载单个对象:

1、在场景和代码中消除对不需要的对象的所有引用。完成此操作后,调用 Resources.UnloadUnusedAssets。

2、以非附加方式加载场景。这样会销毁当前场景中的所有对象并自动调用 Resources.UnloadUnusedAssets。

如果不想自己管理加载资源包、依赖项和资源,可能需要使用 Addressable Assets 包。

Unity关于Asset的一切

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
程序部 码农们的家乡 程序猿的部落 头发的战俘集中营 先说这个整个部门啊 程序游戏程序员 需要学习什么语言呢 这要看是什么游戏 如果是页游 一般需要AS3或者是HTML6 如果是手游平台 那一般是JAVA 如果是PC和游戏机 那一般是C++ 我主要说的是另一个 我认为这个部门的所有职位都必须要非常了解游戏 可能很多人觉得 只要代码写得好就好啦 诶不是啊 这个部门的人懂不懂游戏 对游戏的整体品质有极大的影响 因为如果这个部门的人对游戏不熟悉 他们将很难抓住一些细节的东西 设计部或者技美还是会提出细节的需求 当然这个前提是这些人也有大量游戏经验 如果像国内很多团队那样 这个需求就算交货了 但就算他们能够提出更细节的需求 第一 如果每个细节都得说那么清楚 那工作量和沟通成本会呈指数放大 第二 这里面还是很多的东西是别人从表面看不出来的 甚至根本不知道怎么提出需求 比如如果这个图标拖出去的时候 这个技能刚好没了呢 比如这是个武器技能 刚好这个武器突然坏了呢 或者晚点把这个图标拖到了正在cd的技能上的 又或者把他的背包格子呢 又或者拖出来的的时候没有放左键情况下按了右键 我原本右键是可以触发技能的呢 等等这些情况到底应该发生什么事情 一个熟悉和不熟悉游戏的程序员 考虑到的是完全不同的情况 有些情况QA部门能够发现出来 但有些就很难发现 而这个时候就会留下BUG 同理 在战斗系统 升级系统等等各个系统都有这样的例子 比如战神一个按键回收斧头 这能提出一大堆问题 斧头在飞回来的路上碰到小屁孩怎么办 玩家松手了怎么办 放技能了怎么办 换武器了怎么办 播放过场了怎么办 等等一大堆问题 虽然如果出了BUG总会被抓出来 但是一批好的程序员 如果在一开始就能理清这些逻辑 那无疑让游戏整体品质大大提高 所以一个好的游戏程序员 不能什么事都靠设计提需求 靠QA反馈BUG 自己也需要经验和判断 这决定了游戏的成品品质 而想要成为这样的游戏员 只会写代码可不够啊 还需要大量的游戏经验以及 对这些细微之处的观察 观察好的游戏是怎么处理这些奇葩情节 思考他们是怎么编写这些复杂逻辑 方能成为一个好的程序员 那现在说说这个部门各个职位
Unity Mega-Fiers是一款强大的Unity插件,它为开发者提供了许多功能和工具,以帮助他们创建优秀的游戏体验。 首先,Unity Mega-Fiers具有强大的形变功能。开发者可以通过该插件实现各种形状的变换,包括弯曲、挤压、拉伸等。这为游戏中的人物、物体和环境提供了更多的自由度和个性化选项,使其更具动态和真实感。 其次,Unity Mega-Fiers还提供了高度的粒子系统控制能力。开发者可以使用该插件来创建更加逼真的粒子效果,并具有更准确的控制。这包括粒子的大小、颜色、速度等方面,使游戏中的特效更加出色。 另外,Unity Mega-Fiers还支持可编程网格。这意味着开发者可以通过脚本来控制网格的生成和变形,从而实现各种复杂的效果。无论是地形生成、水体模拟还是其他物体的变形,都可以通过该插件实现,并使游戏更加逼真和具有个性化。 除了以上功能,Unity Mega-Fiers还提供了其他诸多辅助工具,如动画控制、特效编辑等,为开发者提供了更丰富的开发选项和提升游戏质量的手段。 总结而言,Unity Mega-Fiers是一款功能强大的Unity插件,为开发者提供了丰富的形变、粒子系统控制和可编程网格等功能。它能够大幅提升游戏的真实感和品质,并为开发者提供更多的创作空间和个性化选项。无论是初学者还是有经验的开发者,都能够从中受益,并创造出出色的游戏作品。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值