技术分享连载(七十)

技术分享连载(七十)

本期我们聚集了这些话题:Physics性能开销、iOS设备上的ZFighting、AssetBundle资源冗余、UI性能优化...


我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间20分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
UWA QQ群:793972859
UWA 问答社区:answer.uwa4d.com


物理模块

Q1:在游戏里没有使用物理(Physics)相关功能时,怎么把物理相关的性能消耗降到最低?
我们游戏里完全没用到物理相关的功能,只是因为需要做点击碰撞检测,所以GameObject上需要加上BoxCollider组件,但是Profile时会时不时看到Physics.Processing的消耗有点高,也不算非常高,但是理论上如果完全没用物理相关功能的话,总感觉这部分消耗是可以完全干掉的,对于Profiler中Physics模块中给的几个统计不太清楚是怎么计算的,目前使用的Unity版本是5.3.6f1版本。

请输入图片描述

请输入图片描述

就我们目前的分析来看,在Unity5.4版本之前,物理模块是会每帧都运行的。而在Unity5.4版本之后,如果没有使用任何物理相关的功能时(Rigidbody、CharacterController、Rogdoll、Cloth模拟等等),物理模块会被关闭。所以,就你的问题而言,物理模块的开销只能降低,而不能完全消除。

对于物理模块的开销,我们建议从宏观上进行了解,当你的项目完全没有使用物理模块时,那就需要从它的调用次数入手了。
Physics.Processing调用耗时:
请输入图片描述

Physics.Processing调用次数:
请输入图片描述

可以看到,很多时候,该函数的CPU耗时其实并不是物理开销过高,而是调用次数过多。这主要是因为Unity 5.x默认设置的Fixed Timestep为0.02,Maximum Allowed TimeStep为0.333。也就是说,物理模块每20ms更新一次,所以如果某一帧很卡(200ms),那么物理模块会被调用10次,这样耗时就直接上去了。而0.333表示如果该帧CPU开销超过333ms了,那么就不会再调用物理模块,所以上图中调用次数中最大是17次。

请输入图片描述
所以,如果想进一步降低物理模块的开销,在完全没有使用物理的情况下,可以将Fixed Timestep设置为0.05或0.1均可,降低它被调用的频率。同时,尽可能优化其他模块耗时,让每帧的总体耗时尽可能降低。另外,需要注意的是,修改Fixed Timestep也会影响FixedUpdate的调用,在修改之前一定要检测项目中是否有使用FixedUpdate。

关于Contacts、Rigidbody、Collider的说明和推荐值,在UWA Tips中均有详细的说明。同时,也可查看如何读懂UWA报告——物理篇
请输入图片描述

此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/595351860ac5cef316b72ea1
如您对该问题仍有疑问,可以转至社区进行进一步交流。


资源管理

Q2:Unity官方半透明Shader代码在iOS上运行出现问题,参考官方文档(https://docs.unity3d.com/Manual/SL-CullAndDepth.html)中Transparent shader with depth writes写了一个半透明的Shader,在所有iOS设备上都出现类似ZFighting的错误,在XCODE上看了一下,大致定位是深度写入/读取出现了问题。
正常情况

请输入图片描述
有问题的情况
请输入图片描述
环境如下:
Unity4.7.1 f1 graphics Api opengles3.0
测试设备:iPhone5s、iPhone 6、iPhone 6s.

同样的代码在Android设备上没有问题。
ios设备上将Graphics API 设置为OpenGL ES 2.0 和metal在显示正常。

同样的代码在Unity5.3.8上graphics ApI OpenGL ES 3.0 编译到iOS设备上显示正常。
请问是什么问题导致的呢?

第一个Pass预写深度,第二个Pass比较深度LessEqual,硬件差异以及图形API差异,是很难保证第二个Pass比较深度时Equal的。 是否可以手动设置一个深度偏移量来避免这个问题,相关文档可以参考: https://docs.unity3d.com/Manual/SL-CullAndDepth.html

此问答来自于UWA 问答社区,目前题主反馈已经得到解决,特此感谢 jim 提供的回答。
https://answer.uwa4d.com/question/5951d21d96a4c14c505c478d
如您对该问题仍有疑问,可以转至社区进行进一步交流。


资源管理

Q3:AssetBundle包字体bitmap A的使用到AssetBundle包Altas B时B冗余,比如我有个字体vip使用到betaCommon的altas。
请输入图片描述

然后betaCommon打成AssetBundle包。vip也打成AssetBundle包。但是 vip的AssetBundle包里面会包含betaCommon的png.这就造成了会有两份一样的png在内存中。

下图是vip的AssetBundle内容:
请输入图片描述

下图是betaCommon的AssetBundle内容:
请输入图片描述

根据研发团队提供的AssetBundle例子,已经复现了上述问题(我用的是Unity5.5.2版本),vip和BetaCommon两个AssetBundle确实存在冗余,其冗余度如下。
请输入图片描述

之所以出现冗余是因为vip和betaCommon两个Prefab实际上并没有建立其依赖关系(虽然mainfest上注明了存在dependencies)。所以,你的问题解决方式,只需要将BetaCommon Material设置为一个“显式”的AssetBundleName,那么冗余问题就不会存在了。
请输入图片描述

设置后,AssetBundle资源检测结果如下:
请输入图片描述

此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/5950ed9d4477ba5f1121521a
如您对该问题仍有疑问,可以转至社区进行进一步交流。


资源管理

Q4:Unity 5.x打包系统加载资源会出现两份相同内存吗?对此怎么理解呢?
主要是针对unity5.x,特别是5.3.6版本。 我看其他博文上说是AssetBundle一份内存,然后LoadAsset又是一份,但是我看文档不是这样子的,AssetBundle那份只是一个配置信息,真正的内存是在LoadAsset的时候,希望UWA能为我们统一下理解。

理论上,内存是不会重复的,AssetBundle的内存和资源的内存是不一致的,特别是Unity 5.3版本以后。

在5.3.6版本上,加载一个LZ4格式的文件大小为5MB的AssetBundle,其内存是非常小,也就是经常看到的SerializedFile,该值根据OS的不同而不同,而最大不会超过0.5MB(每个AssetBundle内存占用)。AssetBundle.Load加载资源后,内存才会随着加载的资源不同而出现明显提升的现象。

具体的AssetBundle使用介绍,建议查看Unity原厂Manual网站,或者你应该知道的AssetBundle管理机制

关于如何检测资源是否有重复,可以通过Profiler、 UWA资源检测与分析UWA GOT 来进行查看。

此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/59545f97ce12979679229559
如您对该问题仍有疑问,可以转至社区进行进一步交流。


资源管理

Q5:最近学习了UWA关于UI性能优化的直播,想问下切换UI场景使用AssetBundle加载慢,怎么优化界面进入速度,是应该预加载吗?

一般来说,界面加载慢主要的原因有,图集纹理的加载以及大量UI元素的实例化操作。
针对图集的加载,可以尝试合理的规划图集,尽量控制界面所引用的图集数量(即使用到了某个图集中的一个Sprite,也会加载整个图集);其次可以尝试对公共图集进行预加载,通常公共图集较大,且被使用的概率很大。

针对大量UI元素的实例化,这项开销大通常只发生在背包等复杂的界面中,而对于这类复杂界面可以考虑进行分步实例化,即首先实例化如外框、容器等部分的UI元素,然后分帧实例化背包中的UI元素,从而提高界面打开的速度以及流畅性。


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站(answer.uwa4d.com)上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(仅限技术交流)