This article shares the resource management in Unity - AssetBundle (1)
In the previous article, we briefly introduced the resources and basic usage in Unity. Today we will introduce the usage AssetBundle
to manage resources in detail.
Introduction to AssetBundle
AssetBundle
, hereinafter referred to as Ab
, the concept itself is very simple, as the name suggests, it is just a package of a series of materials .
Compared with Resources
the way of organizing resources in folders, Ab
some way will be used to organize resources in the form of "packages".
We can organize all the resources in a certain folder into one Ab
, we can also organize certain types of resources into one Ab
, we can also organize some resources under a certain folder into one Ab
, and even organize some resources from different folders into one a Ab
.
As to how to organize, different projects have different requirements. For example, some projects are relatively small, and resources will be classified according to type, with one resource for each type. Some Ab
projects are relatively large, and each individual system will be organized into one Ab
, or even To be more detailed, each system is organized into more resource types Ab
. We will introduce various solutions and their advantages and disadvantages in detail in the following articles.
No matter how it is organized, Ab
the basic concepts and usage methods are basically the same, and we will only introduce this part today.
First of all, Ab
the main process is:
Ab
Packaging: output the package according to the configuration under the Editor- Load package: load the package into memory from the specified location at runtime
- Loading resources: Loading resources from bundles using
- Unload resources: Unload resources loaded from the package
- unload package: unload package from memory
Next, we will introduce them in several documents.
Pack
Unity provides two organization Ab
methods, one is Asset Labels
, one is AssetBundleBuild
. The former is easy to use, and the latter is flexible.
Official AssetBundle plugin: AssetBundle Browser
The officially provided Ab
plug-in lowers the threshold for use. It can be downloaded from this addressWindow->AssetBundle Browser
, and the window will open after importing the project .
After Asset Labels
setting up Ab
the package, you can use the plug-in to manage and package it. Of course, you can also set it automatically by directly dragging the folder or material to the plug-in window Ab
.
Figure 1 shows all Ab
the packages of the current project, and Ab
what resources each contains.
Figure 2 shows the selected Ab
size, dependencies and other information.
Figure 3 shows the packaged parameters such as output path, compression method, etc.
In some small projects or for novices, this plugin is simply a boon.
Asset Labels
Below the property panel of each resource (including folders), you can see the configuration of the resource label: the
yellow frame is Ab
the package name, and the blue frame is Ab
the variant (Varient).
Package names
If a folder is set Asset Labels
, then all materials under this folder will be added to this folder Ab
, unless a certain material is specified , it will be removed Ab
from the folder representative .Ab
Vary
Variants are different configurations for resources with the same name. The most commonly used is that the same batch of resources can have different variants according to different platforms or different precisions.
Variants require that the types, quantities, and names of the resources included are consistent. It is complicated to say, but you can understand it by looking at the picture. The variant configuration below represents the same few textures, and there are different textures for different resolutions. Variants:
That is to say, two sets of the same picture should be prepared, one high-definition and one low-definition, keep the structure, name, and suffix consistent, and finally two sets will be generated, which can be used Ab
according to requirements during runtime.
In Figure 1, we can also clearly see that there are two variants of texture Ab
with the same internal structure.
package command
If you don't use plugins, you can use code for packaging:BuildPipeline.BuildAssetBundles(OutputPath, BuildAssetBundleOptions, BuildTarget);
The return value is a list information: AssetBundleManifest
, you can get all the information and its dependencies through the list information Ab
.
The build result is all in the output directory Ab
, and a list is attached Ab
to describe all Ab
and its dependencies, that is, AssetBundleManifest
it is also typed into one , and the name of Ab
this list is consistent with the output directory.Ab
If using the build command:
// 当前项目只有一个Ab, 包名为prefab
BuildPipeline.BuildAssetBundles("Assets/Output/AssetBundle/AllAb", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
Then the result is shown in the figure below:
Each Ab
is split into a data file and a manifest file ( .manifest
ending with ).
The content of the additional manifest file is all names Ab
in the output directory and their dependencies (not including themselves), as shown in the following figure (AllAb.manifest):Ab
Other Ab
manifest files include this Ab
Hash information, all materials, and component information and dependencies used by all materials, as shown in the figure below (prefab.manifest)
Unity deserializes components based on component information, such as Class: 0
yes Object
, Class: 1
yes GameObject
, specific information can be queried on the official website .
Parameter Description:
OutputPath
: output directoryBuildAssetBundleOptions
: Build options (only commonly used ones are listed), which can be|
combined with logic and ( )None
: None, useLZMA
compression.UncompressedAssetBundle
: No compression.ForceRebuildAssetBundle
: Force repackaging. If there is no option, the method of adding packaging will be used, and the packaging will be skipped if there is no modification.AppendHashToAssetBundleName
:Ab
Append the hash value toAb
the name, such as:abtest_a616fc6a2ca2fb086b75525b5f6e2635
, the hash value is behind the underscore.ChunkBasedCompression
:LZ4
Packed using the compression algorithm based on .StrictMode
: Strict mode, stop packaging as long as any error is reported.DryRunBuild
: Dry run, that is, it does not actually package, but returns the list information of all packages.DisableLoadAssetByFileName/DisableLoadAssetByFileNameWithExtension
: It is forbidden to use the resource file name or file name plus extension to load the resource. By default, the resource can be loaded in the following ways (if the resource is obtained by using the file name or the file name plus the extension, once there is a file with the same name, there will be The wrong material may be obtained, which file will be obtained is unknown):- Resource full path:
"Assets/Res/Prefabs/obj.prefab"
- Material name:
"obj"
- Asset name plus extension:
"obj.prefab"
- Resource full path:
BuildTarget
: BuildAb
supported platforms, only the commonly used ones are listed here, andEditorUserBuildSettings.activeBuildTarget
the currently activated platform can also be obtained byNoTarget
: no platform specifiedStandaloneOSX
: MacStandaloneWindows/StandaloneWindows64
: WindowsiOS
: iOSAndroid
: Android
LZMA and LZ4 compression
LZMA
Use the stream compression method ( stream-based
), sort all the materials according to the structure, and then form a data stream before compressing.
The advantages and disadvantages are as follows:
- Advantages: Higher compression ratio, smaller output files, faster compression speed
- Disadvantages: There is a sequence requirement, all materials need to be decompressed before loading, the loading speed is slow, the decompression speed is even slower, and the materials will exist in the memory regardless of whether they are used or not
LZ4
Use the block compression method ( chunk-based
), divide all the materials into blocks according to the structure and then compress them.
The advantages and disadvantages are as follows:
- Advantages:
Ab
Only the header information needs to be loaded when loading, the loading is extremely fast, specific assets are only decompressed when the assets are actually used, and the memory footprint is small - Disadvantages: comparatively
LZMA
larger output files
By default, compression Ab
is used LZMA
. If the game size is not large, you can load all the resources at once when entering the game, and the experience in the subsequent game process will be relatively smooth.
AssetBundleBuild
In small projects, or projects with a good structure, it is easiest to use label packaging. Set the label and package it directly. Unity will handle dependencies and other troubles for us.
It is very simple to use tags, but it is not very flexible, and there is a risk of loss once the version is upgraded. In short, there are various reasons that cause us to use more custom configurations for packaging in large projects, that is Packaged by config AssetBundleBuild
.
Packaging with custom configuration and label packaging are independent, that is to say, the same resource, even if it is labeled, we can package it under other Ab
.
The way to use is also very simple, each one Ab
corresponds to one AssetBundleBuild
, we organize all of them before packaging AssetBundleBuild
, and finally hand them over to the build pipeline ( BuildPipline
) for packaging.
[MenuItem("Test/BuildAb", false, 100)]
public static void TestBuild() {
var assetBundleBuild = new AssetBundleBuild{
assetBundleName = "abtest"
};
assetBundleBuild.assetNames = new[]{
"Assets/Res/Prefabs/obj.prefab",
"Assets/Res/Prefabs/test4.prefab",
};
var outputPath = "Assets/Output/AssetBundle/AllAb";
var lst = new[]{assetBundleBuild};
if (Directory.Exists(outputPath)) {
Directory.Delete(outputPath);
}
Directory.CreateDirectory(outputPath);
BuildPipeline.BuildAssetBundles(outputPath, lst, BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
}
AssetBundleBuild
Represents a Ab
packaging configuration, assetBundleName
the attribute is the package name, assetNames
and it is an array of full paths of the resource files contained in the package.
AssetBundleBuild
Finally , add the array to the second parameter in the interface of the construction pipeline construction package .
You think it's over? Naive.
There is nothing wrong with the above packaging on the surface, but there are actually two serious problems:
- What if the same asset appears in multiple packages?
- What if a material needs to use another material, but the material is not in this package?
When using tag packaging, Unity will automatically handle the above problems for us, and now we need to handle it ourselves.
Dealing with duplication and dependencies
When packaging, we use a data structure to save all material identifiers already in a package, so as to ensure that all files will not appear repeatedly in multiple packages.
When adding a resource to the build list of a package, all dependent resources used by the resource are queried through the interface, and if they have not been processed before, they will be added to the current package.
It is more complicated to say, directly on the code:
[MenuItem("Test/Build2")]
public static void Build2() {
var allAbPath = new[]{
new[]{"Texture", "Assets/Res/Texture"},
new[]{"Shaders", "Assets/Res/Shaders"},
new[]{"Model", "Assets/Res/Model"},
new[]{"Prefabs", "Assets/Res/Prefabs"},
};
var assetBundleBuildLst = new List<AssetBundleBuild>();
var cachedAssets = new HashSet<int>(); // 保存资材名称字符串的hashcode, 用来过滤已被处理的文件
// 处理资材文件
void HandleFile(string path, in List<string> lst) {
// 过滤部分不支持的资材
if (path.EndsWith(".meta") || path.EndsWith(".cs") || path.EndsWith(".max")) {
return;
}
// 路径可能是带有盘符的绝对路径, 去除盘符和反斜杠的差异
var outPath = path.Substring(path.IndexOf("Assets", StringComparison.Ordinal));
outPath = outPath.Replace("\\", "/");
// 过滤已处理的资材
if (cachedAssets.Contains(outPath.GetHashCode())) {
return;
}
CollectDependencies(outPath, lst);
}
// 收集依赖
void CollectDependencies(string path, in List<string> lst) {
lst.Add(path);
cachedAssets.Add(path.GetHashCode());
// 收集依赖
// 依赖包含自身, 延迟到HandleFile过滤
var dependencies = AssetDatabase.GetDependencies(path);
foreach(var dependency in dependencies) {
HandleFile(dependency, lst);
}
}
// 处理Ab和遍历目录
foreach(var dirInfo in allAbPath) {
var abName = dirInfo[0];
var dir = dirInfo[1];
// 收集每个Ab包含的所有资材
var assetPathLst = new List<string>();
var info = new DirectoryInfo(dir);
foreach(var fileInfo in info.GetFiles("*", SearchOption.AllDirectories)) {
HandleFile(fileInfo.FullName, assetPathLst);
}
assetBundleBuildLst.Add(new AssetBundleBuild {assetBundleName = abName, assetNames = assetPathLst.ToArray()});
var sb = new StringBuilder(abName + " =====================>\n");
assetPathLst.ForEach((s) => {
sb.Append(s);
sb.Append('\n');
});
Debug.Log(sb);
}
var outputDir = "Assets/Output/AssetBundle/AllAb";
if (Directory.Exists(outputDir)) {
Directory.Delete(outputDir, true);
}
Directory.CreateDirectory(outputDir);
BuildPipeline.BuildAssetBundles(outputDir, assetBundleBuildLst.ToArray(), BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
The comments have been written very clearly, so I won't repeat them here.
When organizing Ab
, try to put unreferenced or less referenced packages in the front, so as to ensure that the resources are in the same location as the folder structure.
packaging strategy
According to the type of project, the size of the project, and the file organization structure of the project, there will be many different packaging strategies. Below we introduce some common strategies:
- All resources are packaged into an ab package (for small projects)
- All resources are classified by type, such as: texture, prefab, model, shader, material, animation, config, etc. (for small projects)
- According to the function, the resources are divided into three parts: startup , common and individual system resources (for large projects):
- Startup resources are necessary resources for normal startup:
- Such as opening screen animation, initial interface UI, hot update UI, etc.,
- This type of resource can be placed in
Resources
a directory to speed up startup. After the hot update is completed, it can be unloaded from the memory.
- Public resources are divided into multiple packages according to type or functionality, which can be selectively loaded and unloaded
- Each system has its own package, or a large system is further divided into multiple subsystems into multiple packages, which can be selectively loaded and unloaded
- Startup resources are necessary resources for normal startup:
Summarize
The basic knowledge introduced to you today Ab
includes packaging methods and packaging strategies. There may be different methods for different projects, and you can use them according to your needs.
The next article will introduce Ab
synchronous loading and asynchronous loading , interested students can continue to pay attention.
Well, that's all for today, I hope it can be helpful to everyone.