UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - 性能
在上一期《特效优化：发现绚丽背后的质朴》中，我们主要针对UWA本地资源检测中和特效相关的知识点做了讲解。这些看似细小的知识点，很容易在大家的开发和学习过程中被疏忽，而长期的问题积累最终都会反映到项目的性能表现上。为此，我们将这些规则列出，并且以一个个知识点的形式向大家逐一解读。 本期，我们将主要面向粒子特效相关的检测规则：“特效运行时包含的ParticleSystem组件数量过多”、“特效播放时最大粒子数量过大”，“特效总贴图数量过大”，以及新增加的规则“开启各向异性过滤的纹理”。我们将力图以浅显易懂的表达，让职场萌新或优化萌新能够深入理解。 1、特效运行时包含的ParticleSystem组件数量过多 本条规则面向的核心其实是项目开发中最常见的一对矛盾：效果与性能。为了实现更为复杂、更为绚丽的展示效果，研发团队会添加各种粒子系统。在带来效果提升的同时，也会产生非常明显的性能消耗和渲染压力。所以我们需要科学地做减法，减少ParticleSystem组件数量，以降低部分特效效果的代价来达到和项目性能之间的平衡。 这里需要说明的是，规则给出的默认阈值是一个比较严苛的标准，研发团队可以根据自己项目的实际需求去设定符合现阶段性能承受范围的阈值。 2、播放特效时最大粒子数量过多 本条规则和我们之前在文章《【性能黑榜】掌握了这些规则，你已经战胜了80%的对手！》中提到的“粒子数上限超过30的粒子系统”的这条规则很相近。 合理的粒子数会使得特效的表现效果恰到好处，但过多的粒子数会给CPU和GPU的计算带来更大压力。在复杂的粒子特效下，由于大量各种粒子的存在，处理特效所带来的性能开销也会大幅度地增加。 天平的两端是特效总体效果和性能，所以我们的视角要提高到总粒子数上。在实际操作中，开发团队要尽可能精确地基于特效总体展示效果，对每一个粒子系统的最大粒子数都进行合理的规划与调整，这样才有可能在保证降低粒子特效更新开销的同时，依然能够接近或维持原有的特效效果。 3、特效总贴图数量过大 本条规则从另一个维度为开发团队提供特效相关的检测规范。贴图涉及的方面很多，在之前的文章《材质优化：如何正确处理纹理和材质的关系》和《粒子系统优化：Mesh模式下的优化策略》内我们曾简单介绍过，Shader对纹理的采样、材质对纹理的引用以及粒子系统对纹理的应用等，如果在使用时不细致，就会导致特效内的贴图资源上涨，从而带来内存和计算上的额外消耗。 所以本条规则从“贴图总数”的角度，为大家统计出这些包含贴图数过多的特效资源，以供开发团队对其进行进一步的优化，来为特效做瘦身。 4、开启各向异性过滤的纹理 在之前的文章《纹理优化：不仅仅是一张图片那么简单》中，我们对纹理的过滤模式有过介绍，简单来讲是为了降低纹理到模型表面的这个过程中发生的“失真”现象。 相比于之前提到的各种过滤模式，纹理“贴”到物体表面时，各向异性过滤多考虑了纹理贴合与视野观察角度的关系。在这个前提下，如果在U、V方向上，纹理像素对应到物体表面的关系不是1:1时，它会按比例在各方向上进行采样不同数量的点，并进行计算以得到最终的对应关系。 在纹理的过滤模式中选择Bilinear（双线性过滤）或者Trilinear（三线性过滤）时，我们就可以对Aniso Level进行调整，范围是从0到16。 当我们把摄像机调成与纹理表面成一定角度时，Aniso Level的作用就会显示出来。如下图是nisoLevel设置为0或1时的纹理的表现（即不进行各向异性过滤）： 下图是AnisoLevel设置为9时（这时候进行了各向异性过滤）的贴图情况。对比两张图就能很明显地发现视野远端的清晰程度是完全不一样的。 开启各向异性过滤，在这种要考虑视野角度的情况下，可以很显著地提升纹理的表现效果，但代价是更高的GPU性能开销。而且各向异性过滤主要适用于大面积的地面与地形设置，对场景内的物体来讲，开启相关纹理的各向异性过滤就有“杀鸡用牛刀”的浪费之嫌了，表现效果上的提升并不足以抵消或平衡由此带来的性能消耗和渲染压力。 所以本条规则筛选出这些纹理后，开发团队要根据实际情况，在充分考量使用场景、表现效果和性能消耗的多方平衡后，再去决定是否需要保留开启各向异性过滤。 希望以上这些知识点能在实际的开发过程中为大家带来帮助。需要说明的是，每一项检测规则的阈值都可以由开发团队依据自身项目的实际需求去设置合适的阈值范围，这也是本地资源检测的一大特点。同时，也欢迎大家来使用UWA推出的本地资源检测服务，可帮助大家尽早对项目建立科学的美术规范。 万行代码屹立不倒，全靠基础掌握得好！ 相关推荐 《UWA学堂训练营｜游戏自动化测试》 性能黑榜相关阅读 《那些年给性能埋过的坑，你跳了吗？》 《那些年给性能埋过的坑，你跳了吗？（第二弹）》 《掌握了这些规则，你已经战胜了80%的对手！》
Unity引擎模块分析—注重效率的你不妨这么做！
UWA GOT是UWA推出的本地性能优化工具，其Online功能限时免费中，并受到了大量开发者的试用和积极反馈。其中，它的总体性能分析模式主要便于研发团队直观地定位、验证和解决逻辑代码中的效率瓶颈。 然而我们知道，引擎模块的性能同样至关重要，仅仅逻辑代码的检测还无法实现系统、完整地定位瓶颈的目的。所以今天，我们在该工具中推出Unity引擎模块的检测。您只需要拥有一个UWA GOT，在本地真机上测试后即可把数据同步到官网，这些详细的数据就能立马呈现。 详细的引擎模块参数 目前，UWA GOT Online报告支持渲染、UI、粒子、动画、加载和物理这六大主流引擎模块的重要参数检测。如下图，在渲染模块页面中，我们可以查看不透明、半透明、视域裁剪CPU和相机后处理等CPU耗时的走势以及某一帧上的耗时。 我们也可以缩放某段测试区域，结合运行截图更直观地定位某些峰值处的表现。 对于引擎模块的重要参数，我们提供了UWA推荐值和相关的优化建议，便于研发团队进行有的放矢的排查和优化。 精准的逻辑代码堆栈 堆栈信息是我们定位性能瓶颈的鹰眼，这次版本的更新不仅丰富了引擎模块的重要参数检测，在逻辑代码中也可以查看更细致的引擎函数堆栈信息，并且通过总体、指定场景和指定帧来定位具体的调用详情。 特别的，在堆栈信息列表中，我们也提供了历史数据对比功能，针对于研发团队定制的性能或功能回归测试，我们可以直接在报告中查看指定重要参数的变化趋势，便于开发团队可以在第一时间验证测试结果。 这次的新功能小编就安利到这里啦！目前，该功能也在限免使用中，研发团队只需要拥有一个UWA GOT，就可以在总体性能分析模式中体验到该功能！还不快打开你的黑科技试一试呀^_^！ 关于UWA GOT Online UWA GOT 是UWA推出的本地性能测评工具，它方便研发团队在本地真机测试，并能在编辑器中搭建本地服务器查看性能数据。现在，在UWA GOT现有的本地测评模式上，我们增加了线上同步和分析功能，研发团队可以将本地测评的数据快速同步到UWA官网，生成在线测评报告，提供更高效的性能分析数据及有针对性的优化建议。同时，贴心的版本对比功能，方便研发团队轻松监测每次测试中的重要性能参数变化趋势，从质量管控上为项目的研发保驾护航。
新年伊始，随着大家紧锣密鼓地开始了工作，UWA每周推送的知识型栏目《厚积薄发 | 技术分享》已经伴随大家走过了100个工作周。回顾两年多来，我们分享了近500个和游戏开发、优化相关的精彩问答。这些问答不仅有具象明确的提问，也有详细周全的解答；既能供研发团队自身项目中即学即用，还能通过参与者的回答分析，帮助我们在解决问题的过程中触类旁通、鉴往知来。我们优选了10个开放性的精彩回答，分享给大家。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 1、如何在项目初期确定美术规范？ 在项目初期，没有任何正式美术资源的情况下，如何给出一个美术资源制作的规范给到美术呢？我明白，就上面的策划需求不能得出一个精确的制作规范，只是想要一个大概的推算方式，给出一些大概的参数，好让美术有规范可以参考。不知是否能给些指引？ 美术也可以按他们想要的精度先制作部分角色和场景，但只有有限种类的资源的情况下，有方法测算出这个精度在性能允许范围吗？也就是说这个精度满足策划需求，可以作为美术制作规范。例如只有一个角色（5000面，512贴图三张，80根骨骼），策划同屏要求20个，就在场景中摆20个一样的角色进去（因为只有一个），如果目标手机不崩溃，以后角色的制作就按这样做。这样可以验证这个精度吗？ 精彩回答1： 作为经历了一个新项目在大家都没经验的情况下做出一个刚小范围内测游戏的苦逼开发者，结合群里讨论，个人觉得以下经验可以参考： 1）选好对标游戏，扒资源来参考。比如畅销榜上的游戏，把资源解出来看，参考模型面数和贴图等游戏。这样最坏的情况下，参考别人能跑上线收到钱的游戏，收钱不保证，但是游戏性能的坑会少很多； 2）所有口头或文档的规范，都是无效的，不可能得到严格遵守，也就是说，不能用程序检测的规范都是空规范，全部做成Editor菜单检查校验； 3）用同一个英雄放20份测同屏的方法是不靠谱的； 4）从gfxbench.com上根据跑分选好基准机型，比如假设要兼容的机型是跑700帧的，那么基准机型得选6000帧的，预留好性能空间，性能别用得太满，否则没回旋余地: 5）贴图少用RGBA32，让美术在做图的时候，做出来一律以压缩模式的纹理来走Unity导真机包来看效果，千万别只是把美术图导手机相册里看效果，这会和真实的游戏效果有所偏差。建议规范只留两张2048*2048的纹理空间给美术发挥，其余全压缩，否则等美术在高画质模式作出效果后不肯降效果，逼程序优化，性能损耗非常大，程序会万分苦逼。 感谢李先生提供了以上回答。 精彩回答2： 这确实是个见仁见智并且取决于项目类型的问题，不过题主是在项目初期，想要快速迭代出策划的设计原型，并且要快速制作并且不用与程序产生过多沟通，在此前提下我觉得设定美术规范的首要目的是：不失控。制作出性能优秀的原型不是前期的目的，但毕竟是项目进展的一部分，如果美术资源制作没有标准规范参考，如果随便一个场景都是几十万面，DrawCall超过300，Overdraw可视化都红得发白，那到后面整个团队都要为此付出时间和精力，甚至返工。所以基本的制作规范也是十分必要的。 其次，在项目前期如何看待优化这个问题呢？我觉得过早的优化也是没有太大意义的，谈优化必须首先定位瓶颈，否则盲目优化除了降低资源质量和运算精度，对项目很难起到正面作用。这时项目处于快速变化中，不适合过早断定，所以在这个阶段依然是保证项目即使没有很优秀的性能，但是也没有很严重的问题，这就已经及格了。到了项目后期优化与效果的博弈，这又是另一个话题了。 在以上前提下，假设题主制作的是一个RPG游戏，主城+若干小副本推图，中端手机 iPhone 5，没有程序的太多干预，那么我的建议是： 1）大致规定好项目在 Unity 中的资源组织格式； 2）设定好 3dmax 导出模型的比例标尺，最好与 Unity 大小 1:1； 3）场景总面数均值5-6w左右（大部分），最高10w（少部分），单个模型300-1500面，摄像机可见部分2w以下，导出去除废点，多余的法线（如果没用的话），尽量单面； 4）场景总面数还要看同屏战斗人数多少做调整，Drawcall最好不超过50，一边给角色和特效留下空间，总 Drawcall 不要超过250这个尽量保证； 5）场景物体每个模型一个材质球，贴图256为主，正方形，pot(长宽2的倍数)； 6）严格限制场景中透明片的大小和重叠的个数，尽量少用，减少面积； 7）角色面数部分，主角1500以下；特殊boss2000以下；精英怪物1000面以下；普通怪物800面以下； 8）每个角色一个材质，除了特殊部件（翅膀等）一律不使用透明材质；贴图长宽相等，符合pot，128-256为主，最大不超过512； 9）去除 IK 节点和所有不必要的网格，对齐模型中心点与坐标原点； 10）预先规定好角色需要换装的所有节点名称，并且将需要换装的部分规定好并制作时拆开；（建议将脸部单独拆卡，脸部可增加面数）； 11）角色骨骼30-35根为主，特殊大boss适当增加，超过40慎重考虑； 12）可以考虑动画帧率10帧每秒，视具体情况或者不限制； 13）粒子单个发射器不超过50，每个特效最好10个粒子以下，同屏不超过500（200太低难以达到），尽量减少材质和粒子种类，大小，面积，层叠数等，粒子真的很费； 14）摄像机一定要调整远近裁剪面，尽量降低远近裁剪面的距离，默认数值过大，也千万不要图方便设置比如 0.1-2000这种，该数值极大影响低端机的深度缓存精度，引起过近的物体穿插闪烁； 15）使用最简单的线性雾，同时善用雾效和摄像机的 culldistant 功能，裁剪掉雾效淹没出的场景部件； 16）可向程序提出贴图导入自动处理工具，比如角色贴图：普通贴图 _D 结尾，法线贴图 _N 结尾，导入时工具自动设置大小和格式； 17）如果某个资源大于5MB，那么要仔细查看是否真的必要； 18）如果成使用工具完成的资源检查和设置，那么都尽量提出需求让程序满足； 19）最好有个人专门负责检查和整理资源； 以上只是摘取了一部分影响比较大的提了出来，也有一定的项目类型针对性，请根据自己的项目酌情参考和调整，实际细节还是比较多。另外，美术同学要善用 Unity 已经提供的各种工具，比如：面数, DrawCall，OverDraw 等等，这些都是直接又重要的基础指标，需要随时关注。美术同学也可以一开始不需要非常清楚这些标准背后的含义，尽量地去贯彻执行，久了就慢慢能理解，有空自己多去思考和追究；这些标准可以为少数情况酌情开特例，但不要太多。 感谢Yaukey提供了以上回答。 此问答来自于UWA 问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5941544c18d35e654e3e2373 2、美术资源导入管理 我们每次大批量地合入美术资源时，经常会出现构建出来的版本出现材质引用丢失、Animator Controller引用错误、贴图引用错误等资源引用错误的问题，美术资源在本地是正确的，其他人机器上Editor看也是正确的，构建机Editor看也是正确的，但构建出来的Bundle是坏的。有时删除Bundle再编会解决，有时则不行，目前遇到这种情况，只能让程序同事在构建机上删Meta重新做一次Prefab，费时费力而且不规范。 想问问这是Unity的Bug吗？大家有没有规避或者优化的方法？在管理美术资源合入的时候有没有更好的流程，我们目前使用Perforce管理Unity工程，要求美术显式上传资源配套的Meta文件。 精彩回答： 我根据我们项目遇到过的问题猜测下，我觉得项目资源导入某个地方有问题的可能性更大些，题主是否可能存在以下情况： 1）是否使用代码混淆。在Prefab 上挂的脚本忘记添加到排除混淆的列表，导致序列化的字段被混淆，打完Bundle后的Prefab资源加载时候，挂接的脚本出现引用错误； 2）资源导入都重载过OnPostProcess并处理了资源设置，这一步是否修改了什么不合理的地方，比如破坏了引用关系； 3）打包AssetBundle时，在构建Bundle 之前有没有使用文件操作API（不是 Unity 的AssetDatabase的API）来直接修改了某个文件夹或者其他会破坏引用关系的行为，然后构建Bundle，完成后恢复文件夹名字（或者恢复资源原始状态），这样丢失引用关系的几率很大； 4）有没有可能发布机器上，看着正常，但是Perforce里面已经存在一堆已修改的Meta文件；这种问题常出现于美术本地有两个A1，A2个相同资源在不同文件夹，A1受版本控制，但是由于某种操作，本地临时资源A2使用了原本A1的Guid，原本正确的 A1 被迫使用了不正确的新生成Guid（相当于两人交换），然后上传了A1的Meta，结果发布机器的下来的A1 Meta就会跟别人丢失引用，或者更新下来本地重新分配了新的Guid；美术策划最容易犯这个错误； 5）我们是Unity 5.3.8p2，上周遇到一个疑似bug，美术多上传了一组相同的资源，我们更新下来都会重新生成Guid，但是很多挂起的Meta在Unity里重新导入后，在版本控制里神奇地消失了，但修改还在； 6）如果都不是，只能尝试最小排除法了，删除项目绝大部分资源，一点点增加，然后打包，重现，排除原因；不行的话然后删除代码，一点点添加，打包，重现...有时候笨办法也是最容易接近真相的。 该问题来自UWA问答社区，感谢Yaukey提供了回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a0e8184e8a3d9357ce19473 3、Camera开启HDR对移动游戏的影响？ 我看到很多炫酷的效果都是用Unity的后处理来实现的，要求Camera开启HDR。但是我不知道开了这个选项会不会很耗，在中低端机上能跑起来吗？另外，使用HDR之后，Camera的Rendering Path是不是不能选Forward? 精彩回答1： 使用HDR可以选Forward，和Rendering Path的选择并不会相互影响。 在手机上单纯开启HDR(fp16)性能的影响并不会很大，各种后处理Pass的开销是要优化的重点。因为一般不会单纯开启HDR而不使用后处理，综合考虑到发热量等因素，不建议低端机器使用HDR和后处理，中高端再开启HDR并配合后处理，并对后处理做基础优化：比如适当降低后处理分辨率，尽量合并多个后处理流程到一个Pass等。 感谢贺甲提供了回答 精彩回答2： 开启HDR本身只是为后处理准备需要的数据，关键在于后处理的效率。假如说的是整个HDR实现的话，占GPU总体时间是一个相当可观的数值，大概可以认为是用带贴图透明片整屏绘制4，5遍左右的量（大概在这个数量级）。如果你只是想做泛光，使用更低质的效果的话，会好很多。 问题是，部分上古机型（诸如我的旧安卓机）本身对unity的后处理不兼容，只要对当前屏幕缓冲做任何操作都会导致卡死，不使用后处理主要是兼容方面的考虑，也就兼带着无法使用HDR了。 但是目前完全可通过兼容性测试来决定特定机型后处理的开关，一刀切的方式并没有必要。但这样又有一个问题：特定后处理提升的画面效果是否对得起它的消耗？是否有其他非后处理的方式可以实现类似的效果而消耗更低？（比如仅仅实现小物体的泛光用透明圆片堆叠效率比正常的Glow效率更高，虽然效果不好），这些也是导致后处理没有广泛使用的一个原因。 所以要看你具体想要实现的效果了。毕竟PSP这种机器末期在机能受限情况下也都在勉强实现后处理泛光效果，说明玩家其实还是有这样的需求的（虽然你拿出这样低质的效果很容易被产品BB糊了不如不加什么的……） 感谢唐翎提供了回答 精彩回答3： 手机上基本都是forward并不影响。不知道5.5.x情况。从5.6.x开始是可以通过设置Tier settings 来调整hdr mode. 有FP16也有R11G11B10格式。这两年手机GPU GFLOPS已经有了飞跃性的提升。附加个数据：比如meta9 一套4-5个后处理下来GPU消耗2-5ms. 感谢蒙占志提供了回答 此问答来自于UWA 问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59f810692f7f63497e0f6baf 4、如何加快打包速度？ 目前我们项目打出来的APK大小在120MB 左右，打一次包平均耗时在20~25分钟。Build过程中绝大部分的耗时在“Building Scene0”和“Building additional assets”这两个阶段。请问这两个阶段Unity具体是在做哪些操作？有没有什么方式可以减少这阶段的耗时？另外如果从硬件层面考虑，如何更有效地提高打包速度？提高硬盘的读写速度和CPU的性能又分别能带来怎样的耗时收益？ 精彩回答1： 我们使用的是AssetBundle的方式，目前600MB的包，没有太多资源修改的情况下，安卓包出包大约10分钟左右，之前是7-8分钟，不修改C#代码单独出Patch的话大致在5-7分钟。 我们在用的安卓打包机价格大约是1万左右，多CPU并且保证单核CPU的性能也是尽量高一些，SDD肯定必备，其他的没什么关系。 我们的CPU使用的是：Intel（R）Xeon（R）CPU E5-2683 v3 @ 2.00GHz 2.00 GHz 提醒一下关于贴图压缩，之前我们一直被贴图压缩折磨，高品质实在是太慢，后来我们是区分了Dev和Pub版本，Dev版本本地贴图压缩使用Fast，发布用的Pub版本才用Best的品质，速度快了非常多~即使美术大量修改贴图，Dev版本出包也很快。 感谢贾伟昊提供了上述回答。 精彩回答2： 我很久之前在Github上发现了这个东西： pvrtextool_wrapper：https://github.com/fxgames/pvrtextool_wrapper Unity打包会调用pvrtextool，通过这个wrapper替换掉原始程序，这样可以在打开发版本时，强制把压缩质量设置到fast模式，这样就可以节约大量的时间，而不需要修改任何贴图的压缩质量参数。如果觉得Mac Pro太贵了，可以试一下这个方法。 感谢lujian提供了上述回答。 精彩回答3： Building Scene 是Unity在打包场景资源中，Building additional assets 是Unity在打包Resources中的资源，我们项目接近600MB了，每次出包都要50分钟以上，苦不堪言。你可以尝试这样： 1）把资源全部使用AssetBundle的形式。除了第一次，在下次出包的时候，只会打包有变化和增量的资源。因为Resources的每次出版本都会重新打资源。这样可以将没修改的资源打包耗时省下来。 2）配置个好的电脑，把CPU换个好点的，硬盘换成SSD的。 以上2点能节省你出包的时间，目前也是我们使用的方法 感谢 hejianchun提供了上述回答。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a7abe4d847802258a06503d 5、如何在PC上检查美术的特效性能？ 有没有比较好的办法在PC上检查美术的特效的性能？我们之前做了个粗略的方法，就是扔N多特效在场景里，检查一下帧数，但是效果感觉不是很好，想听听大家的意见。 精彩回答1： 我们是写估分公式，也就是按一定的规则，遍历整个特效，根据节点的属性计算一个性能分。可以批量扫资源输出Excel查看。复用一下代码可以直接植入到编辑器，让美术做的时候就看到这个分。 不用很精准，这种方法90%的问题都可以很快发现。还可以预先定好规范，结合特效的使用情景来估算特效同时出现数*特效性能分会不会超标。 感谢招文勇提供了回答。 精彩回答2： 特效吃性能主要是OverDraw导致的。我们没在PC上检查，是拿真机检查。 PC的检查是用了钱康来提供一个看OverDraw的脚本，美术可以在做特效的时候大概看一下OverDraw，根据情况来调整。 然后我们构建真机包的时候生成特效列表名单，然后在进到主城之后，在聊天节目输入GM命令，遍历播放特效，每个特效可以通过播放1到n份，然后通过AdvancedFPSCounter插件记录当时的FPS值，记录到文件里。 然后找出帧率低的时候是哪些特效，然后针对性优化即可。 比如代码 if (cmd.ToLower().StartsWith("-gm texiaoplay3")) { Toast.ShowTip("测试美术做的一系列特效 " + cmd); prEffectTest(3); return true; } private static void prEffectTest(int efCount) { if (BilinCamera.Instance == null || BilinCamera.Instance.player == null) { Debug.LogError("找不到场上英雄，因此不能测试特效"); return; } TextAsset conf = Resources.Load<TextAsset>("effeclist"); string[] lines = conf.text.Split('\n'); //先同步加载一遍 for (int i = 0; i < lines.Length; ++i) { string prefabName = lines[i]; if (string.IsNullOrEmpty(prefabName)) { continue; } } BLDebug.isLog2FileEnable = true;//开启写文件 GameManager.Instance.StartCoroutine(prEffectTestAsync(lines, efCount)); GameManager.Instance.StartCoroutine(logUsedFPS(efCount)); } private static IEnumerator logUsedFPS(int efCount) { float startTime = Time.realtimeSinceStartup; float crtTime = Time.realtimeSinceStartup; while (crtEffectName.Length > 0 && (crtTime - startTime) < 6000.0f) {//100分钟内 crtTime = Time.realtimeSinceStartup; CodeStage.AdvancedFPSCounter.AFPSCounter aFPSCounter = CodeStage.AdvancedFPSCounter.AFPSCounter.AddToScene(); BLDebug.Log2File(TimeUtil.currentSqlTimestamp4LongAdv() + "\tlogUsedFPS" + efCount + "\t" + crtEffectName + "\t" + aFPSCounter.fpsCounter.LastValue + "\t" + aFPSCounter.fpsCounter.LastAverageValue + "\t" + Time.frameCount + "\t" + Time.realtimeSinceStartup); yield return new WaitForSeconds(0.1f);//每0.1s采样一次fps } yield return null; } private static string crtEffectName = "notbegin"; private static IEnumerator prEffectTestAsync(string[] lines, int efCount) { float periodTime = 5.0f; //开始逐个播放特效 for (int i = 0; i < lines.Length; ++i) { string prefabName = lines[i]; if (string.IsNullOrEmpty(prefabName)) { continue; } crtEffectName = prefabName; GameObject[] effectGoArr = new GameObject[efCount]; for (int k = 0; k < effectGoArr.Length; k++) { GameObject effectGo = PrefabUtil.loadPrefabToGameObject(prefabName, parentGo); effectGoArr[k] = effectGo; if (effectGo != null) {//是ui特效， GameObject.Destroy(effectGo, periodTime); } else { Debug.LogError("加载失败？？？" + prefabName); } } yield return new WaitForSeconds(periodTime); } crtEffectName = ""; BLDebug.UploadTodayLogFile();//把当天的日志传到服务器 yield return null; } 把日志导入Excel进行分析即可。 感谢李宗波提供了回答。 精彩回答3： 我们分了两块： 1、特效释放对于整体性能的影响部分，这个是针对结论性的统计，在真机上统计释放之后的帧率波动，目前的版本只做了往场景里扔来记录帧率的功能，主要评定特效对于游戏最终的影响； 2、特效的Draw Call、面数和Overdraw影响。这块的统计数据的获取我们目前只能在PC上获取，所以有一个工具在单机版本里逐个播放技能特效，统计对于上述三个指标的评价，找出超标的部分每周周会上给出报告列举出来。 个人感觉资源的检查一定有工具定期来做，持续监控才是最有效的优化方式。 感谢贾伟昊提供了回答。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a3b96e934968145049616fe 6、Graphics API的选择 大家现在在工程里还是选择只使用 OpenGL ES 2.0吗？我记得以前大家都是这么做的，现在这个做法过时了吗？iOS 是否该加上 Metal？ 精彩回答1： 我们目前都是用的Auto，主要有两个原因： Metal测试下来CPU Overhead会比GLES低很多 GLES3能够有tex2Dlod支持 兼容性上来说只有实在老的机器和模拟器会fallback到GLES2，可能效果上会略差一些不过我们测试下来都可以接受。 感谢钱康来提供了以上回答 精彩回答2： 我们现在快要上线的项目选的是ES3.0，iOS和Android都是选的这个，iOS选Metal的时候遇到模型显示不正常的问题，但是能力有限加上没时间没定位到原因，就统一成ES3.0了。选ES3.0还有一个原因，就是发现AssetBundle打出来的资源会比选Auto小很多。 还有就是目前我们的游戏偏重度，不指望用老手机的玩家会付费，所以放弃显卡太老的机型了。 感谢李先生提供了以上回答 此问答来自于UWA 问答社区：如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/594ddec949dc1fb06ce0685f 7、多维度材质对效率的影响 在目前的Unity版本中，使用多维材质是否会对效率产生影响，用多维材质和把模型分块哪个更好？ 制作美术资源时，应该尽量避免使用多维材质。先举例说明多维材质的一个优点是拆分模型做不到的： 一块大石头有石头和草地两个材质，做成一个整体的模型，使用多维材质，作为一个物件进行烘焙，在Lightmap上的UV分布是一个整体，不会出现拆分为两个模型烘焙产生的接缝问题。 除了上面这种情况，其他情况下推荐将模型拆分成多个模型赋予不同的材质。优点是： 1、多个模型会作为多个MeshObject参与到裁剪、静态批次等优化中； 2、拆分的模型和贴图可以进行材质合并，程序才能进行下一步的优化，如果本身是多维材质，就无法进行合并DrawCall的优化； 第一个优点就能带来很大的收益。制作上应该按照一个模型对应一个贴图的做法进行，如果模型是一个整体，比如房子由底座、墙体、屋顶组成，建议将他们多选导出成一个FBX。 另外，不同材质的模型建议做成多个模型，再多选导出成一个FBX，仍然是一个模型对应一个贴图的规范进行制作。 该问题来自UWA问答社区，感谢文雅提供了回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59e890dbe02a95cc6d0c4987 8、AssetBundle粒度规划 关于AssetBundle（下称“AB”）拆分粒度问题。在我的项目中，我是基于逻辑以及最终的打包大小来分的，比如尽量不让压缩后的AB包超过1MB, 这是UWA之前的推荐，同时也是因为当前版本Android包的SerializedFile占用大小（https://blog.uwa4d.com/archives/TechSharing_56.html）所考虑。经过这样的规划之后，我打包这块的代码基本是写死的， 包括手动把公共包拆成多个(公共包略大，不拆的话压缩后会有6、7MB)， 还有每个AB包的内容也是人为拆成多个。 这样虽然最后功能实现了，但个人依旧觉得不够自动化。每次新添加资源的时候， 都得走一遍这种手动流程。也研究了别人写的开源方案（https://github.com/tangzx/ABSystem），全自动分析依赖关系，但问题是最后包打得实在太细了，不太符合科学(但还是推荐大家学习)。所以就想问下各位的公司项目是如何解决这个AB 粒度划分问题的？ 精彩回答1： 这是一个相当开放的问题，仁者见仁，智者见智。UWA目前无法总结出一个统一的方式来建议如何进行打包，首先需要说明我们看到的两点情况： 1）没有最好的打包方式，只有最适合项目需求的打包方式； 2）无论是粗粒度打包还是细粒度打包，现在都有成功的项目在采用，这说明只要符合需求，两种打包方式都是很好的。 接下来，我们就粒度问题给出一些我们的看法： 1）AB粒度建议不宜过细，特别是一个资源一个AB 粒度过细，一方面会导致加载IO次数过多，从而增大了硬件设备耗能和发热的压力；另一方面，在我们测试过的Unity 5.3 ~ 5.5 版本中，Android平台上在不Unload的情况下，每个AB的加载，其每个文件的SerializedFile内存占用均为512KB（远高于其他平台），所以当内存中贮存了大量AB时，其SerializedFile的内存占用将会非常巨大。同时，需要进一步说明的是，该问题已在Unity5.6中进行完善。 2） 在Unity 5.3版本之后，对于AB文件的文件大小其实不必再限定于1MB之内 之前UWA有这一限定是出于两方面的考虑：一是New WWW在Unity 5.3之前是使用最为频繁的AB加载方式（虽然现在也是），在5.3版本之前，New WWW加载会形成一个比较大的WebStream，一般来说是压缩AB的4~5倍，会占用比较高的内存；另一方面，当AB较大（比如大于5MB）时，其加载开销会很大，由于是子线程中运行，所以真正反映到Profiler中时，大家会看到的一个“诡异”的CPU高开销——Graphics.PresentAndSync，具体原因可以看这里（ 扒一扒Profiler中这几个“占坑鬼” ）。所以，我们对此做了一些实验，发现将AB压在1MB以下是一个加载比较可以接受的情况。以上是我们之前为什么会提出1MB的主要原因。但Unity5.3之后，随着LZ4的引入，很多情况已经变化了，基于其Chunk的加载特点，AB加载很快，且内存占用要比之前小很多。所以LZ4的AB其实可以考虑更加粗粒度一些。 但是，这里仍然有以下三点注意： 1）对于需要热更新的AB，也如问答中其他朋友的所言，要考虑实际情况控制AB的大小； 2）即便是LZ4的AB，其加载方式不同，加载效率也可能完全不一致。以下是我们在UWA DAY 2017的分享，我们在两个不同的AB（LZ4格式）中都加载同一个资源，唯一不同的是一个AB包含10个Asset，而另一个AB包含30个资源，以下是三种不同方式从加载AB到AB.Load的耗时对比。可以看出，New WWW加载出现了明显的时间差异。因此，在Unity5.3之后，尽可能建议通过LoadFromFile(Async)来对AB进行加载。 3）对于AB的打包，尽可能把逻辑上同时出现（一个Prefab中非Share的Asset）、小而细碎的资源（Shader、Material、粒子系统等）尽可能打包在一起，并通过LoadAll来进行加载，因为这样会带来更好的加载效率。下图为LoadAll和Load One By One的性能对比。在我们做过的实验中，LoadAll确实会带来更好的性能开销。 上述是我们建议研发团队在AB打包时的一些注意点，希望对大家的项目优化有所帮助。 此问答来自于UWA 问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58e5bd96e042a5c92c3484ec 9、优化数据表的加载 安卓客户端存在大量的模板数据需要配置，其中一些模板表甚至可能达到万级的数据条目，那么怎么对这些数据模板表进行打包和加载，可以兼顾加载速度和热更新表结构？目前的方案是采用Protobuf代替ScriptableObject进行序列化，可以实现热更新模板表结构，但是加载速度相对ScriptableObject有较大的差距，目前数据模板加载较慢便导致了玩家进入世界的时间比较久。因此想了解大家有什么好的建议呢？ 精彩回答1： 本地读取数据表是个老话题了。我不能完全解答这个问题，只能提供一下我过去项目的浅显的经验。用ScriptableObject或者BinaryFormatter二进制存储然后反序列化成保存数据结构的对象，这两种方法应该是加载速度最快的。 我们实际没有采取这个方案，也使用的是Protobuf，是出于以下考虑: 一份二进制数据，客户端和服务器可以通用。从服务器推数据很方便； 策划习惯使用Excel编辑，有脚本可以把表格内容导出成Protobuf的二进制数据，另外，还有.cs/.go表结构描述文件需要重点考虑。也就是说，策划修改表结构、增减表，服务器和客户端的结构描述文件可以自动生成好； 实际用下来，确实会有一些差距。如何选择还是要看表格的体量了。 感谢WangLiang 提供了以上回答。 精彩回答2： 我先把问题拆分一下，题主遇到的问题如下： 第一个问题：配置表存储格式 现在主流的数据存储基本分为三大类，各有优劣，需要根据实际情况选择： 1、ProtoBuf或类似序列化库，这种方式兼容性高，但是加载速度一般； 2、自己实现二进制数据存储，兼容性差，需要精心设计达到较高的数据表达能力； 3、采用Lua热更新方案的游戏，普遍直接把数据存储为Lua表。 第二个问题：配置表数据与代码兼容 一般不建议大量修改数据结构，比如增删字段，如果实在无法避免，需要代码连同数据一起发布进行热更，做好版本管理即可。 第三个问题：配置读取速度优化 1）先从数据量上约减，减小数据冗余重复，数据存储设计优化，多次引用的字段多引用等等； 2）采用多线程加载，避免使用Unity提供的API，在游戏启动时，并行加载配置表，充分利用多核优势； 3）就我们自己项目而言，没有使用Lua的更新方案，但是我们依然采用Lua作为了数据存储，经过优化后加载速度也不错，可以参考 LuaTableOptimizer。 感谢Lujian提供了以上回答。 如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5981c5c5c08748f866b5ebe2 10、Unreal 4 Shadow Map Cache 我想问下Unreal 4的 Movable光源的Shadow Map Cache问题，它的具体更新策略是什么样的呢？如何处理动态物体与静态物体的关系？需不需要对Shadow Map进行Cascade？ 我同时也参考了Cry Engine的文档： http://docs.cryengine.com/display/SDKDOC2/Cached+Shadows 同时如果想移植到Unity，可行吗？或者我想解决大面积实时阴影的问题（光源方向会变化，大部分物体是动态物体 但是频率都不高）有什么解决方案吗？我可以在光源Space下预烘焙数据来达到光源方向变化，用一张Shadow Map的可能性吗？类似 Directional Light Map那种建立空间的？ 精彩回答1： Unreal 4的这个Movable Light的Shadow Map Cache只能给Static、Stationary物体用，因此我觉得其实是想给Movable光照下的Static物体阴影计算做个优化。但是Mobile端没必要用Movable，Stationary就好，Static物体的阴影是预计算的。 Unreal 4的动态物体在计算阴影的时候会计算两次，一次是从静态场景投射到动态物体，一次是动态物体投射到静态场景。在计算静态场景投射到动态物体阴影时，引擎会缓存一张静态场景的Shadow Map，用于计算投射到动态物体上的阴影。因此，对于动态物体也能接收到来自静态场景的精确阴影遮挡，但是这个方式比较耗时，而且mobile也不支持。 Unreal 4也提供了类似Unity的对静态场景投射到动态物体阴影近似解决方案，也是将shadow的预计算结果存储到带有间接光信息（也是SH）的点云（在Unity中就是light probe）中，然后根据动态物体的位置从点云插值出阴影遮挡，但是这种方式只能得到物体整体明暗度的变化，无法计算精确阴影。Unreal 4是推荐mobile上使用后面一种方法的。 需要补充一下的是，Unity解决动态物体接受静态物体烘焙阴影也是采用Light Probe的。题主说是动态光源，动态物体，最好还是实时阴影计算。如果是采用Shadow Map Cache的方案做优化，可能得看具体场景和需求。预计算烘焙多个Shadow Map的方案可能需要考虑两个因素，一是光源变化，二是动态物体变化。如果动态物体和光源变化频率都不高，那么可以尝试对它们采样预计算好Shadow Map。但是这样带来的Shadow Map占用空间和内存开销我们也不清楚，可能得尝试一下才知道。 以上回答由UWA提供。 精彩回答2： 关于Unreal 4的实现，楼上已经说得很详细了，可以参考Unreal 4源码ShadowSetup.cpp/ShadowDepthRendering.cpp，搜索SDCM_StaticPrimitivesOnly相关的代码即可，我补充一下其他问题： 1）针对动静物体怎么处理 在手机上比较难完美，可以针对静物渲染一张SM，动态物件用planar shadow解决 2）Shadow Map Cascade 缓存的话，Shadow Map不能随时更新，如果镜头频繁大距离移动，cascade不能跟随镜头随时更新，过度可能会不自然，这需要根据项目特性权衡 3）能不能光源动，Shadow Map用同一张 看你怎么动，如果是模拟日光，轻微转角，那你只能放弃精确阴影计算，在判断某个空间点是否在阴影区时增加偏转角，相当于把阴影做平行四边形变形 如果想360度转，目前我也没有很好的思路能兼顾cache和平滑转动时的过度，毕竟物体的四面都长得不一样，不可能用一张shadow map做平行四边形变形而不穿帮。 感谢招文勇提供了回答。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a0e6dc2e8a3d9357ce1946d
本期聚集了这些话题：半透明渲染对性能的影响、PSS内存在部分机型上暴涨、Action函数的性能、ShaderVariantCollection生成设定...... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 渲染 Q1：在UWA性能优化报告中，有个专门针对半透明渲染的性能消耗说明，导致半透明渲染高开销的一般有UI、场景和粒子等，那么想知道，UI（好像大部分UI都是有带半透明的）对半透明的影响有多大？在制作UI上有没有什么注意事项？ 就现在的大多数移动项目而言，这个影响是很大的。在半透明渲染的CPU端，主要有两点需要注意： （1）UI Draw Call；（2）UI的重建。 UI Draw Call越高，其渲染耗时越大，所以，建议在题主在UWA测评报告中的CPU详细性能堆栈中，查看UI的Draw Call使用情况。一般移动游戏，都建议将其峰值控制在40以下。而如果降低UI Draw Call，主要还是图集打成Atlas、避免穿插等等，具体的可自行Google。 UI重建同样会造成开销过大，主要表现在主线程的self等待开销中，当UI重建的网格体量较大时，这种情况容易出现。所以，尽可能避免不必要的UI网格重建，也是研发团队在UI制作时需要特别注意的地方。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a731c34e3b569146eeaeb35 内存 Q2：最近我们发现游戏在魅族Pro5在运行时，PSS内存会暴涨，使用UWA GOT测试，发现资源内存并都没涨，而且这个问题目前只在魅族Pro5上出现，其它机型没有这个问题，请问该怎么解决呢？ 我找了一个简单工程，如下图NPC名字跟阴影不能同时显示，否则就会导致PSS内存暴涨。 如下图，GfxDriver内存一直在涨，一秒涨2MB左右，只增不减。运行久了，魅族Pro5会崩溃。 如果GfxDriver和PSS一起升高，那么说明GPU方面存在Bug的概率很高。只能建议如下： （1）尝试在特定机器上不加入“UI阴影”，从制作上进行规避； （2）尝试在更高Unity版本中运行Demo，查看其内存问题是否会修复。 后经题主再次反馈，把 Unity版本从5.4.5升级到5.5.6，然后把 auto graphics api勾选上后，内存爆涨的问题就解决了。如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a741b6fe3b569146eeaeb3a 其他 Q3：new Action(Function)和直接传入Function函数区别是什么？例如以下两个函数有啥区别？ void Method(Action action) { } void MethodCallBack() { } void Start() { //Method(new Action(MethodCallBack)) 和 Method(MethodCallBack) 有啥区别？ 哪个性能高？ } 两者理论上是一样的，因为Method(MethodCallBack)在编译时，编译器会自行给它包一层new Action。所以这两种写法从编译结果来看，是一致的。 这两种写法如果在项目中只是偶尔调用，是没有问题的，但如果被频繁调用，那么比较好的写法是在外部定义一个Action，然后将该Action传给Method来进行复用，即 Action act = New Action（MethodCallBack); void Start() { Method(act); } 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a72f4dba69c4f5b6d1a9949 动画 Q4：我们使用的是老动画系统，动画是单独打包的，在运行时通过AddClip添加动画到模型上去，但是AddClip会触发RebuildInternalState导致波峰，那么大家是怎么解决这个RebuildInternalState触发的波峰呢，难道是只有老动画系统才会发生这个情况吗？ RebuildInteralState在Mecanim中也是有的，只是不叫这个名字了，而是变成了“Animator.Initialize”，两者的作用和触发时刻都差不多。 AddClip确实很耗时，这个在以前就是如此，所以建议如无特殊需求，AddClip尽可能在切场景时进行替换，在Runtime（特别是战斗中时）是不建议频繁调用AddClip的。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a702a5d1c1b88125112c7b8 资源管理 Q5：我查看了UWA上所有关于ShaderVariantCollection的资料之后，自己动手开始做一个ShaderVariantCollection预加载Shader，由于Shader变种比较多以及方便维护，准备写一个工具查找所有需要的Shader.keywards组合， 在生成ShaderVariant的时候有一个参数是PassType。通过Material.GetTag(“LightMode”, true)查找的时候有两个问题： 1）一个Shader里面可能有多个SubShader或者Pass使用不同的LightMode，但是通过GetTag(“LightMode”, true)只能找到第一个； 2）有一些Shader里没有设置Tags{“LightMode”=XXX}（主要是第三方插件），这个怎么处理比较合适？ 我查找工具脚本在这里：https://paste.ubuntu.com/26462717 题主可以尝试反射大法，可以同时找到Keyword和Passtype。 static MethodInfo GetShaderVariantEntries = null; public static List<string> GetShaderKeywords(this Shader target) { if (GetShaderVariantEntries == null) GetShaderVariantEntries = typeof(ShaderUtil).GetMethod(“GetShaderVariantEntries”, BindingFlags.NonPublic | BindingFlags.Static); int[] types = null; string[] keywords = null; object[] args = new object[] { target, new ShaderVariantCollection(), types, keywords }; GetShaderVariantEntries.Invoke(null, args); keywords = args[3] as string[]; List<string> result = new List<string>(); foreach (string keyword in keywords) { foreach (string t in keyword.Split(' ')) { if (!result.Contains(t)) result.Add(t); } } return result; } 感谢钱康来提供了以上回答。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a6ace59cd437d6b816b7ef8 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站（answer.uwa4d.com）上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（仅限技术交流）
UWA官方Demo新增《小米超神》，全面揭秘重度手游的性能表现！
还记得UWA【博观约取】专栏推荐的《小米超神》吗？作为一款重度的MOBA手游，它在不同配置的移动设备上，无论是画面表现力，还是性能开销都非常优秀。我们曾公布过该游戏的主要性能数据，当然其出色性能的背后和各方面的细节处理都有着千丝万缕的联系。为此，我们将该游戏的完整性能数据以UWA demo的形式公开，从而让大家更细致全面地感受其每个引擎模块的具体表现。 为什么重度游戏的性能如此小清新？不妨跟随小编的脚步一起到UWA官网上揭秘吧！ 再此特别感谢研发团队福州朱雀网络对UWA的认可和支持，也感谢他们乐于将项目性能数据与大家一起分享。 首先，我们登录UWA首页www.uwa4d.com，点击观看演示demo。 在性能诊断与优化的示例项目中选择《小米超神》。 同时我们也支持VR项目测评，大家可以点击下图右边的demo了解VR项目的性能报告。 下面我们来围观下《小米超神》的性能报告。下图为报告的性能总结页面。研发团队能从宏观上高效分析项目运行时的整体趋势，包括总体CPU性能、GC调用频率和引擎各模块性能等，同时也能根据同类型项目中的排名，对性能的薄弱环节一目了然，使得优化更加有的放矢。 UWA报告也可以协助开发团队从各个引擎模块（渲染模块、物理模块、粒子模块、动画模块、UI模块等）的微观处深入剖析项目的性能。下图即为UWA报告中渲染模块的耗时，可以看到该模块中有DrawCall、Triangle、半透明和不透明渲染耗时等参数的具体使用情况，条分缕析，疏而不漏。 UWA报告中能展现内存模块的详细使用情况，涵盖了几乎所有资源如纹理、网格、动画、音频等。不仅如此，各个资源的属性（如纹理的高度、宽度，数量峰值等）都一览无遗。在成百上千个资源文件中，即使再小的资源漏洞都无处遁形。 下图为《小米超神》的纹理资源具体使用情况。 90%的性能问题都和加载息息相关，而对于加载问题的定位这正是UWA性能测评的亮点之一，在《小米超神》报告中的资源管理界面中，对于加载/卸载的API调用使用情况，我们能一目了然。 我们可以看到资源加载和卸载的具体操作情况，不仅可以让用户看到整体加载耗时和加载次数，同时还可以通过图表来显示具体每次加载的位置和耗时。 下图为资源实例化功能，通过该功能，开发者能明确任何一个GameObject在实例化和销毁时的CPU占用情况：不仅可以看到最为耗时的GameObject，同时还能看到每次触发的时间点。 需要说明的是，上文提供的这些数据只是报告中的冰山一角，作为一支优秀团队精心打造的重度MOBA手游，我们强烈推荐大家多研究其报告中各个模块的性能细节以加深认知。同时，UWA真正想让大家看到的不仅是数据，更是数据背后我们研究问题的方式和厚积薄发的态度，这也是以后能切实帮到大家的东西。 温馨提示：PC上登录www.uwa4d.com即可以查看该游戏的完整性能数据。 UWA会员功能一览 简单优化，优化简单。这是UWA成立之初的愿景，我们希望UWA能帮到任何一个项目，哪怕是提速一毫秒。如果您的项目也存在运行卡顿、包体过大、资源冗余、内存泄漏、内存过大，代码效率低下、加载龟速等问题，不要犹豫了，时间不等你，让UWA为你助力！ 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（仅限技术交流）
专业的优化服务，就是为你争取时间！
时间对于游戏研发团队的重要程度毋庸置疑，它不仅体现在研发成本上，还隐藏了另一个更重要的因素：机会成本，这从最近如火如荼的吃鸡大战即可窥见一斑。而性能优化作为研发过程中的必经之路，也逃不开这样的命题，这也是为什么UWA要反复强调时间的重要性：如果我们把项目的性能优化到极致，使得项目早一天上线，覆盖更多的用户群，则能把时间价值最大化地转换为可观的财富。 UWA的优化服务，就是在争取更多时间 在服务开发者的过程中，UWA的想法很简单，就是和时间赛跑：在最短的时间里，帮助研发团队找出最高效的优化方法，将性能优化的时间逐步缩短，从而为项目的顺利上线保驾护航。因此，UWA不仅能节省大笔研发开支，还能为项目的运营推波助澜。 在UWA优化过的项目中，项目的性能普遍都有明显的提升。下图为某一项目的性能提升变化，经过7～15天的密集优化，大于33ms的CPU耗时帧数占比从83.2%骤降至10.7%，不仅大幅度提升了游戏的运行流畅度，还很大程度上改善了游戏的发热情况。短时间内解决性能问题，这节省的不仅是大量可预估的研发成本，同样还有潜藏的机会成本。 性能优化不仅可以为你节省研发成本，还可以为整个项目的后期推广节省大量的运营成本。《一起来飞车》项目组反馈，游戏在经过优化后，用户留存率提升了10%。这是什么概念？我们不妨按照如下公式来做个计算： 假设导入的用户量为100万，由于性能的改善使得用户的留存率增加了10%，同时我们假设每个用户的平均获客成本为25元，那么游戏在优化后每导入100万用户，其运营成本就可以节省250万元。 目前，在UWA上优化的测评测试已达到上万次，UWA团队也有幸见证着不少品质精良的游戏的诞生，它们经过周而复始的匠心打磨，最终在漫如星斗的游戏市场熠熠生辉。 UWA性能测评报告的含金量有多高？ 在UWA主打的性能测评工具中，用户可以将其需要评测的项目上传至官网，在24小时内得到一份性能报告。这份报告既能从宏观上分析项目运行时的整体趋势，包括总体CPU性能、GC调用频率和引擎各模块性能等，也能从微观上深入剖析内存管理、资源使用以及逻辑代码在运行时的效率瓶颈。研发团队通过对报告提供的方案进行针对性的优化，能在短期内提升项目的运行效率。 以下为部分专业版功能介绍： 剖析资源的具体使用情况 详尽的资源信息展示，从多种维度（如资源名称、生存周期、内存占用、数量峰值、格式等）定位可能存在问题的资源，从而对“问题资源”快速定位、即刻优化。 轻松定位泄漏的资源 通过比较不同时刻同一场景（或不同场景）的资源信息，可以快速定位其资源使用的差异，只需判断这些“差异”资源的存在是否合理，即可快速判定是否存在资源泄漏，以及具体泄漏的资源。 AssetBundle驻留分析 不仅显示AssetBundle的具体使用情况，包括具体的AssetBundle名称，存放位置、加载方式、还能查看内存中的驻留时长和由该AssetBundle加载出的资源数量，查看是否存在AssetBundle泄漏，并判断使用是否合理的情况。 资源Resource加载/卸载定位 不仅可以让用户看到整体加载耗时和加载次数，同时还可以通过图表来显示具体每次加载的位置和耗时。 GameObject Instantiate/Destroy分析 让开发者明确任何一个GameObject在实例化和销毁时的CPU占用情况：不仅可以看到最为耗时的GameObject，同时还能看到每次触发的时间点。 GameObject Active/ Deactive 分析 某些GameObject的Active/ Deactive的频繁切换会导致大量的CPU耗时，该功能可对这些资源进行详细检测，查看是否有进一步优化的空间（比如纹理可检查其分辨率、格式等）；当研发团队明确了加载或者实例化的瓶颈后，可针对具体资源、GameObject进行缓存，从而降低其CPU耗时。 重要参数解析 深度剖析影响性能的重要参数，从CPU开销、堆内存分配、调用次数和调用路径等多个维度让用户的优化更加有的放矢。 定制化的分析建议，解决“你”的问题，方为优化 在用户得到的性能测评报告中，UWA结合丰富的项目优化经验，不仅能对每一个测试模块的数据给出合理的评定，同时对于超出正常范围的“异常”，UWA也能快速定位瓶颈的来源，即可提供有针对性的方案。 同时，所有UWA的专业会员，都能享有定制化的技术指导，以协助用户更深入地了解项目本身的性能问题，以及如何更合理地使用报告的高级优化功能进行针对性的改善，全程为项目的性能保驾护航。 简单优化，优化简单。这是UWA成立之初的愿景，我们希望UWA能帮到任何一个项目，哪怕是提速一毫秒。如果您的项目也存在运行卡顿、包体过大、资源冗余、内存泄漏、内存过大，代码效率低下、加载龟速等问题，不要犹豫了，时间不等你，让UWA为你助力！ 所有的优化，都是一场和时间的较量。 时间不等你，还好有UWA陪你。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（仅限技术交流）
今天我们为大家带来由福州朱雀网络研发的MOBA手游《小米超神》的UWA测评报告分析。该游戏在不同配置的移动终端设备上，无论是画面表现力，还是性能开销都非常优异。在此，我们将对该款游戏的性能数据进行深度剖析，希望通过这篇文章可以让大家对移动游戏各个模块的运行效率有更为深刻的认知，并对大家的项目研发有所帮助。 一、CPU性能 该游戏在CPU占用方面的性能非常不错，下图为该游戏在红米Note2设备上进行一场5V5战斗时的性能数据。 可以看出，在红米Note2上运行的19876帧中，超过33ms的帧数占比为13.9%，超过50ms的帧数占比为1.7%，并且从图中可以看出，其CPU耗时较高处主要集中在5V5场景的资源加载阶段。因此，该游戏在战斗时的性能可以说是非常优秀，绝大多数时刻游戏运行非常流畅。 同时，通过进一步统计，该游戏的CPU性能超过了64%的同设备（红米Note2）上测试的其他游戏，其能耗更是低于86%的同设备测试游戏。由于目前国内的MOBA游戏较少，所以上述排名并不是在MOBA类型中的排名，而是在所有类型游戏中的排名。对于一款超重度的MOBA移动游戏来说，该CPU性能和能耗排名可以说是相当出色。 其整体CPU性能的优秀表现与其各个模块的合理使用是分不开的。下面，我们就详细讲解其CPU性能方面的亮点之处。 1、渲染模块 通过UWA性能测评报告，我们可以看到该游戏详尽的渲染模块性能开销。该游戏在红米Note2设备上运行时的渲染模块CPU开销如下图所示。通过统计，半透明物体渲染的CPU消耗均值为1.7 ms，主要集中在0.8~3.0 ms范围内（5%~95%）。不透明物体渲染的CPU消耗均值为1.0 ms，主要集中在0.2~1.7 ms范围内（5%~95%）。可以看出，在整个5V5战斗过程中，无论是移动、Farm、Gank还是团战，甚至上高地时，其渲染耗时都稳定在一个较低的耗时区间。这得益于研发团队对于场景模型、蒙皮网格和UI的控制十分得当。 Draw Call峰值为167，且主要集中在 45~130范围内（5%~95%），渲染三角形面片单帧峰值为64900，以上数值均处于合理范围之内。 2、UI模块 该游戏在红米Note2设备上运行时的UI模块CPU开销如下图所示。该游戏使用UGUI作为UI界面的解决方案。经过统计，UI模块总体的CPU占用均值为1.5 ms，主要集中在0.1~3.5 ms（5%~95%），属于合理范围之内。堆内存累积分配为16000帧 2.4MB，平均每帧分配堆内存155.4B，这说明该游戏UI界面的制作及UI重建的影响范围非常合理。目前，UWA推荐UGUI模块中，平均每帧堆内存分配尽可能控制在200B以下。 战斗场景中，UI系统的性能耗时主要是由UI元素的状态变化而导致的，比如血条、飘字等HUD的移动、消隐等。这种操作稍不注意，就会带来较高的UI网格重建开销。所以，UI界面的研发看似直观、简单，但是其对于制作时的层层考究和运行时的耐心调优，则是一款产品是否“匠心”的试金石。以下则为《小米超神》这款产品在经过几轮优化后的UI性能对比图。 3、动画模块 在UWA测评报告中，该游戏运行时的动画模块CPU开销如下图所示。可以看出，除进入场景时出现CPU高值外，其在战斗副本中的CPU开销均控制在较低水平。Animator.Update的CPU均值为2.0 ms，主要集中在0.1~4.3ms区间内，对于MOBA项目5V5场景来说，基本上每帧均有90-130个物体在进行运动（除英雄、小兵之外，还有信使宠物、野怪、塔、插眼等等），由于玩家可以随意查看地图上任何一个角落的特点，其每帧的动画系统压力要比常规的MMO游戏大上数倍。因此，《小米超神》可以将其控制在均值2.0ms的水平线上，已经是非常优秀的数据了。 同时，经过进一步检测发现，动画模块的耗时主要由Animators.ProcessAnimationsJob和Animators.FireAnimationEventsAndBehaviours导致，前者主要是持续的累积耗时，而后者则是非连续的“尖刺”开销。前者是动画系统对于AnimationClip的读取和计算耗时所致，其耗时大小与当前帧参与计算的骨骼节点数、动画曲线数、动画执行状态和Animator Controller的具体设置相关，其具体说明可参见《Unity中动画系统性能优化方案回顾》；后者则是动画事件的具体耗时，主要是项目逻辑代码的性能开销，此处研发团队可以通过性能堆栈来进一步查看其逻辑代码的开销是否有进一步的优化空间。 4、GC 调用 该研发团队对于GC调用频率控制得非常出众，游戏在运行过程中，GC调用频率为1656帧/次，优于目前93%的行业内游戏。一般来说，我们建议一款项目的GC调用频率可以控制在1000帧/次以上。 该游戏的GC调用频率如此优秀，主要得益于研发团队对于项目代码堆内存的控制。下图为游戏运行20000帧的代码堆内存具体分配情况，其Top10函数的堆内存分配总和不超过80MB，足见该团队对于堆内存分配的理解非常深刻。 当前版本的堆内存分配仍然有进一步下降的空间，从堆栈信息中可以看到，其Log输出仍然存在一定堆内存分配，建议研发团队在Release版本中将非关键性Log进行屏蔽。 二、内存模块 《小米超神》在内存上的表现如下图所示。总内存峰值达到297MB，Mono堆内存峰值为48.9MB。297MB的总内存分配相对来说略高，研发团队可尝试在低内存机器上对资源进行进一步控制，从而降低低内存机器上的内存占用。 1、Mono堆内存 从下图可知，该游戏的总体Mono堆内存控制得很好，在20000帧中，Mono的堆内存峰值为48.9MB，该值略高（UWA建议<40MB）。从图中看，是战斗最后上高地时突然出现了较高的堆内存分配，迫使Mono堆内存上涨了8MB（如下图红框所示），对此，研发团队可以根据具体位置查看其堆内存分配，即可定位其具体的堆内存分配根源。 但是，从走势上来看，其Used Mono堆内存占用在5V5战斗结束后，并未完全回落到场景之前（如蓝框所示），这一点需要引起研发团队注意，确认其是否为部分指定容器缓存所致，从而排查项目是否存在堆内存泄露的隐患。 2、资源内存 经过统计，该游戏运行时的纹理资源数量峰值为1003个，内存占用峰值54.8MB。研发团队将纹理内存占用控制得很低，目前仅高于30%的行业项目。经过统计，在内存占用峰值处，ETC1和ETC2格式纹理占有835个，RGBA32格式纹理共占有89个，RGB24格式纹理占有5个，其余为RGBA16格式纹理。 纹理资源在项目运行期间的总体使用情况： 对于纹理资源的优化，一般可分为以下几种： （1）使用更合适的纹理格式 从上图中可以看到，在整个游戏一场5V5战斗过程中，RGBA32格式纹理的使用数量较多，其使用总量已经超过了91%的的行业项目。对此，我们建议在视觉效果可以保证的情况下，尽可能使用ETC1格式纹理（Android平台）进行替换，不仅可以达到更小的内存占用，同时可以获得更快的加载效率。而对于无法进行硬件压缩的纹理，可以通过Dither方法尝试将其转换成RGBA16格式的纹理，具体做法可以参考Unity图片优化神器 - Dither算法进阶方案。 （2）使用更精准的纹理分辨率 一般来说，为了让模型看上去更加精美，除Mesh模型本身以外，其对应的纹理都会选用较高的纹理尺寸，从而让其看上去更加精致。但是，由于渲染物体在真正的游戏中相对于相机是有远近之分的，其显卡底层往往没有（或根本不需要）使用如此高的分辨率来进行渲染，从而就造成了大量的资源浪费，这在我们深度优化过的项目中比比皆是。因此，我们建议可以通过UWA线上测评报告中GPU性能的Mipmap功能页面来直接查看游戏运行时，其底层的纹理分辨率使用情况，如下图所示。 同时，在深度优化报告中，我们也会进行更大量的测试和几十亿像素累积分析，从而来精准指出到底哪些纹理资源的分辨率制作过高，可在不影响视觉效果的前提下，将其分辨率缩小4倍、16倍甚至更多。《小米超神》项目通过这种方式不断优化，其5V5场景的纹理内存已经从之前的78MB降到了现在的52MB。 以上是纹理资源的使用情况，其他资源的内存占用情况如下： 网格资源在项目运行期间的总体使用情况： Mesh资源的内存占用较高，高于60%的行业项目。对于Mesh资源内存的优化，主要有以下几种方法： （1）控制网格顶点属性的使用 详细检测网格模型中的Color数据和Tangent数据，当不需要时切记要将其进行去除，否则会在场景模型拼合时产生大量的内存浪费，具体详细说明可以参考《移动游戏加载性能和内存管理全解析》。 （2）控制网格顶点的数量 详细检测网格模型的顶点数(或面片数）使用是否过大。这是一个说起来容易但实施起来很难的问题，其难点在于如何定义一个Mesh网格的顶点数是否过大。在UWA测评报告中会有一个建议，即建议将Mesh网格顶点数控制在1500个以下。但实际上，这其实是一个“不科学”的规定，因为没有任何一个理论可以证明，其网格数量大于1500就是不合格，或则小于1500就一定合格。所以，我们这一年来花了大量的时间来寻求一种更为合理、科学的判断规则。我们认为判断一个网格模型使用是否合规并不应该是“静态”检测，而应该是一种“动态”检测，与上述纹理资源的检测一样，我们应该去看网格资源在底层渲染时到底占据了多少像素，从而以一种密度统计的方式来判断其网格使用量是否合理。因此，我们提出了一种网格模型测量标准，即“网格模型渲染密度”，其表示每单位数量（比如，1万）像素中，其网格模型的渲染顶点数量。 下图则为游戏运行过程中的网格模型渲染密度统计值。可以看出，虽然第一个模型“Mod_xyc_fz1001”的顶点数仅为1168，但其在游戏运行时平均每帧的渲染像素量仅为34.91个，也就是说平均每个像素要渲染33个网格顶点，这显然是一种浪费。因此，通过“渲染密度”这一检测方式，可以反映任何一个模型在游戏运行时的使用情况。在我们来看，这是一个比单纯设定1500更加合理的判断规则。 AnimationClip资源在项目运行期间的总体使用情况： AnimationClip的内存占用较高，高于76%的全类型游戏项目。对于一款MOBA项目来说，其内存占用较高是可以理解的，因为其战斗副本中拥有大量的动画模型，比如英雄、小兵、野怪、塔、基地等建筑等等。对此，仅能建议研发团队尝试从数量上进行进一步地缩减，以降低其内存的使用。同时，对于动画片段内存的一般优化还有“缩减精度”、“使用Humanoid类型”等方法，其具体优化方法可以参考《Unity中动画系统性能优化方案回顾》。 三、资源管理 该游戏在资源实例化/销毁、Active/Deactive等方面做的非常出色！在游戏运行的20000帧中，Instantiate和Destroy调用次数分别为1653次和4019次，而Active和Deactive调用次数则分别为116次和1447次。同时，对于Instantiate和Destroy操作来说，其主要调用均在进出战斗场景处，副本中虽有Instantiate调用，但无论是频率还是CPU耗时，均处于合理范围之内，如下图所示。 对于GameObject相关的资源管理，我们的建议如下： （1）对项目中存在频繁Instantiate/Destroy操作的GameObject一定要进行大力彻查，下图即为某一项目的Instantiate实例化详情，我们建议对于红框处高频率和耗时的操作重点排查，因为其无论是CPU还是堆内存都对项目性能造成非常大的杀伤力！ （2）频繁的Active/Deactive操作不仅会造成CPU的浪费，同时，它还很可能间接造成更大的CPU耗时，比如Animator.Initialize耗时。在此，我们不妨看下另一款游戏的Animator.Initialize调用情况，如下图所示，其调用的频率和耗时较高，这就是频繁的Active/Deactive操作所造成的结果。因此，对于GameObject不必要的Active和Deactive操作进行控制，是非常有必要的。更为详细的资源加载性能优化总结，可参见《Unity移动游戏加载性能和内存管理全解析》。 （3）不断检测、不断完善，优化是一个需要不断迭代、持之以恒的事情。下图则为《小米超神》经过几轮优化之后的资源管理变化情况。 以上则为《小米超神》游戏在CPU性能和内存管理方面的具体使用情况。优秀的CPU性能、非常少的堆内存分配以及引擎模块间的合理使用，足以看出该研发团队非常深厚的技术功底和对于引擎相当优秀的把控能力。 最后，非常感谢《小米超神》研发团队对 UWA 的认可和支持。感谢他们乐意将项目性能数据与大家一起分享，让更多的研发团队了解到一款性能优秀的MOBA手游在各个模块上应该做到怎样的程度。同时，也希望更多的开发团队可以与我们一起来分享他们的性能数据，让更多的游戏开发者受益！ 关于UWA 由侑虎科技开发的游戏/VR应用性能优化平台，目前提供 1）性能测评与优化 2）资源检测与分析 3）UWA GOT 三大工具，帮助开发者在短时间内大幅度提升性能表现；同时其搭建的知识分享的博客（blog.uwa4d.com）和答疑解惑的互动平台（answer.uwa4d.com）使广大开发者收益，UWA以实力和态度诠释对性能优化的定义：问题的答案永远“在现场”，解决你的性能问题，才叫“优化”。
现实中，在地面上的人影往往因为被投射的物体是粗糙不光滑的，所以影子的轮廓也是有些模模糊糊，没那么棱角分明。在最新的游戏项目中，美术提出我们应该也做一个更柔和、更真实的实时阴影（本文中提到的阴影都是投射在其他物体上的影子，区分于自身的阴影）。 对于这个需求，并没有自造车轮，而是找了一个很好的轮子让它转了起来，我们可以先看一下目前我们项目中影子的效果： PK沙滩1中主角与小怪带着柔和的实时影子 其实Unity本身自带了Soft Shadow的选项，但是有些缺点（下文会具体比较说明）。 在我们的工程里，选用的是NyanHoon Games的「Dynamic Shadow Projector」 官网：http://nyahoon.com/products/dynamic-shadow-projector，在Asset Store就有，免费下载。 这里将这个插件的软阴影与Unity自带的软阴影做一些比较。本篇文章所有测试的条件如下：手机为OPPO A37m（CPU：1.5Hz，内存：2GB，GPU：Mali-T860），目前是一款中低档的手机；场景中放置共13个人物模型；使用白色Directional Light；如无特殊说明，截图和数据皆来自手机。 一、Unity自带Soft Shadow的情况 参数： 参考我们现在的项目，Directional Light，选择Soft Shadow，Quality Settings中的Shadow设置为High Resolution， 70 ～20， Two Cascades。 有一个选项，Shadow Projection，它对于影子的质量影响很大（官方说明：平行光投射阴影有2种方式：Close Fit渲染较高分辨率的阴影，但是如果相机移动时，有时阴影会轻微摆动。Stable Fit渲染的阴影分辨率较低，不过相机移动时不会发生摆动。） 真机情况： 左侧为Unity自带Stable Fit真机表现，右侧为Close Fit真机表现 最开始我尝试的是Stable Fit选项，出来的效果不忍直视（左图）。换成Close Fit后，锯齿问题相当明显的被改善了，但这样造成的问题是性能开销上大幅度的上升。仅从SnapGragon的CPU利用率来看，从比较稳定的40%，增长到了60%左右，而且十分不稳定，有时甚至会跳到70%。 Stable Fit的SnapGragon截图 Close Fit的SnapGragon截图 二、使用Dynamic Shadow Projector 且不开启任何Blur或重采样选项的情况 左侧为插件512分辨率，右侧为1024分辨率 第二组以及下面的第三组测试，都是同时处理区域范围内所有的人物（13个模型），将其渲染到同一张Texture上进行处理。本组实验使用了插件，但是并没有开启附加功能，例如Blur或Mipmap。 上图左侧是分辨率512，右侧是1024，我们目前的项目里用的就是1024的分辨率。可以看到锯齿情况有所改善，但如图所见，依旧有着明显的锯齿，因此个人认为单纯提高分辨率意义不大。不过性能上，真机的CPU利用率，512的为44%左右，1024为53%左右，增长都不多。下图是1024的SnapDragon截图。 插件1024分辨率的SnapGragon截图 三、Dynamic Shadow Projector开Blur的情况 第一张手机截图是512分辨率开Blur，第二张为1024的Blur效果。1024的情况下，影子会多很多细节，但是若追求的是比较模糊的软边影子。其实512的就足够好了。对比第一组的Unity自带软阴影可以感觉到，Unity的Soft Shadow真的是一点都不Soft。 再比较一下性能。可以看到512的时候开了Blur，CPU占用率也是44%左右没什么太多。但是1024的时候CPU性能一下子升到了70%，不过跟Unity的SoftShadow的Close Fit形态比，也就多了10%。 分别为插件512分辨率开Blur，和1024分辨率开Blur的真机效果 插件512分辨率开Blur的SnapGragon截图 插件1024分辨率开Blur的SnapGragon截图 这个插件的Blur选项主要是多做了一步Graphics.Blit。针对这个函数，在Profiler上查看了一下手机GPU的情况。可以注意到从10%占用率，4ms左右增长到了24%占用率，13ms左右。 上下两张分别为插件在512分辨率和1024分辨率开Blur时，Blit函数的真机GPU使用情况 这里附上一下改变了光照颜色后的效果： 左右图分别为Unity自带软阴影与插件512分辨率开Blur时，在黄色Directional Light下的效果。可以感觉到，右侧插件带着Blur的效果，软边将光照的颜色很好的融合在了一起，非常的自然，而Unity的自带阴影可以说完全没有融合环境光。 小结 横向对比以上测试结果，在同为较低损耗的分辨率下，插件+Blur的效果很理想地达到了美术期望的软边阴影效果；高分辨率情况下，Unity自带阴影的锯齿很小，但几乎感受不到边缘的“软”，而插件+Blur，有软边有细节，当然性能略耗。 PS. 针对有性能损耗的blit函数，也可以尝试改写Blur的方式来提高性能。 这是侑虎科技第325原创文章，感谢作者Luisa供稿。欢迎转发分享，未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。（QQ群：793972859） 作者知乎：https://zhuanlan.zhihu.com/taiyouxi，同时，作者也是U Sparkle活动参与者哦，UWA欢迎更多开发朋友加入 U Sparkle开发者计划，这个舞台有你更精彩！
本期话题：打开界面GC过高、动态字体的性能耗时、AssetBundle卸载方法对比、把字体文件裁剪之后对内存和效率的影响是什么、如何优化背包问题... 今天是节后首个工作日，小编又安利了5个营养丰富的技术答疑，让这股知识的清流来缓解下工作上的鸭梨吧！建议阅读时间10分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 资源管理 Q1：我们知道，卸载AssetBundle有两种方式，Unload(true)和Unload(false)，一开始我用的是Unload(false)，好处有以下几点： 1）开销比Unload(true)小，不太影响体验； 2）对于场景自己的AssetBundle，通常文件本身比较大，可以加载完地图之后直接调用Unload(false)； 3）不会销毁正在使用的资源； 4）可以一边加载某些AssetBundle一边销毁另一些AssetBundle，并行处理。 但是实际上用下来，发现会产生资源泄漏问题。虽然代码已经很仔细的检查过了，但还是难免会发生有C#代码引用到某些资源，从而造成AssetBundle释放之后，这些资源释放不掉(UnloadUnusedAssets没用，除非UnloadUnusedAssetsIgnoreManagedReferences) 这个时候我想到了Unload(true)，虽然确实可以解决资源泄漏的问题，但产生的问题正好和上面相反： 1）开销大； 2）场景不能加载完之后直接卸载，一边加载一边卸载可能会有崩溃； 3）比较暴力，可能会出现删除正常资源的风险。 请教下大家是如何考虑这个问题的呢？ 正如题主所说，两种方法都有各自的优缺点，但就从目前的统计来说，使用Unload(false)的项目占据绝大多数。 就UWA而言，我们比较推荐Unload(false)这种卸载方式，因为Unload(true)过于粗暴，可能会增大删除正常资源的风险。 对于Unload(false)会带来资源泄露的问题，需要研发团队进行更为谨慎的控制。但这种泄露是有方法避免的，题主可以定期定时（如每周）通过UWA GOT或线上性能检测来对项目版本进行定制测试，通过场景之间或不同帧之间的资源增量信息来规避资源泄露问题，这种问题越早发现，越容易解决。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59cca2a4430dd9a1336b8b7c UI 制作 Q2：我们项目中在做UI的时候，需要对选择出来的图片路径加个判断，只有某个路径下的图片才可以选上。通过[CustomEditor(typeof(UnityEngine.UI.Image))]无效。不知道还有没其他的接口可以修改图片的Inspector？ 建议题主试试扩展下 Image 组件，比如创建一个 XImage 组件来继承 Image，然后通过 [CustomEditor(typeof(XImage))] 来修改 XImage 的 Inspector。 该问题来自UWA 社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59d9ca49268e715701c74f37 动画 Q3：一个Scroll Rect内有Grid，而Grid下有多个子对象，每个子对象状态使用Animator控制。这个控制在资源工程本地处理无问题，但是在打包加载后出现了刷新问题。具体情况如下：Animator对象在加载并切换状态后，引起了不间断的Layoutrebuild操作，从而引起UI较大的卡顿。这一操作在Disable了对象的Animator脚本后就停止，再开启就继续出现。不知是否有什么解决方案呢？ 动作播放停止后，相当于是持续地赋值同一个值，而Recttransform的Scale只要被赋值就会被认为是Dirty的，从而就Rebuild了。所以这种情况只能禁用Animator了。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59cc726a430dd9a1336b8b7a 字体 Q4：我在Unity文档里看到，如果要渲染的字不在字体数据里，Unity最终会去访问当前平台的系统文字。我想问下，把字体文件裁剪之后对内存和效率的影响是什么？ 内存： 这时候Unity是会加载系统文字，还是系统文字本身就在系统内存里了呢？这部分系统文字的内存是怎么算的？还是说无法避免呢？ 效率： 这边时间消耗是怎么样的？该如何查看？如果在FontNames里写上很多字体，耗时会增加很多吗？ 参考的文档：https://docs.unity3d.com/Manual/class-Font.html 我们做了一个简单的例子，在工程里放一个英文字体，且勾选了 Include font data，在 UILabel 中使用。第一种情况是只输入英文，第二种情况是再输入两个中文。连 Profiler 之后的数据分别是下面两张图： image1.png、image2.png，可见 Unity 部分的内存确实是增加了的。但在 Detailed 模式下，两种情况的内存是完全一样的。 说明 Detailed 模式下 Unity 没有统计 Fallback 中系统字体大小，而 Simple 下的 Unity 部分则是统计到了的。所以只能建议题主自行测试一下，通过对比 Simple 模式下的 Unity 部分，来估计下在使用生僻字后，由于系统文字的加载而增加的内存量。 image1.png image2.png 从实验得到的数据来看，只能说在某些情况下可能会增加耗时，比如某一时间点上要创建一大堆生僻字，每个都需要从 fallback 的字体里逐个查找。但这个耗时很难量化，只能建议关注下 Profiler 的 CPU 面板里 Font.CacheFontForText 一项的开销（举个例子，在 UIPanel 重建时 UIPanel.LateUpdate 里会有出现这一项）。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59cf8777c3135d867732308a 性能 Q5：背包一次性加载元素20-25个, GC瞬间达到3MB，电脑瞬间帧数是15帧，请问各位是如何优化背包问题的? 首先，从Profiler截图中可以看出，目前的效率是统计是出自于Editor中，而非真机上；其次，CPU耗时较高主要是因为以下几处： （1） BuildPipelineIntefaces.InitializeBuildCallbacks 该项为Unity 5.6以后的新增项， 其在Unity 5.6和2017版本中，均有较高的开销，有网友已经报过Bug，Unity论坛中相关回答说该问题在2017.1f2中被修复，题主可自行核查一下。 （2）各种Awake开销 上图中其他蓝框中可以看出，其他较高的CPU耗时和堆内存分配其实是各脚本的Awake代码造成的，而这些脚本是题主团队缩写的自身代码，绝大部分开销并不出自于Unity引擎API。因此，需要题主对自身代码进行进一步检测，查看其CPU耗时和堆内存分配是否合理。 最后，建议题主在真机上进行测试，因为Editor运行时，在不能完全掌握Profiler中各选项的真正含义时，Profiler往往会起到“误导”作用，耗掉大量的研发时间。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59daf3e0b7f9f3186a45e467 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站（answer.uwa4d.com）上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（仅限技术交流）
本期聚集话题：LightingDataAsset Delete后Lightmap展开问题、Gamma和Linear颜色空间问题、AlphaTest和Alpha Blend的性能差异... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 制作 Q1：我这边做了个测试，把场景中的物件进行StaticBatch，用Lightmap烘焙，并且在烘焙完记录每个物件Renderer的lightmapindex and offset，然后在运行中，我删除了生成的LightingData.Asset，自己设置了Lightmapsetting，并且恢复了每个物体Renderer的Lightmapindex and offset, 结果我发现烘焙出来的场景Lightmap还是不对的。我怀疑是不是LightingData.Asset 还记录了别的东西，想问问看UWA有没有什么经验呢？ 我在answer.uwa4d.com上打包一个测试用例，打开Scene/LightMapTest.unity 这个场景即可。 这个问题还是出在Static Batching上。经过测试我们发现如果去掉场景中物件的“Static Batching”标记，换成手动Batching，即采用StaticBatchingUtility.Combine的方式结果就正确了。 同时，我们发现使用LightingData.Asset时，开启Static Batching与不开启都正确，因此我们认为LightingData.Asset可能记录了与CombinedMesh有关的数据，导致如果仅仅使用gameobject的LightMap参数无法正确读取CombinedMesh的LightMap UV。另外一种可能是Unity的一个Bug。 最后，我们建议采用上述手动Batching的方式，即可解决此问题。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c0d16c5cd7219d3bbfb3b3 制作 Q2：我们场景中有两种Unlit物体，一种是在脚本中通过Mesh顶点色（Mesh.colors）赋颜色值，一种是用Shader属性传递颜色值，在Gamma颜色空间时两种物体的渲染颜色是一致的： 但是切换到Linear空间发现不一样了，如下图，左边是顶点色，右边是Shader属性颜色： 顶点颜色和属性都没改过，只是切换了颜色空间，请问是什么情况？ 我能想到的有两种可能性： 1）顶点色的颜色值在Shader中没有被正确处理； 2）右边使用贴图的导入设置中sRGB的选项有错误。 看上去左边的在线性空间下变亮了，而右侧的方块颜色在两种Space下差别不大，因此推测第一种的可能性比较大，顶点色在很多情况下并不被当作颜色处理，而作为值来存储，所以有可能这里处理有问题。至于为什么变亮了，感觉是值经过了伽马校正变大了。 Unity有接口在两种颜色空间下转换，建议题主可以查一下，在Shader中修改代码来排查下是哪里的问题。 该问题来自UWA 社区，感谢贾伟昊提供了回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c387de79a00b1e16da7414 UI 制作 Q3：当使用Linear设置时，UI上图片透明度等也跟着变化，出来的效果与美术人员的需求不一样。请问有什么办法可以让UI不使用Linear或者让UI可以在Linear影响下也正常呢？ 推荐题主可以看下这个帖子 https://forum.unity.com/threads/bug-with-bypass-srgb-sampling.282469 “When switching to linear mode it (greatly) changes how blending works, this is because when sampling only the rgb channels are linearised as it is assumed the alpha is a linear scale representation already.” 简单说，这是正常现象，里面有三种解决方法： 1）改资源的 alpha 通道： Reauthor the content for linear blending (this is supported in photoshop). 2）用 Shader 提前处理下颜色空间的转换： Add a workaround in the shader if in linear space to ‘pretend’ the alpha from the source texture is in the correct format. 3）用屏幕后处理来绕过 UI 的 linear 处理。 可以直接搜 topsekret 的回答。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c1e5c66c8b329c76a5f66e 制作 Q4：我们项目在实现显示部分模型像素的时候用了Builtin的Cutout Shader，还有一种方式是用Blend，也就是把Alpha设成0。我想请教下这两种方式有什么区别？性能上哪个好？在什么情况下使用比较高效？ 答案一：功能上，Alpha Test无法实现半透的效果，只能让物体的某些部分按照Alpha的值“透”或者“不透”，Alpha Blend可以做到半透，但是在多个Alpha Blend的物体重叠的情况下，由于不写Z会导致先后顺序可能存在问题。 由于Alpha Test的实现是基于discard的方式，即在PS里发现Alpha的阈值不符合要求，就将该像素丢弃掉不进行渲染。这种方式会导致使用了类似early-z技术的GPU优化失效，导致性能下降。 另外，知乎上有讨论——“对于PowerVR系列而言会影响HSR（隐藏面消除），打断ISP处理覆盖同一像素的几何体（更具体一点，ISP要得到PS执行后的结果才能正确进行HSR，在这一过程中，所有覆盖了带有discard操作像素的几何体全部都要等待）”。 参考：https://www.zhihu.com/question/27875435 所以整体来说，在移动设备上，Blend具有更高的性能，但是有些效果未必能够达到，结果可能不是美术设计想要的效果，特效中用得较多。 题主也可以参考乐乐的这篇：http://blog.csdn.net/candycat1992/article/details/41599167 感谢贾伟昊提供了以上回答 答案二：不考虑硬件去讨论这个问题有点形而上学，另外，实际使用中还要考虑Overdraw的影响，而不是单纯的一层像素，再有就是，网上很多资料其实已经落后了。所以在知乎上搜这个问题，会有大牛告诉你Blend更快，但是会马上有人把测试截图贴出来说看我们的实测数据“test明显更快”。 建议题主分别用Mali，PowerVR，Adreno的移动设备来测一下就知道差异了。 另外，PowerVR的HSR，楼主可以试试看用PowerVR Tool，看看Blend和Test，是不是像传说的那样，都不能开启HSR，可能会有意向不到的结果。目前我们测试最后的结论是，尽量还是用test。 感谢 kylda提供了以上回答 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c09367a3d42c411c37a0cd/ 制作 Q5：我们有一个需求，是在不同的动画播放的时候切换不同的NormalMap，但是动画的“Add Property”没有NormalMap等变量，请问有什么好的办法可以解决吗？ 可以自己写一个脚本，挂载需要切换NormalMap的节点上面，public NormalMap等变量，然后在脚本里面写段代码，当发现NormalMap修改了，就去改模型的NormalMap。而动画是可以修改这个脚本变量了。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59bf72d0ca564ff3748d4f27 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站（answer.uwa4d.com）上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（仅限技术交流）