Scene
1.避免场景节点深度过大,代码生成的游戏对象尽可能放在根节点下;
2.构建场景尽量使用Prefab,而不是GameObject创建;
3.避免DontDestoryOnLoad节点下有太多生命周期长或引用资源多的复杂节点对象;
4.为经常访问的游戏对象添加Tag标签,静态物体标记Static;
Prefabs
1.通过预制体嵌套,从而创建多个易于编辑的复杂游戏对象层级视图(如房子预制体由窗户、门、家具、墙柱等预制体分别组成);
优点:方便资源重复利用与预制体管理;
uv制作和分配更合理,增加贴图利用率;
方便利用工具做效果较好的LOD(因为预制体划分较细);
修改方便;
便于做精细的场景遮挡剔除;
缺点:Bundle依赖关系复杂;
可能增加Drawcall数量;
不适合大规模远景对象;
实际开发中沟通和设计成本大;
2.创建预制体变体Prefabs Variant(本质还是预制体的实例化),进行一些预制体的修改和使用;
UGUI
UGUI工作流
1.UGUI在Transparent渲染队列中进行渲染,即从后往前画,造成Overdraw过高,片元着色器利用率过高,增加GPU负担;
2.Canvas负责管理UGUI元素,以及UI渲染网格的生成与更新,并向GPU发送DrawCall指令;
3.每个Canvas在绘制之前,都需进行合批,若所有UI元素保持不变,则会直接使用保存的结果;
4.若UI元素发生改变,则将该Canvas标记为’Dirty’,此类Canvas会触发Re-batch(递归处理每个UI元素):
ⅰ.根据UI元素深度进行排序;
ⅱ.检查UI元素覆盖关系;
ⅲ.检查UI元素材质并进行合批(多线程处理);
此过程包含C#层触发的Re-Build过程(接口调用):
ⅰ.当UI元素位置、大小、颜色发生变化时,或根据层级深度排序时标记为’Dirty’, 触发Layout Rebuild;
ⅱ.当顶点数据或材质、贴图数据被标记为’Dirty’时,触发Graphic Rebuild;
优化思路
1.当图集利用率不高时(如存在大量透明像素),会造成片元着色器利用率过高,同时纹理采样器浪费大量时间在无效的像素上,致使需要采样的像素不能被尽快采样,即纹理采样器填充率过低,浪费性能;
2.将可能打断合批的层移到最下面的图层,尽量避免UI出现重叠区,造成合批被打断;
3.拆分多个同级或嵌套的Canvas,以减少Re-batch的复杂度;
4.动态与静态的对象放在不同的Canvas下;
5.不使用Layout组件(性能消耗大,建议自写),字体尽可能替换为图片,其次选用TMP;
RenderMode尽量选用Overlay,减少Camera调用开销;
6.仅在必要时开启Raycast Target,开启此选项的组件越少、层级越浅,性能越好(以按钮为例,应将射线检测开启在根节点上)。同时,对于嵌套的Canvas,使用OverrideSorting打断射线,以避免射线向上一层级Canvas传递;
7.尽量减少每个批次的渲染顶点数(数据查看方式:Profiler-->UI-->Vertex Count);
8.UI的显隐尽量使用Canvas控件控制;
9.对于全屏UI界面,应隐藏其背后所有内容;对于帧率需求不高的UI界面,应使用OnDemandRendering接口对渲染进行降频,而对输入不降频;
10.Scroll View需要大量实例化子对象控件,因此使用时建议通过RectMask2d进行裁剪,并使用基于位置的对象池作为实例化缓存;
11.可通过Font.RequestCharacterInTexture预先加载运行时需要的字体,以降低启动时间;
Physic
Player Settings-->Physics设置:
1.Auto Sync Transforms开启后,会在每次Transform变化后立即进行物理更新。一般默认不开启,这个情况下会在FixedUpdate进行物理更新;
2.Reuse Collision Callbacks会在碰撞时重用之前的碰撞结果实例,碰撞结果往往只是数值不同,因此保持开启可大量减少GC;
3.Default Solver Velocity Iterations默认迭代次数表示每次物理更新的迭代次数,越高则结果越精确,同时CPU负担越高;
4.Layer Collision Matrix应合理设置,仅开启必要的碰撞关系检测,通过对每个碰撞对象设置图层进行规范调整;
Player Settings-->Time设置:
5.Fixed Timestep为物理渲染帧时间,在手机平台上可适量调大,此时应注意高速碰撞遗漏问题;
6.Maximum Allowed Timestep为卡顿时允许的最大物理渲染帧时间,建议0.1-0.6之间;
7.尽量用简单的Collider替代Mesh Collider,即便是多个。必须使用Mesh Collider的物体,尽量设置为Static,并在Player Settings-->Player下勾选Prebake Collision Meshes,以在构建程序时预先构建出网格;
8.使用Collider时,尽可能不使用Rigidbody。对于能够勾选Is Kinematic的,应尽量勾选(勾选时不算做Rigidbody);
9.使用RayCast或Overlap时,应尽量选择NoAlloc版本的函数,无GC开销;同时要对图层进行过滤,在RayCast中应合理规定距离;对于大量的RayCast操作,可通过RaycastCommand进行批量处理,充分利用多核多线程计算;
Animation
Animation
1.播放单个Animation Clip时,Legacy Animation系统更快,因为直接采样曲线并接入Transform;
2.由于动画的缩放曲线比位移、旋转开销大,所以尽量减少使用;
3.常数曲线不会每帧写入场景,更加高效;
Animator
4.不使用字符串查询Animator;
5.使用曲线标记处理动画事件;
6.使用Target Marching函数协助处理动画;
7.将Animator的CullingMode设置为Based On Renderers来优化,并禁用SkinMesh Renderer的Update When Offscreen让角色不可见时停止更新动画;
8.Animator Controller Graph中所有动画节点的Animation Clip都会载入内存,对于大量动画比较消耗性能,可用Playable API(可使用PlayableGraph)解决;
9.Animation适用于动画曲线较少(如UI,Transform动画),运行平台CPU核数较少的场景,而Animator相反,因此在开发时应根据具体情况选用;