02-03-原理篇-资源打包流程详解

资源打包流程详解

篇章 :02-原理篇 · 基础 阅读时间 :约 40 分钟 前置知识:了解 Unity 基本资源加载方式


一、引言

资源打包是 Unity 资源管理流程的核心环节,它决定了资源如何被组织、压缩和分发。一个高效的打包流程可以显著减少构建时间、优化资源体积、提高资源复用率。本章将深入解析资源打包的完整流程,包括资源准备、依赖分析、打包规则选择和构建优化,结合 YooAsset 的实际实现进行详细说明。

资源打包不仅仅是将资源文件压缩成一个包那么简单。它涉及到资源的分类、依赖分析、共享资源处理、压缩策略选择等多个方面。理解这些原理,可以帮助开发者设计出更合理的资源管理方案。


二、资源打包概述

2.1 打包目标

资源打包的主要目标包括:

  • 减小安装包体积:通过压缩和去重,减小安装包体积
  • 实现按需加载:将资源分成多个小包,根据需要动态加载
  • 支持热更新:将频繁更新的资源单独打包,支持热更新
  • 优化加载性能:通过合理的分包策略,优化加载性能
  • 提高资源复用率:通过共享资源处理,减少资源冗余

2.2 打包流程

资源打包的完整流程如下:

markdown 复制代码
资源打包流程
├── 1. 资源选择
│   ├── 选择需要打包的资源
│   └── 设置资源的 AssetBundle 标签
├── 2. 依赖分析
│   ├── 分析资源之间的依赖关系
│   └── 构建依赖图
├── 3. 资源分组
│   ├── 根据依赖关系分组
│   └── 处理共享资源
├── 4. 数据序列化
│   ├── 将资源数据序列化为二进制格式
│   └── 处理引用关系
├── 5. 压缩处理
│   ├── 根据配置的压缩算法压缩数据
│   └── 生成压缩后的数据块
├── 6. 文件组装
│   ├── 将压缩后的数据组装成 AssetBundle 文件
│   └── 生成资源清单和依赖信息
└── 7. 清单生成
    ├── 生成全局资源清单
    └── 生成依赖信息文件

2.3 打包系统架构

YooAsset 的打包系统由以下几个核心组件组成:

markdown 复制代码
YooAsset 打包系统架构
├── AssetBundleCollector:资源收集器
│   ├── MainAssetCollector:主资源收集器
│   ├── StaticAssetCollector:静态资源收集器
│   └── DependAssetCollector:依赖资源收集器
├── BundlePackRule:打包规则
│   ├── PackSeparately:单独打包
│   ├── PackDirectory:目录打包
│   ├── PackTopDirectory:顶级目录打包
│   └── PackGroup:分组打包
├── BuildPipeline:构建管线
│   ├── EditorSimulateBuildPipeline:编辑器模拟构建
│   ├── BuiltinBuildPipeline:内置构建管线
│   ├── ScriptableBuildPipeline:可编程构建管线
│   └── RawFileBuildPipeline:原生文件构建管线
└── BuildOutput:构建输出
    ├── AssetBundle 文件
    ├── Manifest 文件
    └── 依赖信息文件

三、资源选择

3.1 资源选择策略

资源选择是打包的第一步,需要决定哪些资源参与打包。常见的资源选择策略包括:

  • 按路径选择:选择指定路径下的所有资源
  • 按类型选择:选择指定类型的资源
  • 按标签选择:选择具有特定标签的资源
  • 手动选择:手动选择需要打包的资源

3.2 资源收集器

YooAsset 提供了三种资源收集器:

收集器类型 描述 适用场景
MainAssetCollector 主资源收集器,写入资源清单 需要代码加载的资源
StaticAssetCollector 静态资源收集器,参与打包但不写入清单 定制化打包策略
DependAssetCollector 依赖资源收集器,不写入清单 未被引用时自动剔除

MainAssetCollector 详解

MainAssetCollector 是最常用的资源收集器。它会将收集的资源写入资源清单,开发者可以通过代码加载这些资源。MainAssetCollector 适用于需要动态加载的资源,如预制体、场景、纹理等。

StaticAssetCollector 详解

StaticAssetCollector 会将资源打包到 AssetBundle 中,但不会写入资源清单。这种收集器适用于需要定制化打包策略的资源,如 Shader、音频等。

DependAssetCollector 详解

DependAssetCollector 会将资源打包到 AssetBundle 中,但不会写入资源清单。当资源没有被其他资源引用时,它会被自动剔除。这种收集器适用于可选资源,如 DLC 内容。

3.3 资源标签

资源标签是用于标识资源所属 Bundle 的标记。在 YooAsset 中,可以通过设置资源的 AssetBundle 属性来指定其所属的 Bundle。

csharp 复制代码
// 设置资源的 AssetBundle 标签
AssetImporter importer = AssetImporter.GetAtPath(assetPath);
importer.assetBundleName = "mybundle";
importer.assetBundleVariant = "bundle";

四、依赖分析

4.1 依赖分析原理

依赖分析是打包过程中最关键的一步。Unity 在打包时会递归地分析资源之间的依赖关系,确保所有依赖的资源都被正确打包。

依赖分析流程

  1. 资源扫描:扫描每个分组中的所有资源
  2. 依赖提取:提取每个资源的直接依赖
  3. 依赖图构建:将资源之间的依赖关系构建为有向图
  4. 循环依赖检测:检测依赖图中是否存在循环依赖
  5. 共享资源提取:识别被多个分组共享的资源,提取为独立 Bundle

依赖分析的关键点

  1. 递归分析:依赖分析是递归进行的,确保所有层级的依赖都被找到
  2. 去重处理:使用 HashSet 避免重复分析同一个资源
  3. 循环依赖检测:Unity 会检测循环依赖并抛出错误
  4. 外部依赖处理:对于不在当前 Bundle 中的依赖,需要单独处理

4.2 依赖图

依赖图是描述资源之间依赖关系的有向图。在依赖图中,每个节点代表一个资源,每条边代表一个依赖关系。

rust 复制代码
依赖图示例:
Prefab1 -> Texture1
Prefab1 -> Material1
Material1 -> Texture1
Prefab2 -> Texture1
Prefab2 -> Material1

依赖图:
Prefab1 --> Texture1
Prefab1 --> Material1 --> Texture1
Prefab2 --> Texture1
Prefab2 --> Material1

4.3 共享资源处理

当多个 Bundle 共享同一个资源时,需要将共享资源提取为独立的 Bundle,避免资源重复。

共享资源处理流程

  1. 识别共享资源:扫描所有 Bundle,识别被多个 Bundle 共享的资源
  2. 提取共享资源:将共享资源提取为独立的 Bundle
  3. 更新依赖关系:更新所有引用共享资源的 Bundle 的依赖关系

共享资源处理策略

策略 描述 优点 缺点
提取为独立 Bundle 将共享资源提取为独立 Bundle 避免资源重复 增加依赖关系
复制到每个 Bundle 将共享资源复制到每个 Bundle 简化依赖关系 资源重复
合并到第一个 Bundle 将共享资源合并到第一个 Bundle 简化依赖关系 第一个 Bundle 变大

五、数据序列化

5.1 序列化原理

序列化是将对象的状态转换为可以存储或传输的格式的过程。Unity 使用自定义的序列化格式来存储资源数据。

序列化流程

  1. 读取资源文件:读取原始资源文件
  2. 解析资源数据:解析资源文件中的数据
  3. 序列化数据:将资源数据序列化为二进制格式
  4. 写入 Bundle:将序列化后的数据写入 AssetBundle 文件

5.2 引用处理

在序列化过程中,需要处理资源之间的引用关系。Unity 使用引用索引来管理资源之间的引用关系。

引用处理流程

  1. 收集所有引用:收集资源中所有引用的其他资源
  2. 分配引用索引:为每个被引用的资源分配唯一的索引
  3. 写入引用列表:将引用列表写入序列化数据中

六、压缩处理

6.1 压缩算法

AssetBundle 支持多种压缩算法:

压缩算法 压缩率 解压速度 适用场景
LZMA 60-80% 网络传输
LZ4 40-60% 极快 运行时加载
LZ4HC 50-70% 平衡场景
无压缩 0% 最快 首包资源

6.2 压缩流程

压缩流程如下:

  1. 读取序列化数据:读取序列化后的数据
  2. 选择压缩算法:根据配置的压缩算法选择压缩方式
  3. 压缩数据:使用选择的压缩算法压缩数据
  4. 写入 Bundle:将压缩后的数据写入 AssetBundle 文件

七、文件组装

7.1 文件组装流程

文件组装是将压缩后的数据和元数据组装成 AssetBundle 文件的过程。

文件组装流程

  1. 写入文件头:写入 AssetBundle 文件头
  2. 写入资源数据:写入压缩后的资源数据
  3. 写入依赖信息:写入依赖信息
  4. 写入资源清单:写入资源清单
  5. 写入类型树:写入类型树

7.2 资源清单

资源清单是 AssetBundle 的索引部分,记录了 Bundle 中所有资源的名称、偏移量、大小和类型信息。

资源清单格式

erlang 复制代码
资源清单
├── 资源数量
├── 资源 1
│   ├── 资源名称
│   ├── 资源偏移量
│   ├── 资源大小
│   └── 资源类型
├── 资源 2
│   ├── 资源名称
│   ├── 资源偏移量
│   ├── 资源大小
│   └── 资源类型
└── ...

八、清单生成

8.1 全局资源清单

全局资源清单记录了所有 Bundle 的信息,包括 Bundle 名称、依赖关系、资源列表等。

全局资源清单格式

erlang 复制代码
全局资源清单
├── Bundle 1
│   ├── Bundle 名称
│   ├── Bundle 大小
│   ├── Bundle 依赖
│   └── 资源列表
├── Bundle 2
│   ├── Bundle 名称
│   ├── Bundle 大小
│   ├── Bundle 依赖
│   └── 资源列表
└── ...

8.2 依赖信息文件

依赖信息文件记录了所有 Bundle 之间的依赖关系,用于在加载时验证依赖关系。


九、构建优化

9.1 增量构建

增量构建可以显著减少构建时间:

  • 变化检测:检测哪些资源发生了变化
  • 增量打包:只重新打包发生变化的资源
  • 缓存复用:未变化的资源直接从缓存复用

9.2 并行构建

并行构建可以充分利用多核 CPU:

  • 模块并行:不同模块的打包可以并行执行
  • 资源并行:同一模块内的资源打包可以并行执行
  • 依赖管理:确保并行执行时依赖关系正确

9.3 压缩优化

压缩优化可以在体积和加载速度之间取得平衡:

  • LZMA 压缩:适合网络传输,压缩率高
  • LZ4 压缩:适合运行时加载,解压速度快
  • 混合压缩:不同资源使用不同的压缩方式

十、总结

资源打包是 Unity 资源管理的核心环节,理解打包流程对于优化资源管理和加载性能至关重要。在实际项目中,建议:

  1. 合理选择资源:根据项目需求合理选择需要打包的资源
  2. 优化依赖关系:避免循环依赖,减少依赖层级
  3. 选择合适的压缩算法:根据场景选择合适的压缩算法
  4. 监控打包结果:使用 Profiler 等工具监控打包结果

通过深入理解资源打包的原理,我们可以更好地利用 Unity 的资源管理功能,开发出性能更优、体验更好的游戏。


下一篇资源组织与依赖分析

相关推荐
UWA3 小时前
让UE性能分析真正穿透指标:GPU看堆栈,Texture拆到Group
性能优化·游戏开发
甲维斯18 小时前
《钢铁洪流》官网搞定,纯AI制作,Opus5操刀!
前端·人工智能·游戏开发
SmalBox1 天前
02-02-原理篇-Unity Addressable Assets原理深度解析
unity3d·游戏开发
甲维斯2 天前
0代码,0建模,3句话开发一个3D游戏!
前端·游戏·游戏开发
_zhourui_h_2 天前
Unity 内存数据极限防护:一个 int 藏 8 份密文,修改器到底还能怎么改?
unity3d
SmalBox2 天前
02-01-原理篇-Unity原生AssetBundle原理深度解析
unity3d·游戏开发
fujisheng6612 天前
FUI 验证实战:从 Prefab 节点改名到生成诊断与构建门禁
unity3d
_zhourui_h_3 天前
Unity AssetBundle 打包极限治理:依赖环、重复资源、包体膨胀,怎么在上线前全部揪出来?
unity3d
_zhourui_h_4 天前
Unity AssetBundle 极限管理:依赖、异步加载、引用计数、自动卸载到底怎么串起来?
unity3d