https://blog.csdn.net/u012740992/article/details/79371986

怎么分析资源的依赖关系呢,并设置AssetBundleName呢?
我们检测资源之间的依赖关系,遍历每一个有引用的资源进行分析,对于非UGUI的图集资源(UGUI图集上面说了),如果此资源A被其他地方资源B引用仅仅1次,那么就将此资源A的AssetBundleName置空不设置,这样打包时,此资源就会自动被和资源B打到一起合成一个AssetBundle包,如此减少打包的碎片。如果资源A被引用超过2次及以上,那么就为资源独立设置AssetBundleName,从而避免被重复打包到几个依赖它的资源包。
这里所说的资源被依赖超过2次就独立打包,如果觉得碎片化太严重,产生太多AssetBundle文件,也可以设置成n(n>=1)次才独立打包,开心就好。
————————————————
版权声明:本文为CSDN博主「漫漫之间n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012740992/article/details/79371986

前提说明:

本文只是针对Unity5.x及以上版本打包AssetBundle。Unity5.x虽然说打包时会处理好资源的依赖关系,但前提依然要我们设置好目标资源的AssetBundleName,如果设置资源AssetBundleName时忽略了资源之间的依赖关系,那么打包AssetBundle时,依然会产生重复打包的资源,所以我写了一套脚本来自动分析资源的依赖关系,并根据资源的依赖关系来设置AssetBundleName,从而避免不必要的资源重复打包。
    我也了解过,
    Unity的AssetStore也有对应的图形界面工具,查看和处理打包AssetBundle时遇到的资源重复打包问题,但觉得图形化界面工具还得人工查看和修改,如果项目大了,一千多个ab甚至几千个ab,那么每次更新资源时去查看哪里存在依赖那也挺累得,效率不高,并且手动修正难说说没有看漏改漏。所以,不如来套脚本搞它一把,提高工作效率和质量。

我用的是Unity5.3.6。

前提有点特殊的是Unity的UGUI图集打包,Unity的官网有介绍如何将UGUI图集正确打成AssetBundle(但我现在翻回去找不到链接了= =。),简单说下:
首先,UGUI是有图集的。
我的UGUI图集打包AssetBundle方式是,每张图集打成一个AssetBundle,所以我这里保证了每张UI图片的PackingTag和自己的AssetBundleName一样。原因,如果AssetBundleName不一样,那么这张UI图片后面所打成的AssetBundle包将会扯带了整张图集的内容,这张图集别的UI图片也在用啊,却被无辜包含进了这个ab包。所以通过保证UI图片的PackingTag==AssetBundleName来保证每张图集只存在一个AssetBundle,保证图集不被重复打包。

怎么分析资源的依赖关系呢,并设置AssetBundleName呢?
我们检测资源之间的依赖关系,遍历每一个有引用的资源进行分析,对于非UGUI的图集资源(UGUI图集上面说了),如果此资源A被其他地方资源B引用仅仅1次,那么就将此资源A的AssetBundleName置空不设置,这样打包时,此资源就会自动被和资源B打到一起合成一个AssetBundle包,如此减少打包的碎片。如果资源A被引用超过2次及以上,那么就为资源独立设置AssetBundleName,从而避免被重复打包到几个依赖它的资源包。
这里所说的资源被依赖超过2次就独立打包,如果觉得碎片化太严重,产生太多AssetBundle文件,也可以设置成n(n>=1)次才独立打包,开心就好。

资源依赖处理的代码构建思路:
这里写图片描述
其实资源之间的依赖关系,就是一个树形依赖关系,只要能构建出资源之间的依赖树,那么就能了解到某个资源被多少颗树引用,也就是被多少个资源引用,从而对症下药,自然能合理设置AssetBundleName。

然后有代码LoaderManager.cs和ABInfo.cs。
注意:一定要放在Editor文件夹下!!

LoaderManager.cs

using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;
using System.Collections.Generic;

public class LoaderManager {

static Dictionary<string, AssetInfo> assetInfoDict = new Dictionary<string, AssetInfo>();

private static string curRootAsset = string.Empty;
    private static float curProgress = 0f;

[MenuItem("AssetBundleMgr / SetAssetbundleName")]
    static void SetABNames()
    {
        string path = GetSelectedAssetPath();
        if (path == null)
        {
            Debug.LogWarning("请先选择目标文件夹");
            return;
        }
        LoaderManager.GetAllAssets(path);

}
    [MenuItem("AssetBundleMgr / ClearAllAssetbundelname")]
    static void CleaarAllABNames()
    {
        string[] abnames = AssetDatabase.GetAllAssetBundleNames();
        foreach (var n in abnames)
        {
            AssetDatabase.RemoveAssetBundleName(n, true);
        }
    }

public static void GetAllAssets(string rootDir) {
        assetInfoDict.Clear();

DirectoryInfo dirinfo = new DirectoryInfo(rootDir);
        FileInfo[] fs = dirinfo.GetFiles("*.*", SearchOption.AllDirectories);
        int ind = 0;
        foreach (var f in fs)
        {
            curProgress = (float)ind / (float)fs.Length;
            curRootAsset = "正在分析依赖:"+f.Name;
            EditorUtility.DisplayProgressBar(curRootAsset, curRootAsset, curProgress);
            ind++;
            int index = f.FullName.IndexOf("Assets");
            if (index != -1)
            {
                string assetPath = f.FullName.Substring(index);
                Object asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
                string upath = AssetDatabase.GetAssetPath(asset);
                if (assetInfoDict.ContainsKey(assetPath) == false
                    && assetPath.StartsWith("Assets")
                    && !(asset is MonoScript)
                    && !(asset is LightingDataAsset)
                    && asset != null
                    ) {
                    AssetInfo info = new AssetInfo(upath, true);
                    //标记一下是文件夹下根资源
                    CreateDeps(info);
                }
                EditorUtility.UnloadUnusedAssetsImmediate();
            }
            EditorUtility.UnloadUnusedAssetsImmediate();
        }
        EditorUtility.ClearProgressBar();

int setIndex = 0;
        foreach (KeyValuePair<string, AssetInfo> kv in assetInfoDict) {
            EditorUtility.DisplayProgressBar("正在设置ABName", kv.Key, (float)setIndex/(float)assetInfoDict.Count);
            setIndex++;
            AssetInfo a = kv.Value;
            a.SetAssetBundleName(2);
        }
        EditorUtility.ClearProgressBar();
        EditorUtility.UnloadUnusedAssetsImmediate();
        AssetDatabase.SaveAssets();
    }
    /// <summary>
    /// 递归分析每个所被依赖到的资源
    /// </summary>
    /// <param name="self"></param>
    /// <param name="parent"></param>
    static void CreateDeps(AssetInfo self, AssetInfo parent = null) {
        if (self.HasParent(parent))
            return;
        if (assetInfoDict.ContainsKey(self.assetPath) == false) {
            assetInfoDict.Add(self.assetPath, self);
        }
        self.AddParent(parent);

Object[] deps = EditorUtility.CollectDependencies(new Object[] { self.GetAsset() });
        for (int i = 0; i < deps.Length; i++) {
            Object o = deps[i];
            if (o is MonoScript || o is LightingDataAsset)
                continue;
            string path = AssetDatabase.GetAssetPath(o);
            if (path == self.assetPath)
                continue;
            if (path.StartsWith("Assets") == false)
                continue;
            AssetInfo info = null;
            if (assetInfoDict.ContainsKey(path))
            {
                info = assetInfoDict[path];
            }
            else {
                info = new AssetInfo(path);
                assetInfoDict.Add(path, info);
            }
            EditorUtility.DisplayProgressBar(curRootAsset, path, curProgress);
            CreateDeps(info, self);
        }
        EditorUtility.UnloadUnusedAssetsImmediate();
    }

static string GetSelectedAssetPath()
    {
        var selected = Selection.activeObject;
        if (selected == null)
        {
            return null;
        }
        Debug.Log(selected.GetType());
        if (selected is DefaultAsset)
        {
            string path = AssetDatabase.GetAssetPath(selected);
            Debug.Log("选中路径: " + path);
            return path;
        }
        else
        {
            return null;
        }
    }
}

1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140

ABInfo.cs

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;

public class AssetInfo
{

//是不是被打包文件夹下的直接资源
    private bool isRootAsset = false;

public string assetPath { get; private set; }

private HashSet<AssetInfo> childSet = new HashSet<AssetInfo>();
    private HashSet<AssetInfo> parentSet = new HashSet<AssetInfo>();

public AssetInfo(string assetPath, bool isRootAsset = false)
    {
        this.assetPath = assetPath;
    }
    public Object GetAsset()
    {
        Object asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
        return asset;
    }
    /// <summary>
    /// 从这里开始分析构建资源依赖树
    /// </summary>
    /// <param name="parent"></param>
    public void AddParent(AssetInfo parent)
    {
        if (parent == this || IsParentEarlyDep(parent) || parent == null)
            return;

parentSet.Add(parent);
        parent.AddChild(this);

parent.RemoveRepeatChildDep(this);
        RemoveRepeatParentDep(parent);
    }
    /// <summary>
    /// 清除我父节点对我子节点的重复引用,保证树形结构
    /// </summary>
    /// <param name="targetParent"></param>
    private void RemoveRepeatChildDep(AssetInfo targetChild)
    {

List<AssetInfo> infolist = new List<AssetInfo>(parentSet);
        for (int i = 0; i < infolist.Count; i++)
        {
            AssetInfo pinfo = infolist[i];
            pinfo.RemoveChild(targetChild);
            pinfo.RemoveRepeatChildDep(targetChild);
        }
    }
    /// <summary>
    /// 清除我子节点被我父节点的重复引用,保证树形结构
    /// </summary>
    /// <param name="targetChild"></param>
    private void RemoveRepeatParentDep(AssetInfo targetParent)
    {

List<AssetInfo> infolist = new List<AssetInfo>(childSet);
        for (int i = 0; i < infolist.Count; i++)
        {
            AssetInfo cinfo = infolist[i];
            cinfo.RemoveParent(targetParent);
            cinfo.RemoveRepeatParentDep(targetParent);
        }
    }

private void RemoveChild(AssetInfo targetChild)
    {
        childSet.Remove(targetChild);
        targetChild.parentSet.Remove(this);
    }
    private void RemoveParent(AssetInfo parent)
    {
        parent.childSet.Remove(this);
        parentSet.Remove(parent);
    }

private void AddChild(AssetInfo child)
    {
        childSet.Add(child);
    }

/// <summary>
    /// 如果父节点早已当此父节点为父节点
    /// </summary>
    /// <param name="targetParent"></param>
    /// <returns></returns>
    private bool IsParentEarlyDep(AssetInfo targetParent)
    {
        if (parentSet.Contains(targetParent))
        {
            return true;
        }
        var e = parentSet.GetEnumerator();
        while (e.MoveNext())
        {
            if (e.Current.IsParentEarlyDep(targetParent))
            {
                return true;
            }
        }
        return false;
    }
    public bool HasParent(AssetInfo p)
    {
        if (parentSet.Contains(p))
            return true;
        return false;
    }
    /// <summary>
    /// 打包碎片粒度
    /// </summary>
    /// <param name="pieceThreshold"></param>
    public void SetAssetBundleName(int pieceThreshold)
    {
        AssetImporter ai = AssetImporter.GetAtPath(this.assetPath);
        //针对UGUI图集的处理,图集以文件夹为单位打包ab
        if (ai is TextureImporter)
        {
            TextureImporter tai = ai as TextureImporter;

string filePath = System.IO.Path.GetDirectoryName(this.assetPath);
            tai.spritePackingTag = filePath.ToLower().Replace("\\", "_").Replace(".png",string.Empty).Replace(".jpg", string.Empty).Replace(" ", string.Empty);
            
            //AssetBundleName和spritePackingTag保持一致
            tai.SetAssetBundleNameAndVariant(tai.spritePackingTag + ".ab", null);
            Debug.Log("<color=#2E8A00>" + "设置ab,Image资源: " + this.assetPath + "</color>");
        }
        else
        {
            string abname = this.assetPath.Replace("/", "_") + ".ab";
            //不是图集,而且大于阀值
            if (this.parentSet.Count >= pieceThreshold)
            {
                ai.SetAssetBundleNameAndVariant(abname, string.Empty);
                Debug.Log("<color=#6501AB>" + "设置ab,有多个引用: " + this.assetPath+"</color>");
            }
            //根节点
            else if (this.parentSet.Count == 0 || this.isRootAsset)
            {
                ai.SetAssetBundleNameAndVariant(abname, string.Empty);
                Debug.Log("<color=#025082>" + "设置ab,根资源ab: " + this.assetPath + "</color>");
            }
            else
            {
                //其余的子资源
                ai.SetAssetBundleNameAndVariant(string.Empty, string.Empty);
                Debug.Log("<color=#DBAF00>" + "清除ab, 仅有1个引用: " + this.assetPath + "</color>");
            }
        }
    }
}

1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160

用法:
1,选择Unity内我们所要打包的资源所在的文件夹;
2,菜单栏“AssetBundleMgr->SetAssetbundleName”,完成!看一下资源的AssetBundleName。

如:我选择了Prefabs文件夹,然后菜单栏“AssetBundleMgr->SetAssetbundleName”,资源都被正确设置了AssetBundleName。

————————————————
版权声明:本文为CSDN博主「漫漫之间n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012740992/article/details/79371986

Unity打包AssetBundle自动分析资源依赖关系(包括UGUI图集打包)相关推荐

  1. UGUI 图集打包工具Sprite Packer

    一.设计的目的:让开发者忘记图集的概念,使用小图去开发UI,unity自动会将这些小图按照tag名字打到图集里面去. 二.启用的方式:在Edit->Project Settings->Ed ...

  2. Unity3d之UGUI图集打包与动态使用(TexturePacker)

    前言 在用UGUI时,我们也需要将一个个小图打包成图集,以减小Drawcall(类似coco2d-x一样,打包成图集一次性加载以内存换取图片读取效率),UGUI打包并使用图集有两种方法:一种是使用系统 ...

  3. Unity UGUI图集打包与动态使用(TexturePacker)

    TexturePacker 在用UGUI时,我们需要将一个个小图打包成图集,然后将图集一次性加载以内存换取图片读取效率,即减小Drawcall. UGUI打包并使用图集有两种方法:一种是使用系统自带的 ...

  4. Unity5.x 依赖关系打包 AssetBundle 研究

    Unity5.x新依赖打包及加载 https://blog.csdn.net/strugglebydreamlin/article/details/78031086 demo:https://pan. ...

  5. 资源打包Assetbundle .

    在手游的运营过程中,更新资源是比不可少的.资源管理第一步是资源打包.传统的打包可以将所有物件制成预设Prefab,打包成场景.今天我们来一起学习官方推荐的Assetbundle,它是Unity(Pro ...

  6. Unity3d AssetBundle依赖关系获取

    PS:本文将从"打包之前"和"打包之后"两个方面去说明如何获取依赖关系 获取AB包依赖的作用 众所周知,如果一个AB包(我们称之为C)里面的资源引用到的其他资源 ...

  7. Unity最新版打包AssetBundle和加载的方法

    一.设置assetBundleName 二.构建AssetBundle包 三.上传AssetBundle到服务器 四.把AssetBundle放到本地 五.操作AssetBundle 六.完整例子 七 ...

  8. cluster oracle修改,Oracle 修改集群的资源属性(依赖关系)

    修改集群的资源属性: -- 在11g中 使用Crsctl modify resource res_name -attr 命令可以随意添加修改集群的各项资源的属性 来个例子: 查看数据库资源的全部属性: ...

  9. 软件开发项目管理中的依赖关系

    依赖关系亦称"逻辑关系".在项目管理中,指表示两个活动(前导活动和后续活动)中一个活动的变更将会影响到另一个活动的关系. 通常活动之间的依赖关系包括: 强制依赖关系(所做工作中固有 ...

最新文章

  1. poj2438(哈密顿回路)
  2. Thrift架构~thrift中间语言的认识(只有它什么都不是,它才有可能什么都是)
  3. Spring MVC-06循序渐进之Converter和Formatter
  4. 深度学习 CNN CUDA 版本2
  5. C++:求数字i以后的n个素数
  6. 20145302张薇 《信息安全系统设计基础》第14周学习总结
  7. 图神经网络的可解释性
  8. 如何阻止分布式拒绝服务***
  9. 从零单排PAT1015,1016,1017,1018
  10. Linux系统下安装flash player插件
  11. Word公式编辑器的使用方法
  12. kali:hydra破解ssh密码
  13. linux suse11 sp3安装,SUSE Linux Enterprise Server 11 SP3安装教程详解
  14. CiteSpace学习笔记(四)——功能区和参数区
  15. 爬虫玩得好,牢饭吃到饱?这3条底线千万不能碰!
  16. 如何看待哔哩哔哩(B站)的后端代码主仓库被上传至了GitHub?
  17. 怎样用Java求水仙花数和水仙花数的数量
  18. FFmpeg MP4 m3u8 视频 相互转换
  19. 人民币趣味品--收藏新宠
  20. 【Bluetooth|蓝牙开发】三、一篇文章,带你总览蓝牙协议

热门文章

  1. ASP.NET DataBinder.Eval与 Eval
  2. Tshock的config.json配置文件翻译(对应5.1.2版本)
  3. HSSF 读取excel
  4. echarts双坐标轴数据错乱问题
  5. 19年,改变,遇见更好的自己!(文末送电子书)
  6. Power bi 3.16 树形图
  7. 《华林科纳-半导体工艺》高效硅太阳能电池
  8. 掌握这6大技能体系:西安java培训
  9. 第27章 Python3 OS 文件 、 目录方法教程
  10. 如何评价工作了30多年,但是至今单身未婚的游戏建模师?