一.项目概览
1.检查资源的环境情况:在Project中通过Search By Type查看资源分布情况
2.关注场景中的摄像机数量(影响渲染流程的复杂度)与灯光数量(影响光照与阴影复杂度)
3.运行游戏后,点击Stats观察渲染信息,如图下所示:
注: Tris为三角面数,Verts为顶点数
二.静态资源的优化
1.Unity Assets 工作流程图
导入 > 创建 > 构建 > 分发 > 加载
2.资源类型
1.外部导入资源:模型网格,纹理,音乐音效,动画等
2.内部创建资源:预制体,Timeline,VFX等
注:导入设置与资源规格影响性能
3.静态优化分析工具
1.进入Unity UPR网页
2.创建新的项目(项目包名在Project Settings > Player > Package Name)
3.通过解压AssetChecker并且通过Win+R(输入命令:cd /d AssetChecker所在路径)
4.输入命令:assetcheck.exe --project="project_path" --projectId="project_id"
4.音频优化
1.Force To Mono:如果左右声道相同可以开启此选项,使得双声道变为单声道。
2.Compression Format:长时间音频使用Vorbis(压缩但保真),短时间音频使用 ADPCM(压缩但不保真)。
3.Sample Rate Setting(Override Sample Rate):修改默认音频采样率,一般移动平台为22050Hz。
4.Load Type:
1)Decompress On Load:音频资源小于200KB。
2)Compressed In Memory:较大的复杂音频。
3)Streaming:长度较长的音效或者背景音乐,但会增加CPU开销。
5.注意:实现静音功能时,应该直接销毁AudioSource组件,将音频从内存中卸载。
5.模型优化
1.DCC工具模型导出概要
1)统一数据
2)导出网格必须是多边形拓扑
3)导出前确保所有Deformers全部烘培到网格模型上
4)原始模型尽量少的材质,网格,骨骼数,并且导出时FK与IK节点分离
(Unity不支持导入IK骨骼节点,所以导出前需要删除)
注意:不建议模型使用的纹理随着模型一并导出;不建议导出携带场景信息。
2.Unity模型设置概要
1)Scene >Import XXX可以选择不开启
2)Meshes >Read/Write 一般不开启(除非运行时动态修改网格或蒙皮网格动画)
注:开启此选项会在内存中额外复制一份,分别保存在内存与显存中。
3)Geometry >Index Format(16bit):模型顶点少于65535个可开启,否则 Auto。
4)如果模型无动画可以设置Animation >Import Animation关闭。
6.纹理优化
1.纹理概要
1.常用纹理类型:
1)Default:默认纹理
2)Normal map:法线贴图
3)Sprite(2D and UI):使用2D Sprite或者UGUI
4)Lightmap:光照贴图
5)Single Channel:如果原始图片只有一个通道,则选此类型(节省内存)
2.纹理大小
Mipmap(分级细化纹理):类似于图片LOD,但不需要额外生成对象
注:纹理小欠采样模糊,纹理大过采样噪点。
3.纹理色彩空间
金属贴图,粗糙度贴图,法线贴图等(不用做颜色信息)不适用sRGB色彩空间。
4.纹理压缩
一般使用硬件(GPU)支持的纹理压缩格式(ASTC,ETC2等)。
5.纹理图集(一系列小纹理图像的集合)
6.纹理过滤
1)Point(No Filter):计算量最少但近距离纹理呈现块状。
2)Bilinear(双线性):像素平滑渐变但近距离纹理模糊。
3)Trilinear(三线性):平滑过渡Mipmap明显变化。
4)Anisotropic Filtering(各向异性过滤):适用于地表纹理。
2.纹理设置与优化
1.设置
1)Alpha Is Transparency:如果非半透明,关闭此选项。
2)Generate Mip Maps:除2D与固定视角游戏外,都建议开启。
3)Filter Mode:选择双线性和2x各向异性过滤,有选择地使用三线性。
4)Fromat:无
2.优化思路
1)将类似生命周期的小纹理放在同一纹理图集中
2)设计时应该避免大面积的半透明纹理
3)将序列帧动画放入纹理图集
3)颜色渐变(黑白)贴图采用单通道压缩
注:判断纹理是否为单通道与查看Mip Map各级别情况
贴图上方点按R,G,B如果只有一个有画面则可以设置单通道,上方右侧即为Mip Map级别显示图样查看。
7.动画优化
1)有动画文件的模型导入:需要开启模型Rig中Animation Type选择Generic(通用骨 骼)或Humanoid(人形骨骼),若需要重定向或者IK使用人形骨骼,否则使用通用骨骼(减少CPU运算)。
2)Rig >Optimize Bones:建议开启,剔除没蒙皮顶点的骨骼。
3)Rig >Skin Weight:对于不重要的动画对象,可以减少为1根。
4)Animation >Anim.Compression:一般选择Keyframe Reduction
注:开启压缩,会有XXX Error选项,减少Error可以提升动画精度(细节),幅度与体积越大,误差会被放大。
总结:优化应注意效果差异,动画曲线数量(数量越少并以常量曲线为主越好)与动画文件大小(一般不超过1M)。
三.工作流优化
1.Unity工程目录结构
1)Asset文件夹:项目资产
2)Library文件夹:项目内部资源数据信息
注:如果编辑器使用出现问题,可以删除重新生成。
3)Packages文件夹:项目包文件信息
4)Project Settings文件夹:项目设置信息
5)UserSettings文件夹:用户设置信息
6)Temp(临时数据)与Logs(日志信息)文件夹
2.Assets目录中Resources文件通常是Unity项目性能问题的主要来源,尽量使用Assets Bundle方式进行构建和加载资源。
3.Assets目录结构设计
1)一级目录:区分编辑器与运行模式,区分工程大版本,例如:场景,设置,游 戏运行,编辑器,脚本等。
2)二级目录:区分资源类型(预制体,特效,动画,贴图等)。
3)三级目录:资源子类型下的区别。
4)四级目录:只有Audio/Texture/Models做四级划分,按模块或者生命周期划分。
四.编辑器优化
1.场景资源优化
1)避免场景节点深度太深。
2)尽量使用Prefab节点构建场景(内存不变,只需要引用即可)
3)避免DontDestroyOnLoad(或者添加Hidden Flag Dont Sale标记的资源对象)下太 多生命周期过长或者引用过多资源的复杂对象。
4)给经常使用的对象添加Tag,静态对象(运行时不移动的对象)添加Static标记。
注:FindGameObjectWithTag是效率最高的方法寻找场景对象。
2.预制体优化
1.嵌套预制体(嵌套关系)
注:不适用大规模远景对象,会增加材质与Drawcall数量。
2.预制体变体(父子关系)
1)特点:变体只是预制体的实例;不能改变与删除Prefab(父)
注:右击预制体Create > Prefab Variant创建预制体变体。
3.Drawcall:
1)概念:CPU调用图像编程接口,(CPU)调用Drawcall命令开启一个(GPU)渲染过程。
2)减少Drawcall的方式:批处理(把多个小Drawcall合并成一个Drawcall),减少CPU提交的次数与时间,并且怕批处理适合静态物体。
3.UGUI优化
1.UGUI渲染细节
1)绘制顺序是从后往前,很难保证每个像素不被重新绘制
2)若UI SpriteAtlas图集利用率不高,则大量完全透明的像素被采样也会导致重新绘制,导致纹理采样器无法尽快采样有效像素。
2.Canves优化
1)避免UI元素重叠
2)拆分使用Canves或者嵌套使用Canves(用来减少Re-batch复杂度)
3)拆分动态与静态对象,分别放入不同Canves
4)尽量不使用Layout组件(减少Layout Re-build)
5)Canves的RenderMode尽量使用Overlay模式(减少Camera调用开销)
3.射线检测优化
1)必要交互UI开启Reycast Target(非必要不开启)
2)对于复杂控件,尽量在根节点开启Reycast Target
3)对于嵌套的子Canves,开启OverrideSorting会打断射线向父级Canves传递
4.UI字体文件导入优化
1)Rendering Mode一般选择Smooth即可
2)Character:除Dynamic,其余均为静态字符集
3)Include Font Data:使用对应运行平台操作系统已有字符,则不勾选此选项( 减少内存空间)
5.UI字体优化
1)利用不多的特殊字体可以使用图片或者Custom Font(自定义图片字体)
2)利用Font.RequestCharacterInTexture(字符串)可以预载需要字体到图集
注:运行时,UIText组件会动态生成字体图集(只会保留激活的组件中的字符)
6.UI组件优化
1)UI元素如果可以拉伸,则减少UI Sprite大小
2)对于UI显隐,不使用控制透明度或者激活/关闭,而去控制Canves的激活/关闭
3)使用全屏UI,需要隐藏背后所有内容
4)在对话中时UI建议使用OnDemandRendering.renderFrameInterval = n(将渲染降低至原有的1/n) 对渲染进行降频
注:不使用Target FPS,因为会对输入也降频
补充:对于Scroll View使用RectMask2D组件裁剪,使用对象池作为实例化缓存。
注:RectMask2D组件会限制子物体的显示范围。
4.物理优化
1.物理解决方案:Box2D(2D通用开源框架), Nvidia PhysX(非确定性,硬件加速,不适用网络游戏 ) , Unity Physics(基础), Havok Physics for Unity
2.项目中Physics设置:
1)Reuse Collision Callbacks:一般建议开启,会降低托管堆GC开销。
2)Defult Solver(Velocity)Iterations:一般默认,设置迭代次数,提高精度。
3)Boradphyase Type:一般默认,对场景划分,加速物理查找。
3.项目中Time设置:
1.可以调整Fixed Timestep,降低更新频率,提高性能。
1)副作用:无法检测物理碰撞。
2)解决方案:利用射线作为高速物体的碰撞检测;利用两个渲染帧的物体位置做一个包裹盒检测物理碰撞。
注:物理更新是在FixUpdate中完成的。
4.Collider:进行碰撞检测,Trigger对象不需要Rigibody组件。
优化:1)使用简单的 Collider,用多个简单的代替Mesh Collider(三角形碰撞)
2)Mesh Collider尽量保证物体静态。
3)在PlayerSetting中开启Prebake Collision Meshes, 预先烘培碰撞网格。
5.Rigibody:进行碰撞模拟,Rigibody对象越少越好。
1)Kinematic: 不受力影响,当对其他Rigibody施加物理影响。
2)Rigibody:完全由物理引擎模拟。
6.RayCast与Overlap
1)使用NoAlloc版本的函数,较少GC(垃圾回收)开销。
2)指定对象图层进行过滤,指定RayCast距离。
3)如果大量使用RayCast操作可以通过RaycastCommand的方式批量处理,利用JobSystem来分摊到多核多线程计算。
5.动画优化
1.Animator
1)不使用字符串查询Animator。
2)使用曲线标记来处理动画事件。
3)使用Target Marching函数(目标点匹配)协助处理动画。
4)将Animator的CullingMode设置为Cull Update Transform,并禁用SkinMesh Renderer组件的Update When Offscrren使得角色不可见时不更新动画。
注:状态机会将所有的动画节点全部载入内存,开销较大。
2.Animation
1)CPU核数少时,可以使用Animation播放动画。
2)动画曲线较少时,使用Animation。
3)将Animation的CullingMode设置为Base On Renderers
3.Playable(自定义程度更高,优化的效果更好)
4.动画方案的选择:
1)简单少量曲线动画使用Animation。
2)动画要求与逻辑要求较高,并且动画资源不多使用Animator Graph(状态机)
3)动画混合要求高,需要高级动画效果(技能编辑器等)并且动画资源多,采用Animator + Playable API扩展Timeline的方式完成。
五.项目优化理论
1.剔除(Culling)
1.剔除内容:看不到的像素,网格与对象;重复且无用的资源;无用且不执行的代码
2.Unity中的剔除方案:
1)像素剔除:摄像机平截头体剔除,Bake-face Culling,Early-Z,Pre-Z Pass
2)网格剔除:Layer Mask,可见距离剔除,Occlusion(CPU + 烘培)
3)灯光剔除:Tile-Based Deferred Rendering,Forward +
4)场景剔除:Additive Scene
2.简化(Simplization)
1.简化内容:运行效率较重的资源,低效和不合适的功能
2.Unity中的简化方案:
1)Quality Settings的质量分级
2)烘培光照代替实时光照
3)简化碰撞体代替Mesh碰撞
4)Local Volume代替Global Volume
5)RayCast代替SphereCast等
6)纹理文字代替系统文字
7)Mesh/Shader/HL OD
3.合批(Batching)
1.资源Batching(Mesh,Texture,Shader参数,材质属性)
2.Draw call Batching(Static Batching,Dynamic Batching)
3.GPU Instancing(直接渲染,间接渲染,程序化间接渲染)
4.Set Pass Call Batching(SRP Batching)
六.项目优化实践
1.优化总述
· 1.性能优化流程
1)发现问题:平台,操作系统,问题发生的前提情况,一般性还是特殊性问题
2)定位问题:造成问题的位置,确定瓶颈
3)研究问题:确定方案处理问题
4)解决问题:验证处理结果与预期的一致性
2.影响性能的主要问题
1)CPU(工厂1)
2)GPU(工厂2)
3)带宽(连通道路)
4)内存(仓库)
5)隐形问题:功耗比(相同效果的消耗量),填充率(传输数据的填充度),发 热率(设备发热带来的降频影响)
3.性能问题的可能情况(由高到低):
CPU利用率 >带宽利用率 >CPU/GPU强制同步 >片元着色器 >几何图形(纹理)在CPU与GPU传输 >顶点着色器 >几何图形的复杂性
4.优化思路:
1)升维(算法复杂,优化好)/降维(算法简单,优化差)
2)维度转换(面向对象与面向数据的转化等)
3)空间与时间的取舍(TAA与DLSS等)
4)量纲转换
2.性能总览与瓶颈定位
1.Unity Profiler中常见的标记:
1)WaitForTargetFPS:等待达到目标帧率(一般CPU与GPU都没负载问题)
2)Gfx.WaitForGfxCommandsFromMainThread/WaitForCommand:渲染线程准 备接受新的渲染命令(一般瓶颈在CPU)
3)Gfx.WaitForPresentOnGfxThread/WaitForPresent:主线程等待渲染线程绘制 完成(一般瓶颈在GPU)
4)WaitForJobGroupID:等待工作线程完成(一般瓶颈在CPU)
2.Unity UPR工具
在电脑端安装UPR Desktop,然后在UPR网页中我的项目,创建测试项目,在测试列表中新建测试,并复制Session Id给UPR Desktop,然后将测试设备与电脑连接(或者连接在相同的wifi环境下),输入测试设备的IP地址,然后打开游戏,再点击开始测试,一段时间后结束在网页中就会生成相关检测报告。
3.SSAO优化
1.概述:
SSAO在URP文件中进行设置,并且可更改Rendering Path:前向渲染与延迟渲染
2.设置调整:
1)Method:一般选Interleaved Gradient,计算更快,相机静止不会出现扰动。
2)Radius(采样半径):一般设置为0.1即可,数值越大,性能消耗越大。
3)Falloff Distance:场景物体较多时影响较大,可以适度降低。
4)Quality >Source:如果是延迟渲染则无法调整,正向渲染一般默认即可。
注:延迟渲染会大幅降低渲染成本,但并不是所有平台兼容。
5)Downsample:建议开启,处理像素会变为原来1/4,大幅降低GPU性能
6)After Opaque:虽然会造成非真实的渲染,但一般情况下建议开启
7)Blur Qulity(模糊质量)与Sample(采样数):建议开启Medium或Low即可
3.其余优化方案:
1)使用HBAO(采样更少)或GTAO(采样更少且效果好)代替SSAO。
2)针对SSAO的Shader指令进一步优化。
3)采用烘培AO到光照贴图的方案。
4.AA反走样优化
注:MSAA在URP文件中,SMAA在摄像机设置中
1.MSAA:仅支持前向渲染,显卡硬件支持,效果较好,运动画面一般。
2.FXAA:开销小,适合移动平台,动态场景闪烁问题。
3.SMAA:开销较小,适合低端PC端,效果好于FXAA。
4.TAA:支持延迟渲染,效果较好,性能开销低,低帧率鬼影问题。
5.优化方案
1)高端设备采用SMAA或者TAA
2)中端设备采用FXAA
3)低端设备建议关闭AA渲染
4)一般不需要同时开启MSAA与其余后处理层面的反走样。
5.后处理优化
1.在URP文件的Post-processing设置
1)Grading Mode:支持浮点精度纹理的设备选择HDR,否则选择LDR
2)LUT size:在LDR选项下可以修改为16
3)Fast sRGB/Linear convesions:建议开启
2.影响性能较大的后处理效果:Bloom(泛光)【降低采样和迭代次数】,Depth Of Field(景深)【切换Guassian(高斯)和Bokeh的景深模式】,Motion Blur(运动模糊),Lens Flare(镜头光晕)【Occlusion设置与光晕优化】
3.优化建议:一般不使用后处理,尽量使得原始素材就接近所需要的表现效果,如果必须使用则,尽量不要使用Global,而是使用Local,而且不要堆叠过多后处理效果,应该使用脚本有目的地开启与关闭。
6.场景简化
1.远景简化
如果远景(玩家无法到达)是使用真实模型搭建,可以使用反射探针(Static旁朝下三角改为Reflection Probe Static)烘培一张只有远景模型的贴图(Convolution Type改为None),再将这张贴图赋给SkyBox/CubMap材质,最后将材质给予环境中的天空盒。
2.中景简化
调整LOD的显示范围,并且可以酌情关闭低LOD模型的阴影(Cast Shadow 改为Off),调整规则就是大物体可以减少直接裁剪的距离,但需要多个LOD模型均匀分布,而小物体则可以增加直接裁剪的距离并且关闭LOD阴影,LOD数量可以只有1个。
调整Project Settings中Quality的LOD Bias,大于1,保留更多细节;小于1,更激进剔除
7.遮挡剔除与光影剔除
1.遮挡剔除
1)开启摄像机中的Occlusion Culling。
2)静态遮挡物(墙壁等)Static旁边倒三角选择Occluder Static,静态被遮挡物体(墙壁之后的物体等)选择Occludee Static。
3)打开Occlusion窗口点击烘焙即可。
注:若遮挡物为动态物体(门窗等),可以加入Occlusion Proto 组件,通过脚本进行逻辑控制即可(函数延时实现)。
2.光源剔除
方法一:可以通过设置Rendering Layer调整光源渲染层级(详见Unity手册)
方法二:设置URP管线文件:
1)Render Limit(每个对象最大能接受几个光源影响)
2)可以调小Shadow Atlas Resolution与Shadow Resolution Tiers的值
3)调小Cascade Count的值(可以减少远距离细小阴影的个数)
8.地形优化
由于Unity提供的地形方案对移动端并不友好,可以采用插件进行地形绘制。
9.移动平台耗电量与发电量优化
移动平台存在温度墙,一旦温度过高就会降频处理,移动平台优化应该尽量拖迟触发温度墙的时间以及减少降频时间。
1.常规优化
锁60FPS时,CPU可10~12ms,GPU可6~8ms
锁30FPS时,CPU可18~20ms,GPU可8~10ms
注:移动平台可以放宽CPU限制,收紧GPU限制。
2.非常规优化
1)网络与IO:发包频率与频繁的IO读写。
2)显示亮度与FPS:动态分辨率,亮度与帧率限制。
10.启动时间优化
IOS平台与安卓平台启动App的过程不同,需要不同的优化手段。
由于能力有限,部分内容(Shader,IO,GC,网络等)无法很好理解,所以不做笔记。
注:未完成内容包括渲染流程精简,内存优化,主光源级联阴影优化,移动端打包与启动优化。