在游戏开发过程中,游戏性能是非常重要的。如果游戏运行很慢、卡顿甚至卡死就可以知道游戏出现性能问题。在尝试解决问题前需知其所以然,然后尝试不同解决方案。若是依靠或是自身原有的经验去解决问题,可能会做无用功,甚至引申出更复杂的问题。在这里就需要用到性能分析工具,性能分析工具可以提供游戏性能表现的详细息信。透过游戏运行的外在表现,获取运行运行时各方面性能内在信息。如CPU、GPU及内存等使用情况,锁定引起性能问题所在。
Unity Profile
Unity Profile是Unity常用的官方性能分析工具,在开发游戏过程中,借助Profile来分析CPU、GPU及内存使用状况。
Unity Profile窗口
打开Unity Profile窗口:Window > Analysis > Profiler (快捷键Ctrl+7)
Unity Profile窗口左侧,有一列Profilers,每个Profiler显示游戏某一个方面的信息。如CPU Usage(CPU使用情况)、GPU Usage(GPU使用情况)、Rendering(渲染)、Memory(内存)、Audio(音频)、Video(视频)、Physics(物理)、Physics(2D)(物理2D)、Network Messages(网络消息)、Network Operations、UI、UI Details、Global Illumination(全局光照)
Unity Profile窗口左上角的Add Profile添加需要的Profile,选中某个Profile通过右上角的"✖"隐藏Profile。
Unity Profile窗口顶部的控制按钮:
Record:监测运行数据
Deep Profile:深度分析,所有脚本代码将被分析。包括所有函数调用,游戏代码中花费的时间,都将被记录。注:深度分析会产生非常大的开销,占用大量内存。
Profile Editor:在Editor模式下的性能消耗数据,不需要运行
Editor:要分析在另一台设备的游戏或在另一台计算机上的播放器,可以将Unity编辑器连接到另一台设备或计算机。下拉Editor列表显示在本地网络上所有运行播放器。在Build Settings对话框中找到Development Build复选框勾选,让编辑器能够连接到播放器。在这里还可以勾选Autoconnect Profiler,使编辑器和播放器在启动时自动连接。
Allocation Callstacks:
Cear on Play:
Clear:清理监测运行数据
Load:读取先前保存的数据,在按下shift按钮时单击“Load”,则文件内容将附加到内存中的当前配置文件帧。
Save:将录制的帧写入文件,以(.data)为后缀名
Frame:显示所在帧数/总帧数。
◀▶:向前/后一帧
Current:跳到当前帧
2020.05.07
Profiler.FinalizeAndSendFrame:这个是Unity Profiler在记录和传输性能数据的开销,可忽略。
WaitForJobGroup:这个是主线程在等待子线程完成的耗时开销,如果该项较高,那么说明该帧中某子线程的开销很大。
Camera.Render:是Unity引擎的主要渲染函数,其中负责了绝大部分场景的渲染工作。
Culling:遮挡剔除
Drawing:渲染操作
Render.OpaqueGeometry:不透明渲染函数(正常游戏物体渲染)
Render.TransparentGeometry:半透明渲染函数(玻璃等半透明材质渲染)
Camera.ImageEffects:渲染后期处理效果(Bloom、运动模糊、景深等效果)
案例:作者最近在项目中遇到大量使用玻璃游戏物体,通过Ciconia Studio的Glass Shaders玻璃插件实现效果,项目在性能测试阶段监测到对GPU消耗极高,在Profile GPU Usage数据分析确定Render.TransparentGeometry消耗
然后当然是去搜索RenderTexture.GrabPixels消耗原由然后看到
https://gameinstitute.qq.com/community/detail/128139
然后就去项目Glass Shaders中找到罪魁祸首GrabPass{}
这里我解释一下GrabPass{}
两种GrabPass的写法
第一种是直接GrabPass{}的写法,这种写法抓屏的图片就直接存到_GrabTexture这个系统预定义的贴图变量中了,我们就可以直接访问该贴图,但是这种写法会导致每个使用GrabPass的物体进行一次抓屏的操作!(要点这就是为什么多个玻璃材质游戏物体造成高额的性能消耗)
另一种是GrabPass{“TextureName”}的写法,其中TextureName是我们自定义的一个贴图名称,这种写法,unity每帧只会为第一个使用了该名称的物体进行抓屏操作,之后的就可以复用这张贴图了。
然后我就改创建两个shader “Glass Internal”“Glass Vessel”分别用于显示外面的玻璃容器和可放置在玻璃容器里显示的玻璃器材,用两张渲染贴图GrabPass{"_GlassVessel"}、GrabPass{"_GlassInternal"}达成渲染效果。
这样没遮挡部分是显示无问题的,遮挡部分就没有进行绘制。这方面由于作者对shader涉及较浅(没入门)通过编码手段实现不了。
(思路:判断游戏物体是否遮挡然后新绘制贴图,只有有出现遮挡才进行新的贴图抓取)
作者用来其他手段来对遮挡部分进行弥补显示。然后就看优化后的效果。总体来说优化1.8ms