热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

Unity资源打包之AssetBundle

AssetBundle的作用:1.AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;2.AssetBundle自身保存着互相

Asset Bundle的作用:

1.AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;

2.AssetBundle自身保存着互相的依赖关系;

3.压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;

4.把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小;

什么是AssetBundle

可以归为两点:

1,它是一个存在于硬盘上的文件。可以称之为压缩包。这个压缩包可以认为是一个文件夹,里面包含了多个文件。这些文件可以分为两类:serialized file 和 resource files。(序列化文件和源文件)

serialized file:资源被打碎放在一个对象中,最后统一被写进一个单独的文件(只有一个)

resource files:某些二进制资源(图片、声音)被单独保存,方便快速加载

2,它是一个AssetBundle对象,我们可以通过代码从一个特定的压缩包加载出来的对象。这个对象包含了所有我们当初添加到这个压缩包里面的内容,我们可以通过这个对象加载出来使用。

Asset Bundle资源打包实例

无论是模型资源还是UI资源,最好是先把他们放在Prefab中,然后在做成Assetbundle。我们以模型来举例,Assetbundle中可以放一个模型、也可以放多个模型,它是非常灵活了那么最需要考虑的就是模型空间占用的问题。

下面我们来实际操作下,首先随便先创建两个3D对象,Cube和Capsule,并将他们做成Prefab,然后去指定资源的AssetBundle属性,这里我将这两个模型都打包成model.ab包

(xxxa/xxx)这里xxxa会生成目录,名字为xxx ,后面的ab是后缀名,可自己制定。



设置好属性后,下面开始构建AssetBundle包,首先先创建一个文件夹命名Editor,这个文件夹是不会进行打包的特定编辑器扩展文件夹。然后我们创建一个编辑器扩展类CreateAssetbundles。写入下面的代码

using UnityEditor;
using System.IO;
public class CreateAssetbundles {
[MenuItem("AssetsBundle/Build AssetBundles")]
static void BuildAllAssetBundles()//进行打包
{
string dir = "AssetBundles";
//判断该目录是否存在
if (Directory.Exists(dir) == false)
{
Directory.CreateDirectory(dir);//在工程下创建AssetBundles目录
}
//参数一为打包到哪个路径,参数二压缩选项 参数三 平台的目标
BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows64);
}
}

BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载时间更长。使用之前需要整体解压。一旦被解压,这个包会使用LZ4重新压缩。使用资源的时候不需要整体解压。在下载的时候可以使用LZMA算法,一旦它被下载了之后,它会使用LZ4算法保存到本地上。

BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快

BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部。

注意使用LZ4压缩,可以获得可以跟不压缩想媲美的加载速度,而且比不压缩文件要小。

然后回到Unity里面点击我们刚刚扩展出来的打包按钮

点击后我们的模型就打包了出来,可以在工程的目录下可以找到AssetBundles目录,在AssetBundles下有个Scene文件夹里面就是我们的打包文件了,后缀是.ab



AssetBundle的加载

AssetBundle的加载有以下几种方式,从内存加载使用LoadFromMemoryAsync,从本地文件加载可以使用LoadFromFile,从服务器上Web上加载可以使用UnityWbRequest。下面我们来看看这几种加载的方式。

首先可以先把我们Unity里面的两个模型的Prefab Cube和Capsule删除了,然后创建一个脚本挂在Camera上,打开脚本

第一种加载方式(LoadFromMemoryAsync)从内存加载

using UnityEngine;
using System.IO;
using System.Collections;
public class LoadFromFileExample : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/scene/model.ab";
//第一种加载AB的方式 LoadFromMemoryAsync
//异步加载
AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
yield return request;
AssetBundle ab = request.assetBundle;
//同步方式
//AssetBundle ab= AssetBundle.LoadFromMemory(File.ReadAllBytes(path));
//使用里面的资源
Object[] obj = ab.LoadAllAssets();//加载出来放入数组中
// 创建出来
foreach (Object o in obj)
{
Instantiate(o);
}
}
}

第二种方式(LoadFromFile)从本地加载

using UnityEngine;
using System.Collections;
public class LoadFromFileExample : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/scene/model.ab";
//第二种加载方式 LoadFromFile
//异步加载
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
yield return request;
AssetBundle ab = request.assetBundle;
//同步加载
//AssetBundle ab = AssetBundle.LoadFromFile(path);
//使用里面的资源
Object[] obj = ab.LoadAllAssets();//加载出来放入数组中
// 创建出来
foreach (Object o in obj)
{
Instantiate(o);
}
}
}

第三种方式(UnityWbRequest)从服务器或者本地加载

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class LoadFromFileExample : MonoBehaviour {
IEnumerator Start () {
//第三种加载方式 使用UnityWbRequest 服务器加载使用http本地加载使用file
//string uri = @"file:///C:\Users\Administrator\Desktop\AssetBundleProject\AssetBundles\model.ab";
string uri = @"http://localhost/AssetBundles\model.ab";
UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri);
yield return request.Send();
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
//使用里面的资源
Object[] obj = ab.LoadAllAssets();//加载出来放入数组中
// 创建出来
foreach (Object o in obj)
{
Instantiate(o);
}
}
}

这样我们Model包里面的资源就加载出来并创建在场景里了。这时候运行Unity就可以看到两个模型都各自创建了出来



当然也可以创建指定的资源例如

AssetBundle ab=AssetBundle.LoadFromFile("AssetBundles/scene/model.ab");
GameObject go = ab.LoadAsset("Cube");
Instantiate(go)

这样就实现了Asset Bundle资源的加载了

AssetBundle分组策略

1,把经常更新的资源放在一个单独的包里面,跟不经常更新的包分离

2,把需要同时加载的资源放在一个包里面

3,可以把其他包共享的资源放在一个单独的包里面

4,把一些需要同时加载的小资源打包成一个包

5,如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分 v1 v2 v3 unity3dv1 unity3dv2

1,逻辑实体分组

a,一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)

b,一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)

c,所有的场景所共享的部分一个包(包括贴图和模型)

2,按照类型分组

所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包

3,按照使用分组

把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包

依赖打包

意思就是例如有两个模型使用的都是同一个材质和贴图,那么模型和材质贴图之间就是依赖关系。如果我们这两个模型都单独打包出来那么就会打包出两份材质和贴图,这样包就会变大,那么我们如何解决呢,这里Unity里面自带有一种方式,那就是首先先把所依赖的材质和贴图单独打包到一个文件夹中,然后再分别打包两个需要依赖这个材质和贴图的模型。这样Unity就会去查找这个材质贴图,发现这个材质和贴图已经打包了出来,那么它就不会去重复的打包材质和贴图了,这样就大大减小了包的大小



上面一个是直接两个模型分别打包出来可以看到材质和贴图都分别打包了出来,分别都是63KB,而下面的是先将材质和贴图打包出来是62KB再将两个2KB的模型打包出来,总共也才64KB。



这就是Unity自带的依赖打包.

但是加载的时候模型、材质和贴图都要进行去加载,不然就会出现财政的丢失

using UnityEngine;
public class LoadFromFileExample : MonoBehaviour {
void Start () {
AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/cube.ab");
AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/share.ab");
//GameObject go = ab.LoadAsset("Cube");
//Instantiate(go);
Object[] obj = ab.LoadAllAssets();//加载出来放入数组中
//创建出来
foreach (Object o in obj)
{
Instantiate(o);
}
}
}

使用AssetBundleManifest获取所有的包

在打包AssetBundle后出现一个AssetBundles和一个AssetBundles.manifest两个文件,打包出来的所有的AssetBundle包都会放在AssetBundles里面。



而AssetBundles.manifest是一个文本文件,里面有一些包的信息,下面可以打开看看

所以下面我们就可以去读取到AssetBundles然后获取里面所有的AssetBundle包

在Start方法里面写入

AssetBundle manifesAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
AssetBundleManifest manifest= manifesAB.LoadAsset("AssetBundleManifest");
foreach (string name in manifest.GetAllAssetBundles())
{
print(name);
}

这时候运行Unity就可以看到所有包都完整的输出出来了。



利用Manifest加载某个包所依赖的包

AssetBundle manifesAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
AssetBundleManifest manifest= manifesAB.LoadAsset("AssetBundleManifest");
foreach (string name in manifest.GetAllAssetBundles())
{
print(name);
}
string []strs=manifest.GetAllDependencies("Cube.ab");
foreach (var name in strs)
{
AssetBundle.LoadFromFile("AssetBundles/"+name);
}

运行后可以看到所依赖的Share包的资源也加载了出来

AssetBundle的卸载

卸载有两个方面

1,减少内存使用

2,有可能导致丢失

所以什么时候去卸载资源

AssetBundle.Unload(true)卸载所有资源,即使有资源被使用着

(1,在关卡切换、场景切换的时候

(2,资源没被调用的时候

AssetBundle.Unload(false)卸载所有没用被使用的资源

个别资源怎么卸载

(1,通过 Resources.UnloadUnusedAssets.

(2,场景切换的时候

文件校验

文件校验可以在文件传输的时候保证文件的完整性,例如A在给我传输了一个文件之前会生成一个校验码,对于这个文件只会生成这一个唯一的校验码,只要传输给我的文件有一点不一样那么校验码就会完全不同。所以A在传输给我文件的时候会把文件和校验码都传输给我,当我取到这个文件的时候我也会使用和A同样一个算法去生成这个文件的校验码,然后拿这个值和A传输给我的校验码比对,如果一样说明这个文件是完整的,如果不一样那么就重新传输。下面是几个算法生成的校验值

CRC MD5 SHA1

相同点:

CRC、MD5、SHA1都是通过对数据进行计算,来生成一个校验值,该校验值用来校验数据的完整性。

不同点:

算法不同。CRC采用多项式除法,MD5和SHA1使用的是替换、轮转等方法;

校验值的长度不同。CRC校验位的长度跟其多项式有关系,一般为16位或32位;MD5是16个字节(128位);SHA1是20个字节(160位);

校验值的称呼不同。CRC一般叫做CRC值;MD5和SHA1一般叫做哈希值(Hash)或散列值;

安全性不同。这里的安全性是指检错的能力,即数据的错误能通过校验位检测出来。CRC的安全性跟多项式有很大关系,相对于MD5和SHA1要弱很多;MD5的安全性很高,不过大概在04年的时候被山东大学的王小云破解了;SHA1的安全性最高。

效率不同,CRC的计算效率很高;MD5和SHA1比较慢。

用途不同。CRC一般用作通信数据的校验;MD5和SHA1用于安全(Security)领域,比如文件校验、数字签名等。

Unity Asset Bundle Browser tool

这是一个AssetBundle的查看工具,是Unity官方发布的一个扩展工具,可以查看帮助打包AssetBundle和查看AssetBundle内容。可以去GitHub上下载

https://github.com/Unity-Technologies/AssetBundles-Browser

下载后直接将里面的Editor扩展工具拖入我们的Unity Project工程中



然后再窗口Window下找到并选择AssetBundle Browser选项,就可以打开看到我们AssetBundle 窗口了

这是一个轻量级的AssetsBundle使用工具,里面可以打包可以查看打包的内容可以删除打包的内容,非常好用

链接:https://www.jianshu.com/p/5d4145cd900c



推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文总结了在开发中使用gulp时的一些技巧,包括如何使用gulp.dest自动创建目录、如何使用gulp.src复制具名路径的文件以及保留文件夹路径的方法等。同时介绍了使用base选项和通配符来保留文件夹路径的技巧,并提到了解决带文件夹的复制问题的方法,即使用gulp-flatten插件。 ... [详细]
  • 前端性能优化无损压缩webp格式的图片
    一、什么是webpWebP格式,谷歌开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的23,并能节省大量的服务器宽带资源和数据空 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了Redis中RDB文件和AOF文件的保存和还原机制。RDB文件用于保存和还原Redis服务器所有数据库中的键值对数据,SAVE命令和BGSAVE命令分别用于阻塞服务器和由子进程执行保存操作。同时执行SAVE命令和BGSAVE命令,以及同时执行两个BGSAVE命令都会产生竞争条件。服务器会保存所有用save选项设置的保存条件,当满足任意一个保存条件时,服务器会自动执行BGSAVE命令。此外,还介绍了RDB文件和AOF文件在操作方面的冲突以及同时执行大量磁盘写入操作的不良影响。 ... [详细]
  • 本文介绍了在Python中使用zlib模块进行字符串的压缩与解压缩的方法,并探讨了其在内存优化方面的应用。通过压缩存储URL等长字符串,可以大大降低内存消耗,虽然处理时间会增加,但是整体效果显著。同时,给出了参考链接,供进一步学习和应用。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
author-avatar
amy
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有