从零开始游戏开发Unity优化:UI控件优化 | 全面总结 |建议收藏
Posted 小听歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始游戏开发Unity优化:UI控件优化 | 全面总结 |建议收藏相关的知识,希望对你有一定的参考价值。
你知道的越多,你不知道的越多 🇨🇳🇨🇳🇨🇳
点赞再看,养成习惯,别忘了一键三连哦 👍👍👍
文章持续更新中 📝📝📝
Proilier性能
drawcall不显示,显示SetPassCalls
渲染材质的先后顺序,材质渲染消耗时间,材质切换渲染切换一次:可以成为SetPassCalls,俗称DrawCall
切换渲染材质的顶点批次
一个批次渲染材质
面试经典:如何解决UI的卡顿
Canvas画布,节点!
Canvas优化要点
一个Canvas下的所有UI元素都是合并在一个Mesh网格中的,过大的网格Mesh更新时开销过大
合批优化:同一个批次进行渲染,三角形放同一个批次
移动会进行重新合批、重新绘制、开销大
一般比较复杂的UI界面,都拆分成一个独立的子Canvas
动静分离
静态UI不会被重建,动态UI会被重建
但是如果Canvas细分太多,会导致DrawCall增多
把同一个面板的UI资源放在同一个图集里,创建一个SpriteAtlas,将Sprite指定此图集
背包资源放在一个图集里
如果一个面板的UI资源来源多个图集,打开面板会卡段
背景大图不要和小图放在一起
还有一个Overdraw GPU优化
绘制区域有半透明元素,同一个位置,同一个像素点被同时绘制
新手引导,空的透明的四边形,点击屏幕任意位置开始
透明的UIImage
无图的UI遮罩点击优化
不执行点击的UI元素,不要勾选RayCaster,每一帧回去检测
少用布局组件LayoutGroup或者Content SizeFitter
用户操作 重绘 消耗大量计算时间
写算法自己算
Layout原理
遍历SetDirty对象会消耗性能
UI控件优化
Unity自带的ScrollView的问题
滚动,UI元素位置变化,Canvas就会重构,重新合批
如果ScrollView下的元素没有UI点击,千万不要去加RayCaster组件
Mask组件可见范围以外禁止显示,但不代表不渲染
ScrollRect控制滚动条,会把所以物品全部渲染,不会判断哪些不能被渲染
高性能滚动视图的实现思路
初始化滚动时
计算可视范围
遍历每一个格子,判定其是否位于可视范围内
如果可见,则显示,否则,隐藏
滚动时
重新计算可见格子
如果有格子移除,则将其格子用于新的格子的显示
类似对象池的思想
字体UI优化
角色名3D字体
文字+图标+血条
不用Text组件(有性能问题),使用TextMeshPro
🎁🌻🌼🌸 粉丝福利来喽 🎁🌻🌼🌸
- 免费领取海量资源 🎁
简历自测评分表、Unity职级技能表、面试题库、入行学习路径等- 《Unity游戏开发五天集训营 》50个名额 🎁
我给大家争取到了 50个《游戏开发五天集训营 》名额,原价198,前50个免费
扫码加入,暗号小听歌
即可参加ARPG狼人战斗系统、饥荒生存类游戏开发、回合制RPG口袋妖怪游戏等游戏开发训练营- 额外抽奖机会🎁
参加游戏训练营、还有机会获得大厂老师在线面试指导、或者有机会获得价值1998元的《Unity极速入门与实战》课程
Unity游戏开发初探Unity动画优化
一、简介
在最近的优化工作中,马三发现项目中的动画文件内存占比实在是太大了,峰值竟然有200多mb,很明显需要进行优化。经过一番网上查阅资料并结合自己实际操作以后,得到一些需心得体会,在这里马三记录一下并且分享给大家,希望对大家能有一些帮助。
二、动画压缩的注意事项
1.fbx中的动画无法压缩精度,即降低动画文件的浮点数精度
fbx中的动画无法压缩精度,压缩完重启Unity会发现又恢复为原来的样子,并且在版本控制中看不出差别。原因是fbx在Unity中被识别为只读文件,精简动画这个修改的结果实际上是保存在Library/metadata。也就是说这个修改是本地化的操作,无法放入版本管理。导入fbx中的animation是read-only的(考虑到re-import,可编辑的意义其实不大),要编辑需要将动画文件复制出来。可以选中fbx中的动画文件,ctrl+D复制一份出来。复制出的文件是可以编辑的,运行脚本也无问题。然后项目中去使用这个复制的动画文件。
2.Ctrl+D复制出来Anim以后会发现,复制出来的这个anim的文件体积会比原来的fbx动画体积还要大
Ctrl+D复制出来Anim以后会发现,复制出来的这个anim的文件体积会比原来的fbx动画体积还要大这个也是正常的。项目中fbx一般是二进制方式存储的,复制出来的anim如果是用text存储的话,体积会比原来大很多。这个没有太大的影响,最后还要看打出来的ab的大小,实测证明anim打出来的ab要比fbx的体积小很多。
下面列举了两幅图,对比说明了anim动画和fbx动画打出的bundle文件大小对比和运行时内存占用的对比情况:
anim动画assetbundle文件大小:
anim动画运行时占用内存:
fbx动画assetbundle文件大小:
fbx动画占用运行时内存:
可以看到无论是AssetBundle的体积还是运行时内存占用,使用抽离出来的anim动画都比使用fbx中的动画要节省。
3.去除动画文件的scale信息
对于一般的人形动画需求,不会有模型骨骼scale变化的情况。因此我们可以把动画信息的scale部分去除,可以节约一部分大小。
4.为什么压缩动画的float精度、剔除Scale曲线,可以达到减少运行时内存占用
Mecanim的动画系统的压缩确实不是靠改变float类型来达到的,而是通过降低数值位数后,将曲线上过于接近的数值(例如相差数值出现在小数点4位以后)直接变为一致,可以产生更多的const曲线,从而让引擎达到更高效存储的效果,进而达到所谓的“压缩”结果。缩短float类型的精度,导致动画文件内点的位置发生了变化,引起Constant Curve和Dense Curve的数量也有可能发生变化,最终可能导致动画的点更稀疏,而连续相同的点更多了。所以Dense Curve是减少了,Constant Curve是增多了,总的内存是减小了。
5.尽量使用从fbx中复制出来的anim动画,而不是直接引用fbx中的动画文件
很多项目在开发初期阶段,为了快速迭代,并没有使用后处理工具将导入的带有动画的fbx文件进行动画抽离,而是直接是用fbx中的动画文件。实际上这种做法也会造成内存占用较多。因为fbx文件有可能依赖了一些贴图、材质,而且如果项目处理的不够好的话,还会导致交叉引用的出现。比如有一个主角的fbx动画文件,由于美术同学的一些操作,将它引用了怪物的一些材质,然后这个材质又会引用一些纹理。我明明只想加载简简单单的一个主角待机动画,结果就像从泥土里面拎花生一样,带出了一连串的其实不必要加载的文件,白白占用了大块的内存空间,很有可能就因为这一些内存空间被占用就导致了游戏的闪退和崩溃,这个问题是在我们项目中真实遇见过的情况,很值得注意一下。
6.动画文件压缩方式(Anim.Compression)
一般项目都会对这个进行设置,所以就放在最后讲了。对于包含有anim动画的fbx文件,Unity提供了下面的这个设置面板。在Animation选项卡中,我们可以通过设置Anim.Compression来调整动画的文件的压缩方式:
-
Off 关闭压缩
-
Keyframe Reduction 减少没有必要的关键帧
-
Optimal 优化压缩,官方会选择最优的压缩方式来进行压缩,建议选择这个,我们项目也是选择的这个。
7.动画精度压缩与曲线剔除代码
1 //---------------------------------------------- 2 // ColaFramework 3 // Copyright © 2018-2049 ColaFramework 马三小伙儿 4 //---------------------------------------------- 5 6 using System; 7 using System.IO; 8 using System.Reflection; 9 using Sirenix.OdinInspector; 10 using Sirenix.OdinInspector.Editor; 11 using UnityEditor; 12 using UnityEngine; 13 using UnityEngine.Profiling; 14 15 /// <summary> 16 /// 动画优化,存储占用/内存占用/加载时间 17 /// 通过降低float精度,去除无用的scale曲线 18 /// 从而降低动画的存储占用、内存占用和加载时间. 19 /// 使用方法 20 /// 通过菜单ColaFramework/OptimiseToolKits/优化动画打开窗口, 21 /// 在Assets目录下选择要优化的动画,点击Optimize按钮,等待一段时间即可 22 /// </summary> 23 public class AnimtionClipOptimizeToolKit : OdinEditorWindow 24 { 25 [ShowInInspector] 26 [InfoBox("剔除Scale曲线")] 27 private bool m_excludeScale; 28 29 private static AnimtionClipOptimizeToolKit _window; 30 31 [MenuItem("ColaFramework/Optimise/AnimtionClipOptimize")] 32 [MenuItem("Assets/Optimise/AnimtionClipOptimize")] 33 protected static void Open() 34 { 35 _window = GetWindow<AnimtionClipOptimizeToolKit>("动画优化压缩工具"); 36 _window.Init(); 37 _window.Show(); 38 } 39 40 private Vector2 m_scoll; 41 private bool m_ing; 42 private int m_index; 43 44 private string animclipPath; 45 private AnimationClip animClip; 46 private static MethodInfo getAnimationClipStats; 47 private static FieldInfo sizeInfo; 48 49 private void Init() 50 { 51 Assembly asm = Assembly.GetAssembly(typeof(Editor)); 52 getAnimationClipStats = 53 typeof(AnimationUtility).GetMethod("GetAnimationClipStats", BindingFlags.Static | BindingFlags.NonPublic); 54 Type aniclipstats = asm.GetType("UnityEditor.AnimationClipStats"); 55 sizeInfo = aniclipstats.GetField("size", BindingFlags.Public | BindingFlags.Instance); 56 } 57 58 protected override void OnGUI() 59 { 60 var selects = Selection.objects; 61 62 using (var svs = new EditorGUILayout.ScrollViewScope(m_scoll)) 63 { 64 m_scoll = svs.scrollPosition; 65 foreach (var obj in selects) 66 { 67 var clip = obj as AnimationClip; 68 if (clip == null) 69 continue; 70 EditorGUILayout.ObjectField(clip, typeof(AnimationClip), false); 71 } 72 } 73 74 75 using (new EditorGUILayout.HorizontalScope()) 76 { 77 m_excludeScale = EditorGUILayout.ToggleLeft("Exclude Scale", m_excludeScale); 78 79 if (GUILayout.Button("Optimize")) 80 { 81 m_ing = true; 82 } 83 } 84 85 if (m_ing) 86 { 87 if (m_index >= selects.Length) 88 { 89 m_ing = false; 90 m_index = 0; 91 EditorUtility.ClearProgressBar(); 92 return; 93 } 94 95 var info = string.Format("Process {0}/{1}", m_index, selects.Length); 96 EditorUtility.DisplayProgressBar("Optimize Clip", info, (m_index + 1f) / selects.Length); 97 98 var obj = selects[m_index]; 99 m_index++; 100 var clip = obj as AnimationClip; 101 if (clip == null) 102 return; 103 animClip = clip; 104 animclipPath = AssetDatabase.GetAssetPath(clip); 105 Log("优化前---->"); 106 FixFloatAtClip(clip, m_excludeScale); 107 Log("优化后---->"); 108 } 109 } 110 111 private static void FixFloatAtClip(AnimationClip clip, bool excludeScale) 112 { 113 try 114 { 115 if (excludeScale) 116 { 117 foreach (var theCurveBinding in AnimationUtility.GetCurveBindings(clip)) 118 { 119 var name = theCurveBinding.propertyName.ToLower(); 120 if (name.Contains("scale")) 121 { 122 AnimationUtility.SetEditorCurve(clip, theCurveBinding, null); 123 } 124 } 125 } 126 127 var curves = AnimationUtility.GetCurveBindings(clip); 128 foreach (var curveDate in curves) 129 { 130 var curve = AnimationUtility.GetEditorCurve(clip, curveDate); 131 if (curve == null || curve.keys == null) 132 { 133 continue; 134 } 135 136 var keyFrames = curve.keys; 137 for (var i = 0; i < keyFrames.Length; i++) 138 { 139 var key = keyFrames[i]; 140 key.value = float.Parse(key.value.ToString("f3")); 141 key.inTangent = float.Parse(key.inTangent.ToString("f3")); 142 key.outTangent = float.Parse(key.outTangent.ToString("f3")); 143 keyFrames[i] = key; 144 } 145 146 curve.keys = keyFrames; 147 clip.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curve); 148 } 149 } 150 catch (System.Exception e) 151 { 152 Debug.LogError(string.Format("CompressAnimationClip Failed !!! animationPath : {0} error: {1}", clip.name, 153 e)); 154 } 155 } 156 157 #region LogInfo 158 159 private void Log(string title) 160 { 161 Debug.LogFormat("{0} FileSize:{1},MemorySize:{2},InspectorSize:{3}", title, GetFileSize(), GetMemorySize(), 162 GetInspectorSize()); 163 } 164 165 private long GetFileSize() 166 { 167 var fileInfo = new FileInfo(animclipPath); 168 return fileInfo.Length; 169 } 170 171 private long GetMemorySize() 172 { 173 return Profiler.GetRuntimeMemorySizeLong(animClip); 174 } 175 176 177 private int GetInspectorSize() 178 { 179 var stats = getAnimationClipStats.Invoke(null, new object[] {animClip}); 180 return (int) sizeInfo.GetValue(stats); 181 } 182 183 #endregion 184 }
此工具也已经集成进了ColaFramework:https://github.com/XINCGer/ColaFrameWork/blob/master/Assets/Editor/OptimizeToolkits/AnimtionClipOptimizeToolKit.cs
三、总结
在本篇博客中,马三跟大家一起分享了一下在优化项目动画文件内存占用中的一些注意事项,希望可以对大家起到一些帮助。同时这里也有一些非常不错的关于动画内存优化的博客和uwa的问答,马三在这里贴给大家,可以自己阅读一下,加深理解。
最后的最后,还不得不提一下 ACL 这个非常牛逼的C++编写的动画压缩库,至于它的原理和如何使用,马三在这里先买个关子,我会在后面的博客中进行讲解,敬请期待!
如果觉得本篇博客对您有帮助,可以扫码小小地鼓励下马三,马三会写出更多的好文章,支持微信和支付宝哟!
作者:马三小伙儿
出处:https://www.cnblogs.com/msxh/p/14090805.html
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!
以上是关于从零开始游戏开发Unity优化:UI控件优化 | 全面总结 |建议收藏的主要内容,如果未能解决你的问题,请参考以下文章