1)Unity性能优化剖析思路
2)资源打包关系依赖树
3)SpriteAtlas 中Include in Build的作用
4)应用Streaming Mipmap后纹理内存没有降落的疑难
5)URP Renderer Feature实现二次元描边,Cutout的解决问题
UWA每周推送的知识型栏目《厚积薄发 | 技术分享》曾经随同大家走过了330个工作周。精选了2022年上半年的精彩问答分享给大家,期待UWA问答持续有您的陪伴。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
Unity
Q:Unity有多少优化点?比方合批:动态合批、SRP合批、GPU实例化、UGUI Reruild、光照烘焙、反射探针、光照探针、Shader.Parse、Shader.CreateGPUProgram、场景加载优化和GC优化,还有哪些优化点?
A1:大方向上能够从CPU、内存、GPU这三个方向切入。
细分一下能够从CPU、内存、渲染、资源优化、耗电优化、网络优化、卡顿优化、优化工具的抉择把握这几个点动手。
一、CPU优化
- 缓存计算结果
- 预处理
- 限帧法
- 主次法
- 多线程
- 引擎模块(动画、物理、粒子、导航)
- 逻辑优化
二、内存优化
- 缓存法
- 内存池
- 资源管理器
- 管制GC
- 逻辑优化
- Shader变体数量优化
三、渲染优化
- SetPassCall渲染状态切换频次管制
- DrawCall数量管制
- 带宽负载
- 显存占用
- GPU计算量
四、卡顿优化
- 降帧法
- 摊帧法
- 限度数量法
- 逻辑优化
- IO优化
- 应用进度条
五、资源优化
- 纹理优化
- UI优化
- 字体优化
- 模型优化
- 场景优化
- 粒子优化
- 材质优化
- 指定规范美术标准
- Shader变体数量优化
六、耗电优化
下面说到的优化点,或多或少都会影响到手机的耗电,也是优化耗电的措施,除此之外还有:
- 动静调整限帧
- 动静调整画质
七、网络优化
- 缩小无用字段
- 升高字段精度
- 防止反复发送
- 网络异步化
- 压缩有效字节
- 压缩协定包
以上说的这些要点,大部分摘抄演绎自《移动游戏性能优化通用技法》。强烈建议多花些工夫认真浏览一下这篇文章,而后以这篇文章作为指南,再去认真钻研外面提到的优化细节该如何开展。
感激马三小伙儿@UWA问答社区提供了答复
A2:优化点必定是无穷无尽的,这里搬运UWA的客户端性能优化思路,针对常见的引擎模块的相干问题都做了剖析,讲的是比拟全比拟透的,常见的优化难题都列举了。
《Unity性能优化 — 物理模块》
《Unity性能优化 — 动画模块》
《Unity性能优化系列 — 资源内存透露》
《Unity性能优化系列—Lua代码优化》
《粒子系统优化——如何优化你的技能特效》
《Unity性能优化系列—加载与资源管理》
《Unity性能优化系列—渲染模块》
《Unity性能优化 — UI模块》
《反对资源加载剖析、场景宰割》
《UWA报告应用小技巧,你get了吗?》
《UWA本地资源检测更新,助你严守我的项目性能的每个角落!》
感激芭妮妮@UWA问答社区提供了答复
AssetBundle
Q:想做包体资源剖析,大家有什么好的树显示工具或者思路举荐吗?有比拟好的开源计划也能够。最简略就像N叉树一样,比方root一个文件名,而后开展整个树结构。
A1:我本人做了一个,供参考。都是用Unity本人的IMGUI最根本的接口去实现。
EditorWindows
GUI.Box
GUI.BeginGroup
GUI.Label
Handles.DrawBezier
Handles.DrawWireDisc
TreeView
基本上,组织好各个AssetBundle的依赖关系其实是很好出现的。
感激黄程@UWA问答社区提供了答复
A2:举荐一款比拟好用的插件,不止有依赖树,还有其余打包的资源数据可供剖析:
https://assetstore.unity.com/…
感激郑骁@UWA问答社区提供了答复
AssetBundle
Q:SpriteAtlas中Include in Build的作用是什么?
A:专门做了一些测试,具体如下:
以下表白中Sprite对应的是Sprite类型的对象,Texture2D对应的是Texture2D的对象,这和Sprite对象是齐全不同的货色,sactx示意生成的图集纹理。
测试状况包含2个变量:
- SpriteAtlas对象是否被动打包AssetBundle
- SpriteAtlas对象上是否勾选Include in Build
第一种状况,SpriteAtlas打包AssetBundle:
那这里要思考的是SpriteAtlas援用的Sprite是否会独自打包,如果这些小Sprite不被动打包,是会被动进这个SpriteAtlas的AssetBundle外面的,如果其余的UI Prefab中,比方有个Image应用了一个小Sprite,那么这个小Sprite就冗余了。
这里勾不勾选Include in Build的区别在于:加载Image的时候,这个Image会不会主动显示,勾选了Include in Build,会主动显示图片,不勾选,则须要脚本增加回调来被动加载SpriteAtlas,并callback(spriteatlas)。
第二种状况,SpriteAtlas不退出AssetBundle打包:
- 不勾选Include in Build
假如小的Sprite打包AssetBundle,在这个AssetBundle外面不会有sactx,这个sactx的Texture2D的纹理变成“隐没”的状态,没有任何货色能够援用到这个sactx纹理,而且因为在工程外面有SpriteAtlas的存在,所以在小的Sprite的AssetBundle外面也不能让其自身对应的小的Texture2D纹理进AssetBundle包,所以图像就永远显示不进去了。- 勾选Include in Build
所有的小的Sprite所在的AssetBundle外面都会被动蕴含sactx的图,且会蕴含所有没有被动打包的小的Sprite。如Sprite1和Sprite2是SpriteAtlas外面的两个小的Sprite。Sprite1被动打包,Sprite2不被动打包,那么Sprite1的AssetBundle外面是会有Sprite1和Sprite2以及sactx纹理。
总结:
- 如果有Sprite退出了某个SpriteAtlas,那么任何真正应用到这个Sprite的资源都不会有对Sprite对应的小的Texture2D纹理的援用,而是对sactx图集纹理的援用。
- 如果SpriteAtlas不打包,必须勾选Include in Build,否则sactx纹理就“隐没”了,在勾选Include in Build的前提下,而且SpriteAtlas中的所有小的sprite必须打包到同一个AssetBundle外面,否则sactx会冗余。
- 如果SpriteAtlas打包了AssetBundle,sactx永远不会冗余了(这里的冗余是指打包AssetBundle造成的冗余)。SpriteAtlas外面的小的Sprite也最好打包AssetBundle,不然这些小的Sprite就会冗余。勾选或者不勾选Include in Build都不影响各种依赖关系,惟一的区别是是否会被动显示图片,勾选了就会被动显示图片,不勾选就须要脚本管制来显示图片。
感激Xuan@UWA问答社区提供了答复
Texture
Q:为什么我在我的项目中应用了Streaming Mipmap然而在GOT报告中看纹理内存没有降落?是没有正确失效还是统计有问题?
A:之前做过相干测试,发现GOT Online是能够统计到被Streaming Mipmap影响的纹理的正确内存的,所以我揣测你遇到的状况大概率还是没有正确失效导致的。以下是对如何让一张纹理利用Streaming Mipmap的简略流程总结,其中会注明须要特地留神的一些条件(有些被官网文档收录,有些则文档中没有,但试验证实为必要):
- 在Project Settings-Quality中开启Texture Streaming选项。然而试验发现Editor中开启该选项而真机上却会生效的景象,导致所有纹理的Streaming Mipmap设置全副生效。所以为了确保失效,首先应该在代码中调用QualitySettings.streamingMipmapsActive API全局地开启这个选项,能力确保Streaming Mipmap可用。
- 调整1中设置的参数。比拟重要的参数是Memory Budget参数和Max Level Reduction参数。Memory Budget示意纹理资源的估算,默认值是512MB,但依据UWA的大量我的项目数据来看,中低端机上个别为200MB左右。它的数值代表的是所有纹理资源的估算——即,它既包含了非流式的纹理、又包含了咱们想要采纳流式的纹理——但这个“估算”并不代表纹理资源可占用的下限,只是Unity判断对于一个开启Streaming Mipmap的纹理到底采纳它的哪些Mipmap通道的参考值,非流式纹理可能轻易冲破这个估算。
Max Level Reduction则是代表着Unity通过流式存储最高能取到哪一级的Mipmap通道,这个参数的优先级比Memory Budget要高,也就会造成理论内存超过预算的状况。(比方该参数为2时,则最多剔除Mipmap0和1通道,即使抛弃当前还远超出预算值也不会进一步剔除。)
也就是说,如果Memory Budget值设置的远高于我的项目中纹理理论占用的内存,则Texture Streaming可能齐全不起效,所有开启Streaming Mipmap的纹理仍将保留它们的全副Mipmap通道。
- 设置开启Streaming Mipmap的纹理。1、2中提到的设置只对开启了Streaming Mipmap的纹理起效,而这只是官网文档的说法,从实际操作来看,Texture Streaming只对同时满足以下三个条件的纹理失效:
1)开启了Streaming Mipmap且开启了Generate Mipmap的纹理(这一点官网文档中没有提及,事实上开启Generate Mipmap才会生成Mipmap通道供Streaming Mipmap剔除);
2)被即时加载的纹理(如一开始就曾经在场景中被依赖的纹理,即使开启了Streaming Mipmap其内存也不会发生变化,通过AssetBundle加载和Res.Load()加载的纹理则能够),也即官网文档中这句话的理论含意:
如果是进行Android开发,还须要关上Build Setting,并将Compression Method设置为LZ4或LZ4HC。Unity须要应用其中一种压缩办法进行异步纹理加载,这是纹理串流零碎所必须的操作。
3)Gfx局部内存(这里指的是纹理资源开启Read/Write选项时,复制到CPU端的那一部分内存是不受Streaming Mipmap影响的);
- Streaming Mipmap剔除Mipmap通道的法则。它的机制其实和Texture Quality是相似的。咱们晓得,开启Mipmap的纹理之所以会变成原来的4/3倍,实际上是它各个通道所占用的内存之和。举例而言,一个具备11个Mipmap通道的原大小为1MB的纹理(10241024分辨率、ASTC44格局),其内存占用为1+1/4+1/16+…的11项等比数列之和,即约4/3。等比数列的各项就对应了Mipmap0、Mipmap1、Mipmap2…等各个Mipmap通道。那么,当Max Level Reduction参数设置为2时,其实际意义就是保留Mipmap2和后续所有更小的通道,而剔除Mipmap0和Mipmap1通道,此时的内存大小为4/3MB-1MB-1/4MB=85.33KB。这和我在Profiler或GOT Online中看到的数据基本一致。
- 对于采纳Streaming Mipmap计划的倡议。根据上述试验和剖析不难看出,Streaming Mipmap是的确具备一些长处的,对于对内存比拟敏感,尤其是纹理内存占用很大的我的项目,采纳Streaming Mipmap计划是十分正当和举荐的选项。与此同时,它的理论应用要求对我的项目中纹理资源的内存占用有相当的理解和布局——相干设置在Quality中,天经地义地应该思考到不同设施Lod分级时不同的设置。在中低端机中,设置尽量低的Memory Budget和尽量高的Max Level Reduction;在高端机上则恰恰相反,在内存可承受范畴内尽量开启最好的画面体现。除此之外,对于哪些纹理要开启Streaming Mipmap,个别是场景中3D物体的纹理,而UI模块采纳的纹理则尽量敞开。因为Mipmap的意义次要在于适应纹理在间隔镜头远近时的体现须要、防止失真等,而UI齐全不须要这些,开启只会白白浪费内存和计算工夫。
感激Faust@UWA问答社区提供了答复
Rendering
Q:之前咱们的卡通渲染是在Shader里写多个Pass来绘制的描边,最近尝试用SRP Batcher优化时发现,SRP Batcher不反对多个Pass的Shader。于是我尝试用URP Renderer Feature来渲染所有角色的描边。
实现起来很简略,但有一个问题解决不了,就是Cutout的问题。
裙子的下边缘是用贴图的Alpha管制的,并不是真正的顶点。以前的Pass写在角色渲染的Shader里,能够用贴图来管制,但用Renderer Feature来解决后,所有角色模型的描边是用的同一个材质,不能再用模型各自的贴图的通道来解决了。显示成果就是Cutout的描边局部无奈解决:
边缘比较复杂,然而管制的顶点就只有几个,感觉不太好实现。
当初模型顶点的色彩信息我曾经用过了,RGB是描边色彩,A是描边粗细。我能想到的方法是用A的一些非凡值来非凡解决一下某些顶点(相当于Clip掉一些顶点,但必定没有相干API),但又感觉仿佛不太可行。不晓得大家有没有遇到过,或者有没有什么好方法呢?
本人尝试了用顶点信息标记点,但有瑕疵,点关联的边会受影响,描边没了:
让美术加了一些点,根本也能解决(其实外边缘还是不会显示全,但曾经看不太进去了):
但这办法还是不好。最好在Renderer Feature里能够获取到正在渲染的模型的材质信息。
是否能够把一个多Pass的Shader里的某个Pass弄到独自的Renderer Feature里画,而不是从新画一遍?比方画第一遍的时候禁用这个Pass,Renderer Feature画的时候再启用它?
A1:自定义一个LightMode,Render Feature里设置这个LightMode,这样材质球上的贴图数据什么就能有。
补充个截图大略是这样的:
对于自定义的LightMode,Unity默认疏忽,只有Render Feature里手动指定了要画这个LightMode,Unity才会去绘制。
感激jim@UWA问答社区提供了答复
A2:如下,这样SRP Batcher终于能够合批多Pass的Shader了:
不必禁用失常的渲染。
两个Pass,一个失常的Pass,一个自定义LightMode的Pass,lightMode的Pass渲染描边用ScriptableRendererFeature手动指定渲染自定义的LightMode。Unity不会去渲染你自定义的LightMode。
感激题主仇磊@UWA问答社区提供了答复
封面图来源于网络
明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官网技术博客:blog.uwa4d.com
官网问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官网技术QQ群:793972859(原群已满员)
发表回复