Unity加载模块深度解析(网格篇)
在上一篇 加载模块深度解析(一)中,我们重点讨论了纹理资源的加载性能。这次,我们再来为你揭开其他主流资源的加载效率。
这是侑虎科技第53篇原创文章,欢迎转发分享,未经作者授权请勿转载。同时如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)
资源加载性能测试代码
与上篇所提出的测试代码一样,我们对于其他资源的加载性能分析同样使用该测试代码。我们将每种资源均制作成一定大小的AssetBundle文件,并逐一通过以下代码在不同设备上进行加载,以期得到不同硬件设备上的资源加载性能比较。
测试环境
引擎版本:Unity 5.2版本
测试设备:三台不同档次的移动设备(Android:红米2、红米Note2和三星S6)
网格资源
网格资源与纹理资源一样,在加载时同样会造成较高的CPU占用,且其加载效率由其自身大小(网格数据量)决定。因此,我们通过选择不同数据量的网格资源来详细分析其加载效率。
测试1:不同面片数的网格资源加载效率测试
我们选取了四种不同面片数的网格资源,含有的面片数分别为1K、5K、10K和50K,且不含有Tangent顶点属性。四组网格资源的内存占用分别为195KB、0.8MB、1.4MB和3.9MB,其对应AssetBundle大小为43KB、108KB、178KB和507KB。
测试网格:
我们在三种不同档次的机型上加载这些网格资源,为降低偶然性,每台设备上重复进行十次加载操作并将取其平均值作为最终性能开销。具体测试结果如下表所示:

通过上述测试,我们可以得到以下结论:
1、资源的数据量对加载性能影响较大,面片数越多,其加载越为耗时。设备性能越差,其耗时差别越为明显;
2、随着硬件设备性能的提升,其加载效率差异越来越不明显。
测试2:相同面片数、不同顶点属性的加载效率测试
我们选择测试1中的网格资源做为该测试的样本数据,并在打包时加入Tangent顶点属性。则四组网格资源的内存占用分别为287KB、1.2MB、2.1MB和5.8MB,其对应AssetBundle大小为72KB、228KB、376KB和937KB。与测试1相同,我们在三种不同档次的机型上重复进行十次加载操作并将取其平均值作为最终性能开销。具体测试结果如下图所示:

通过上述测试,我们可以得到以下结论:
1、顶点属性的增加对内存和AssetBundle包体大小影响较大。与测试1中未引入Tangent顶点属性的网格数据相比,测试2中的网格数据在内存上均大幅度增加(增加量与网格顶点数有关),且AssetBundle大小同样有成倍(1~2)的增加。
2、顶点属性增加对于加载效率影响较大,且顶点数越多,影响越大。
注意事项:
模型常见的顶点属性主要有Position、UV、Normal、Tangent和Color。Color属性与Tangent属性一样,如果网格顶点拥有该属性,同样会对内存、物理体积和加载性能造成影响。
在使用Draw Call Batching时,切忌将不同属性的网格模型拼合在一起。举个例子 ,100个网格模型进行Static Batching,如果99个模型只有Position和UV两种属性,而剩下1个模型函数有Position、UV、Normal、Tangent和Color五种属性。那么引擎在进行拼合时,会将前99个模型的顶点属性补齐,然后再进行拼合。这样无形中会增加大量的内存占用,从而造成不必要的内存浪费。
测试3:开启/关闭Read/Write功能的加载效率测试
我们使用测试1中的网格资源数据,并关闭其Read/Write功能,从而来查看其Read/Write功能对加载效率的影响。关闭Read/Write功能后,四组网格资源的内存占用分别为104KB、454KB、0.8MB和2.3MB,其对应AssetBundle大小为38KB、94KB、152KB和428KB。与测试1相同,我们在三种不同档次的机型上重复进行十次加载操作并将取其平均值作为最终性能开销。具体测试结果如下图所示:

通过上述测试,我们可以得到以下结论:
1、关闭Read/Write功能会降低AssetBundle的物理大小,其降低量与资源本身数据量相关。同时,关闭Read/Write功能会大幅度降低网格资源的内存占用;
2、关闭Read/Write功能会略微提升该资源的加载效率。
通过以上测试和分析,我们对于网格资源的管理建议如下:
1、在保证视觉效果的前提下,尽可能采用“够用就好”的原则,即降低网格资源的顶点数量和面片数量;
2、研发团队对于顶点属性的使用需谨慎处理。通过以上分析可以看出,顶点属性越多,则内存占用越高,加载时间越长;
3、如果在项目运行过程中对网格资源数据不进行读写操作(比如Morphing动画等),那么建议将Read/Write功能关闭,既可以提升加载效率,又可以大幅度降低内存占用。
正是由于以上加载效率问题,UWA对每个网格资源参数进行了详细的分析。通过性能测评和资源检测两个工具,对项目在Online运行和Offline制作阶段进行双重检测,从而方便加快速查看资源的使用情况,定位引发性能问题的具体资源。
针对网格顶点数据的检测,可以通过以下两种方式:
1. 通过性能测评报告查看:
2. 通过资源检测报告查看:
针对网格顶点属性的检测,可通过性能测评报告进行查看:
针对网格顶点Read/Write功能的检测,可通过资源检测报告进行查看:
说明:以上测试数据为我们所用的测试网格加载数据,需要指出的是,不同网格资源的加载效率会略有相同,因为其数值的不同会造成AssetBundle压缩包大小的不同,进而造成最终加载效率的不同。同时,需要注意的是,加载方式的不同(一个协程逐资源加载/多协程同时加载),其加载效率也是完全不同的。关于这一点,我们将在后续文章中进行讨论。最后,我们后续会进行更多的测试,以期为大家提供更为普遍的测试结果。
以上为网格资源在加载时的性能测试。关于加载模块的性能问题,我们会不断推出Shader、音频等其他资源的加载性能分析、资源卸载性能分析、资源实例化性能分析、不同加载方式的性能分析等一系列技术文章,并对目前UWA所检测过项目的共性问题进行总结,以期让大家对项目的加载效率有更加深入的认知,并提升对加载模块的掌控能力。
Unity加载模块深度解析(网格篇)的更多相关文章
- Unity加载模块深度解析(Shader)
作者:张鑫链接:https://zhuanlan.zhihu.com/p/21949663来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 接上一篇 加载模块深度解析(二 ...
- Unity加载模块深度解析(纹理篇)
在游戏和VR项目的研发过程中,加载模块所带来的效率开销和内存占用(即“加载效率”.“场景切换速度”等)经常是开发团队非常头疼的问题,它不仅包括资源的加载耗时,同时也包含场景物件的实例化和资源卸载等.在 ...
- 创建以及加载模块【nodejs第四篇】
建立两个文件,文件一createModule.js ,文件二main.js createModule.js的代码,主要用于创建一个模块 /** * Created by Administrator o ...
- Linux驱动之内核加载模块过程分析
Linux内核支持动态的加载模块运行:比如insmod first_drv.ko,这样就可以将模块加载到内核所在空间供应用程序调用.现在简单描述下insmod first_drv.ko的过程 1.in ...
- CesiumJS 2022^ 源码解读[7] - 3DTiles 的请求、加载处理流程解析
目录 1. 3DTiles 数据集的类型 2. 创建瓦片树 2.1. 请求入口文件 2.2. 创建树结构 2.3. 瓦片缓存机制带来的能力 3. 瓦片树的遍历更新 3.1. 三个大步骤 3.2. 遍历 ...
- AngularJs 动态加载模块和依赖
最近项目比较忙额,白天要上班,晚上回来还需要做Angular知识点的ppt给同事,毕竟年底要辞职了,项目的后续开发还是需要有人接手的,所以就占用了晚上学习的时间.本来一直不打算写这些第三方插件的学习笔 ...
- AngularJS中多个ng-app(手动加载模块)
1.当有多个ng-app时:(首先是要加载angularJS) <div ng-app=""> <p>姓名:<input type="tex ...
- 老调重弹:JDBC系列之<驱动加载原理全面解析) ----转
最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者 ...
- apache加载模块的说明
转: apache加载模块的说明 2017年04月11日 15:23:35 刚子狂想 阅读数:1432 LoadModule auth_basic_module modules/mod_auth_ ...
随机推荐
- 经典的Hello World VFP前端调后端C# Webservice
1.按我设想的三层架构中,VFP是完全可以做为前端UI的,我们可以划分如下三层结构: 图片:三层架构图.jpg[设为封面] [删除] 其实大家看图,都明白大致意思,但是要明白各层数据是怎么流动的,却要 ...
- Qt事件过滤器Event Filter
事件过滤器针对一类或者多种不同类型的对象,定义了重写操作. 简单的说: 1.先对UI对象注册Event Filter 例如: ui->drawBtn->installEventFil ...
- jquery-1.3.2.js
Uncaught SyntaxError: Unexpected identifier
- Ruby-递归和尾递归
递归和迭代的区别 递归: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 迭代: 利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话 ...
- Android(Logcat、Monitors)
刚学习Android 的时候总喜欢输出"Hello Word"这样的信息来判断是不是执行了某个方法,最初连Android Studio控制台.断点这些在哪里都要找好久,现在好了多点 ...
- sql遍历
DECLARE @BTime DATETIME,@ETime DATETIME;DECLARE @Temp TABLE (ID BIGINT IDENTITY(1,1),aid BIGINT,newc ...
- hdu 1387(Team Queue) STL
Team Queue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- web程序员该学习什么
以我个人的观点分了几个级别,仅供参考 初级发展(学习期) 前端应该学习HTML javascript css 能够制造简单的前端页面满足自己的工作需求 后端应该学习asp.net or jsp or ...
- 第四十一章 微服务CICD(3)- jenkins + gitlab + webhooks + publish-over-ssh(1)
一.作用 使用webhooks来实现当git客户端push代码到gitlab后,jenkins会立即去gitlab拉取代码并构建. 二.步骤 1.安装插件 ruby_runtime(Hook插件依赖于 ...
- 使用merge同时执行insert和update操作
SQL点滴18—SqlServer中的merge操作,相当地风骚 今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在tech ...