Resource management in Unity - AssetBundle(1)

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 AssetBundleto 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 Resourcesthe way of organizing resources in folders, Absome 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 Abprojects 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, Abthe basic concepts and usage methods are basically the same, and we will only introduce this part today.

First of all, Abthe main process is:

  • AbPackaging: 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 Abmethods, 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 Abplug-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 Labelssetting up Abthe 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.

insert image description here
insert image description here
insert image description here

Figure 1 shows all Abthe packages of the current project, and Abwhat resources each contains.

Figure 2 shows the selected Absize, 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
insert image description here
yellow frame is Abthe package name, and the blue frame is Abthe 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 Abfrom 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:

insert image description here
insert image description here

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 Abaccording to requirements during runtime.

In Figure 1, we can also clearly see that there are two variants of texture Abwith 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 Abto describe all Aband its dependencies, that is, AssetBundleManifestit is also typed into one , and the name of Abthis 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:

insert image description here
Each Abis split into a data file and a manifest file ( .manifestending with ).

The content of the additional manifest file is all names Abin the output directory and their dependencies (not including themselves), as shown in the following figure (AllAb.manifest):Ab

insert image description here

Other Abmanifest files include this AbHash information, all materials, and component information and dependencies used by all materials, as shown in the figure below (prefab.manifest)

insert image description here

Unity deserializes components based on component information, such as Class: 0yes Object, Class: 1yes GameObject, specific information can be queried on the official website .

Parameter Description:

  • OutputPath: output directory
  • BuildAssetBundleOptions: Build options (only commonly used ones are listed), which can be |combined with logic and ( )
    • None: None, use LZMAcompression.
    • 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: AbAppend the hash value to Abthe name, such as: abtest_a616fc6a2ca2fb086b75525b5f6e2635, the hash value is behind the underscore.
    • ChunkBasedCompression: LZ4Packed 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"
  • BuildTarget: Build Absupported platforms, only the commonly used ones are listed here, and EditorUserBuildSettings.activeBuildTargetthe currently activated platform can also be obtained by
    • NoTarget: no platform specified
    • StandaloneOSX: Mac
    • StandaloneWindows/StandaloneWindows64: Windows
    • iOS: iOS
    • Android: Android

LZMA and LZ4 compression

LZMAUse 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

LZ4Use 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: AbOnly 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 LZMAlarger output files

By default, compression Abis 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 Abcorresponds 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);
}

AssetBundleBuildRepresents a Abpackaging configuration, assetBundleNamethe attribute is the package name, assetNamesand it is an array of full paths of the resource files contained in the package.

AssetBundleBuildFinally , 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 Resourcesa 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

Summarize

The basic knowledge introduced to you today Abincludes 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 Absynchronous 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.

Guess you like

Origin blog.csdn.net/woodengm/article/details/122091922