zoukankan      html  css  js  c++  java
  • 浅谈优化

    UI的拼接要讲究章法,根据一定的效率流程去走,会提高效率,还需要遵守原则,提高性能

    流程如下:

    1、原画师提供效果图

        原画师一般会先给一张效果图,表示这个界面风格会做成什么样的,基本功能都会展示出来,包括按钮的大小和图片等,虽然是一个静态的界面,但是已经展示了所有的功能和一系列的变化,这个界面上所需要的图在这个界面上都能看得到,比如点击的时候的状态等,每一个按钮的颜色和图标等都会展现

    2、美术切图

        美术切图师会根据效果图把这些图标都切出来,切成一些碎图(用到的资源),提供给程序

    3、程序拿到碎图

        因为一个碎图都会让GPU传送数据一次,这样会增加DrawCall,因此拿到碎图以后需要打成大图,一般用TexturePacture这个软件

        RGBA8888:每一个通道占8位

        RGB565:没有透明度通道

        大图尺寸大小:

          如果要兼容所有机型:则打成1024*1024

          如果是在Iphone4以前,如果传一个比1024大的,则会发现手机屏幕是黑的,因为那时候的手机的GPU只能处理1024*1024以下的图片,超过了这个大小,GPU就不能识别和解压,因为GPU的显存比较小,所以GPU的显存决定了图片的大小,大于了则会黑屏

        2048*2048:高端机,Iphone以下会不能适配

    4、在TexturePacker中打成大图

        导出,分别是.png文件和.tpsheet文件,

        在unity中导入插件texture import,做成图集后,把图集生成的这两个文件拖到Unity中后,然后自动切好碎图

        切图:根据UV坐标切的,在.tpsheet文件中,记录的切图的格式,

      QA:碎图打成大图?

        DC:CPU向GPU传输数据,没传送一次数据就是一个drawcall,传送的是两种数据:Material和Mesh

        降低Draw其实就是降低Material和Mesh的传输次数,Material和Mesh只要发生了变化,那么DrawCall就会重新传输或多次传输

        碎图没传送一次都会产生一次DrawCall,做成大图之后,只需要传输一次就可以了,会有效的降低DrawCall

      Mesh:

        网格合并:

          减少Mesh的传输次数

          Dynanic Batch:小兵和麻将

          两个image是否能合并,需要看Material是否一致,图片是否在同一个大图上

        Batch:

          条件:同类型的Mesh,同一个材质球,这两个必须是一致的,如果有一个发生了变化,就会分开发,不会合并

          Dynanic Batch:用程序的方式进行合并,

          Static Batch:把场景中的房子、石头进行静态批处理

        RPG:DrawCall要少于150

      Material:

        在做UI界面的时候,尽量用自己的材质球,容易控制,不添加材质球会自动使用unity默认的材质球

    UI优化方面:

      UI层级计算:

        1、计算层级:

          unity会先按照是否同层级,如果同层级的话,会看是否同一个材质球

          在Shader中Queue会把场景中所以的物体分为几个渲染层次,分别是Background(1000)、Geometry(2000)、AlphaTest(2450)、Transparent(3000)、Overlay(4000)五个层级,相机中最先渲染Background,比如同样位置的cube,它的xyz都一样,谁的Tags标记在最前面,谁最先渲染,

          UI也是一样的,Unity会把物体分为很多层级,根据层级去划分,然后同一层级里又按材质球进行划分,比如Text和Image都是同层级的,但是不能合并,有两个DrawCall

          1.如果有一个UI元素,它所占的屏幕范围内(通常是矩形),如果没有任何UI在它的底下,那么它的层级号就是0(最底下)

          2.如果有一个UI在其底下且该UI可以和它Batch,那么它的层级号与底下的UI层级一样

          3.如果有一个UI在其底下但是无法与它Batch,那它的层级号为底下的UI的层级+1

          4.如果有多个UI都在其下面,那么按前两种方式,遍历计算所以的层级号,其中最大的那个作为自己的层级号

        2、合并批次原则:

          1、Unity会将每一层元素进行一个排序(按照材质、纹理等信息),合并掉可以Batch的元素成为一个批次

          2、Text组件会排在Image组件之前渲染

          3、Unity会再做一个优化,即如果相邻间的两个批次正好可以Batch的话就会进行Batch,

             比如说在0层级里面有text和image,在1层级里面也有text和image,渲染的时候先渲染0层级的text然后image,再渲染1层级的text,然后1层级的image,如果这两个image用的同一个材质球,这两个image也能合并,那么0和1这两个层级也能合并,产生两个DrawCall

        总结:1、有相同材质和纹理的UI元素是可以Batch的,可以Batch的UI上下叠在一块不会影响性能,但是如果不能Batch的UI元素叠在一起,就会增加DrawCall开销

           2、尽量让同一个材质球上的东西放在同一级上

             3、有些情况可以考虑人为增加层级从而减少DrawCall,比如一个Text的层级为0,另一个可Batch的Text叠在一个图片A上,层级为1,那此时2个Text因为层级不同会安排2个DrawCall,但如果在第一个Text下放一个透明的图片(与图片A可Batch),那两个Text的层级就一致了,DrawCall就可以减少一个

           4、要尽量避免使用Mask,其实Mask的功能有些时候可以变通实现,比如设计一个边框,让这个边框叠在最上面,底下的UI移动时,就会被这个边框遮住(Mask的原理采用的OPengl的模板,其下面的所有元素都不会合并)

           5、Z值保持为0(Z值不一样也会分批次传输)

      UI重建:

          1,、动静分离

            1、比如在做NPC血条的时候,当NPC动的时候,血条跟着NPC进行位移,这样的经常变动的UI单独放在一个Canvas下面,

            2、在制作UI时,一定要仔细查验UI层级,删除不必要的UI元素,这样可以减少深度排序的时间以及Rebuild的时间

            3、减少Rebuild的频率,将动态UI元素(频繁改变如顶点、Alpha、坐标和大小等的元素)与静态UI元素分离出来,放到特定的Canvas中

            4、谨慎使用UI元素的enable与disable,因为它们会触发耗时较高的rebuild,替代方案之一是enable和disable,UI元素的canvasrender.setDisable或Canvas

            5、谨慎使用Text的BestFit选项,虽然这个选项可以动态的调整字体大小以适应UI布局而不会超框,但其代价是很高的,Unity会为用到的该元素所用到的所有字体生成图元保存在Atlas里,不但增加额外的生成时间,还会使得字体对应的atlas变大

            6、谨慎使用Canvas的PixelPerfect(像素最优化)选项,该选项会使得UI元素在发生位置变化时,造成layoutRebuild。(比如ScrollRect滚动时,如果开启了Canvas的pixelPerfect,会使得Canvas.SendWillRenderCanvas消耗比较高)

            7、使用缓存池来保存ScrollView中的Item,对于移出或移进View外的元素,不要调用Disable或enable,而是把它们放到缓存池中取出服用

            8、除了rebuild过程之外,UGUI的touch处理消耗也可能会成为性能热点。因为UGUI在默认的情况下会对所有可见的Graphic组件调用raycast。对于不需要接收touch时间的graphic,一定要禁用raycast,对于unity5以上的可以关闭graphic的RaycastTarget,而对于unity4.6,可以给不需要接收touch的UI元素加上canvasgroup组件,关闭Interactable

      多层级渲染:

            同一个像素块的地方,有多个UI控件在绘制,它的像素buffer会不断的叠加累计, 

            一般来说,造成GPU性能瓶颈主要有两个原因:复杂的vertext或pixel shader计算以及overdraw造成过多的像素填充。在默认情况下UGUI中所以UI元素使用都使用UI/Default Shader,因此在优化的时候可优先考虑解决OverDraw问题,OverDraw主要是因为大量UI元素的重叠引起的,查看OverDraw比较简单,在Scene窗口中选择overDraw模式,场景中越亮的地方表示overDraw越高

          为了降低OverDraw,可以做如下优化:

            1、禁用不可见的UI,比如当打开一个系统时如果完全挡住了另外一个系统,则可以将被遮挡住的系统禁用

            2、不要使用空的Image,在Unity中,RayCast使用Graphic作为基本元素来检测touch,在笔者参与的项目中,很多人使用空的image并将alpha设置为0来接收touch事件,这样会产生不必要的overdraw

            3、只挂载Button替代空的image

        性能检测工具:

            profile

    NGUI:

        原理:和UGUI的原理是一样的,UGUI是在NGUI的原理上发展出来的

        渲染原理:

          1、以Panel为单位

          2、同一材质球和同一Panel上的控件:会统一发送给GPU,不分层级

          3、同一类型的网格:一起传输

    UI制作的各项指标(衡量游戏好坏的标准)

        1、首先是安卓2G低端机型要流畅运行在20到25fps,内存不超过350MB

        2、IOS1G低端机型流畅运行20到25fps,内存不超过300MB

        3、场景加载速度:启动场景速度尽量控制在5秒以内。还有优化是对性能和效果的权衡,这点是非常重要的,不能只考虑性能而不讲究美术效果,或者反过来只追求美术效果,玩都不能玩的话,游戏也是不成功的。

        4、顶点数:手机上:如果游戏能流畅运行,保持2W个顶点,角色的顶点数一般700----3000左右,主角色2000左右,npc:1000以下,最大承载量5W个

              PC上:最大承载量:10W左右,主角色:5000---8000个

      内存管理:

        1、程序代码: 

          1、unity3d使用的库:.Data都是unity3D常用的库文件

          2、程序员写的代码

          优化(PlayerSetting):

            1、API Compatibility level选择.Net 2.0 Subset(能把项目中没必要用到的dll去掉)

            2、Stripping Level:表示从build的库中剥离的力度,每一个剥离选项都将从打包好的库中去掉一部分内容,你需要保证你的代码没有用到这部分被剥离的功能,选为“Use micro mscorlib”的话,将使用最小的库

            3.string改为stringbuilder

            4、foreach改为for

        2、托管代码:

          1、是被Mono使用的一部分内存,.netmono框架里

          2、托管堆中存储的是你在你的代码中申请的内存,一般来说,无非是new或者Instantiate两种生成object的方法(事实上Instantiate中也调用了new)

          优化:

            1、减少对GameObject的Instantiate()和Destroy()的调用

            2、在合适的时候,也可以手动地调用System.GC.Collect()来建议系统进行一次垃圾回收

            3.多用缓存池

        3、本机堆:

          1、unity引擎进行申请和操作的地方,比如贴图、音效、关卡数据等

          2、资源:纹理、网格、音频等

          3、GameObject和各种组件

          4、引擎内部逻辑需要的内存:渲染器、物理系统、粒子系统等

          优化:

            1、在场景初始化的时候,我们要尽量的减少场景中摆放的物体,所有的资源都是采用动态加载的方式,都放在assetbundle包里,当你加载完成一个Unity的scene的时候,scene中的所有用到的asset(包括Hierarchy中所有GameObject上以及脚本中赋值了的材质,贴图,动画,声音等素材),都会被自动加载(这正是Unity的智能之处),在场景初始化的时候

            2、在脚本里面声明直接拖拽的,这样的物体是无法释放的,只有当这个脚本被释放了,那么这个GameObject才会被释放,因此尽量减少这样的引用

            3、尽量减少在Hierarchy对资源的直接引用,而是使用Resource.Load的方法,在需要的时候从硬盘中读取资源,在使用后用Resource.UnloadAsset()和Resource.UnusedAssets()尽快将其卸载掉

            4、尽量减少代码的耦合和对其他脚本的依赖是十分有必要的

            

  • 相关阅读:
    WAS日常维护中的重启时机——总结
    利用Shell生成Zabbix监控的数字报表
    Zabbix version upgrade (1.8.3 to 1.8.12)
    xeyes命令
    centos系统调节屏幕亮度
    centos7 安装kchmviewer 软件
    ftp使用FileZilla工具传输文件
    搭建vsftpd服务并实现本地用户访问
    centos中创建服务和关闭防火墙的基本命令
    阿里云vsftpd登录失败:530 Permission Denied.
  • 原文地址:https://www.cnblogs.com/xingyunge/p/7594226.html
Copyright © 2011-2022 走看看