e-works数字化企业网  »  文章频道  »  基础信息化  »  移动应用

移动平台Unity3D应用性能优化

2017/6/25    来源:极客头条    作者:陈星百      
关键字:移动应用  Unity3D  
VR由于双眼double渲染的原因,对性能的优化要求比较高,在项目的进展过程中,笔者总结了一些关于移动平台上Unity3D的性能优化经验供大家分享。
    WeTest 导读
 
    做了大概半年多VR应用了,VR由于双眼double渲染的原因,对性能的优化要求比较高,在项目的进展过程中,总结了一些关于移动平台上Unity3D的性能优化经验,供分享。
 
    一、移动平台硬件架构
 
    移动平台无论是Android 还是 IOS 用的都是统一内存架构,GPU和CPU共享一个物理内存,通常我们有“显存”和“内存”两种叫法,可以认为是这块物理内存的所有者不同,当这段映射到cpu,就是通常意义上的内存;当映射到gpu,就是通常意义上的显存。并且同一段物理内存同一时刻只会映射到一个device。
 
移动平台Unity3D 应用性能优化
 
    即使是在同一物理内存上 ,之前的openGL ES规范中CPU和GPU之间的内存是不能共享的,vertex和texture的buffer是需要拷贝的。后面出来的vulkan 与IOS的metal 可以共享内存。
 
    了解了移动平台的硬件架构,就知道了 1)CPU 2) 带宽 3) GPU 4) 内存 都有可能成为移动平台3D应用性能瓶颈。
 
    二、移动平台3D应用的画面渲染过程
 
    1、CPU通过调用绘制命令(称为一次Draw Call)来告诉GPU开始进行一个渲染过程的。一个Draw Call命令会指向本次绘制需要渲染的信息,这些信息包括:顶点数据、纹理数据、shader参数(光照模型、法线方向、光照方向等)等,简单地说就 画什么,用什么画,怎么画。 
 
移动平台Unity3D 应用性能优化
 
    2、GPU接收到Draw Call命令之后就会开始进行一次单元渲染,关于GPU的单元渲染的过程是这样的(简单示意图): 
 
移动平台Unity3D 应用性能优化
 
    1)从显存中取出拷贝的顶点数据和光照模型。
 
    2)通过顶点处理器(Vertex Processor)对顶点数据进行一系列的变换和光照处理,包括裁剪处理。tips: 简单的想想,游戏中的各个物体的坐标都是参照游戏中的世界坐标系的,而实际显示的画面是玩家视角或者摄像机视角,这中间就有许多坐标系的转换。这些活就需要顶点处理器来做,最终我们得到了我们所需要视角的画面。
 
    3)到这一步,画面还只是一些多边形,而实际显示在屏幕上的是一个个像素,这里就需要(光栅处理器)Rasterizer进行光栅化(Rasterization),从而将画面变成一个像素图,把所有的顶点对应到一个一个的像素位置。
 
    4)对这些像素进行上色,通过片元处理器(Fragment Processor)中的像素着色器(Pixel Shader)按照shader光照模型,根据纹理对应位置颜色,计算元颜色,再经过深度计算、透明测试计算出每个像素的最终颜色。
 
    5)把结果输出到图像缓存中,全部完成后拿去显示。
 
    三、Unity3D应用性能优化之CPU
 
    CPU的优化非常重要,CPU的表现直接决定了VR应用的帧率,应用的耗电量,发热量。我们来看看相比于普通的app,VR应用的CPU都承担了什么责任:a、业务逻辑 b、网络通信 c、I/O操作 d、drawcall e、physic逻辑 f、GC内存回收 g、垂直同步等待。
 
    业务逻辑、网络通信、I/O操作
 
    这一块的优化和普通的app差不多。
 
    关于业务逻辑:有些不同的是Unity脚本中有一类update方法(Update、FixedUpdate、OnGUI等),这一类方法是在每帧刷新的时候调用的,是比较影响每帧耗时的,为了严格控制这一部分的执行时间,需要注意的以下几点: 
 
    a、尽量不要再Update函数中做复杂计算,如有需要,可以隔N帧计算一次,对于纯数学计算,可以开辟新线程来计算(Unity 为什么一般避免使用多线程, 实际上大多数游戏引擎也都是单线程的, 因为大多数游戏引擎是主循环结构, 逻辑更新和画面更新的时间点要求有确定性, 如果在逻辑更新和画面更新中引入多线程, 就需要做同步而这加大了游戏的开发难度。UnityEngine绝大多数类是不支持子线程的,所以一般只有纯数学计算才会用到子线程去计算。)
 
    b、关闭所有在update类中执行log的打印操作(Unity中一次log打印有时长达7ms,Profiler数据)。
 
    c、不在update类方法调用Getcomponent、SendMessage、FindWithTag这几个耗时较长的方法。
 
    d、不在update类方法中使用临时变量。
 
    关于网络通信、I/O操作:这些普通app的优化和注意点没有什么很大区别,有一点是,Unity工程中使用了资源动态加载,有些资源是保存在服务器端的,在有必要的时候才会通过网络load下去加载。这个资源动态加载需要注意一个问题:由于网络通信过程,CPU总是处于等待的状态,一般资源下载是多线程同时操作,为了尽快上屏显示资源(在这个工程中是一些图片和英雄的3D模型),但是资源有可能是在同一个帧周期中下载完毕的,如果直接加载的话,可能会出现Camera瞬时渲染过多三角形面,造成渲染时间(Camera.Render()函数执行时间)过长,,卡顿的现象。所以这里要注意,网络下载可以多线程多任务同时下载,但是在Unity主线程,要避免出现同时加载大型模型和大纹理的情况,最好使用队列的方式,保证一帧只渲染一个3D模型。
 
    关于GC
 
    为什么要把GC放在CPU这一部分?虽然GC是用来处理内存回收的,但是却增加了CPU的开销(GC一次开销可长可短,有时长达100ms)。因此对于GC的优化目标就是尽量少的触发GC。
 
移动平台Unity3D 应用性能优化
 
    首先我们要知道所谓的GC是Mono运行时的机制,而非Unity3D游戏引擎的机制,所以GC也主要是针对Mono的对象来说的,而它管理的也是Mono的托管堆。 明白了这一点,你也就明白了GC不是用来处理引擎的Assets(贴图,音效,模型等等)的内存释放的,因为U3D引擎也有自己的内存堆而不是和Mono一起使用所谓的托管堆。其次我们还要清楚什么东西会被分配到托管堆上?对,就是引用类型。引用类型包括:用户自定义的类,接口,委托,数组,字符串,Object.而值类型包括:几种基本数据类型(如:int,float,bool等),结构体,枚举,空类型。所以GC的优化也就是代码的优化。
 

责任编辑:李欢
本文为授权转载文章,任何人未经原授权方同意,不得复制、转载、摘编等任何方式进行使用,e-works不承担由此而产生的任何法律责任! 如有异议请及时告之,以便进行及时处理。联系方式:editor@e-works.net.cn tel:027-87592219/20/21。
e-works
官方微信
掌上
信息化
编辑推荐
新闻推荐
博客推荐
视频推荐