如何有效提升性能Unity Gear VR游戏性能

  VR应用比非VR应用需要更强的计算性能优化是一个很重要的任务。若目标平台是像GearVR这样的手机设备优化就更重要了。

  以下是一些应该试着了解的性能指标:

  場景中顶点数少于50K~100K 且面数少于50~100K

  下面是一些简单的技巧,用于满足上述要求:

  静态批处理场景中可能存在大量的静态几何体例如墙体,椅子灯光和从不移动的网格。在编辑器中将它们标记为静态对象为烘焙光照贴图,请确保将其标记为静态贴图不要让烸个对象都会导致一次绘制调用,而是把对象标记为可被组合成一个网格的静态对象

  静态批处理有个关键要求:所有对象必须使用楿同的材质。若静态墙带有木头材质静态椅子带有铁材质,所有墙会被批量处理为一次绘制调用椅子作为单独网格进行另外的绘制调鼡。

  纹理集如之前所说每个材质引发一次绘制调用。直觉可能是木门和铁椅子需要使用不同的材质由于它们的纹理不同。然而若使用相同的着色器,就可以用纹理集为它们创建共用的材质纹理集就是一个包含所有小纹理的大纹理。我们可以使用一个材质加载一個纹理而非使用多个材质加载多次。每个对象可以对应到纹理集中不同坐标的一个纹理

  你可以在绘制管线中手动生成纹理集,但昰Juan Sebastian的Pro Draw Call Optimizer工具非常有用它可以生成纹理集,并且在替换新对象时不会搞混资源

  动态批处理非静态对象可以动态批处理为一个单独的绘淛调用。我曾注意到该过程大量占用CPU且每帧都在计算但这是一个很好的优化。这只对使用相同材质且顶点数少于900的对象有效使用纹理集为所有的动态对象创建一个材质,就可以进行简单的动态批处理啦

  LODs(多细节层次)LOD组是改善性能的简便方法。使用有多个LOD的资源并鼡低分辨率的几何体渲染离相机远的对象。Unity可以自动随着相机临近在各个LOD间转换

  填充率,过度绘制及裁剪这是个值得关注的话题減少过度绘制,最远的对象最先绘制随后上面依次绘制更近的对象。这个在平均分辨率为1080P的PC显示器上没什么问题但对于有极高分辨率嘚VR和手机设备来说问题就比较严重。大量的过度绘制组成了大量像素从而影响填充率纹理填充率是限制GPU性能的关键。

  一些解决方案提供了遮挡剔除和视锥体剔除视锥体剔除是指不渲染位于相机视锥体外的对象。不渲染看不到的对象!遮挡剔除是剔除被其它对象挡住的對象比如,门后的房间可以被整体剔除默认情况下,遮挡剔除是针对整个场景的如果关卡设计得当甚至可以让你剔除游戏中的整个關卡。

  LOD组当然也可以裁剪离场景很远的对象进一步使填充率最小化。

  关卡设计若游戏涉及到玩家从一个房间移到另一个房间簡单的解决方法是一个关卡包含整个游戏。缺点在于内存的消耗尽管每个房间中的各对象和材质都不可见,但其仍会被加载到内存中將每个房间放置于单独的关卡中,在代码中智能的异步加载关卡可以改善性能

  异步加载在玩家即将进入下个房间之前,加载下一个關卡不要使用Application.LoadLevel()同步加载,因为加载时会导致游戏挂起由于头盔的跟踪是实时的,这会导致眩晕对玩家来说体验太糟糕。

  光照烘焙关掉实时阴影!接受动态阴影的对象不会被批处理这会导致严重的绘制调用。

  在PC机上使用单个实时方向光就可以实现很好的动态陰影效果。对于大多数现代的PC都可以提供逼真的逐像素阴影然而在移动平台,你需要烘焙光照而不是实时阴影以高分辨率烘焙光照结匼软硬阴影实现类似的效果。

  阴影尤其是为了高性能的手机体验对于3D对象的阴影处理要使用传统技巧。可以通过在对象下放置一个簡单的带有模糊阴影纹理的2D四边形模拟半真实的阴影

  VR小提示:不要尝试使用阴影缓冲。预处理光照环境并在角色下方使用老套的模糊阴影纹理处理方法

  Light Probes(光照探针)当使用烘培光照时,静态对象效果不错但动态对象还有不妥对于动态对象可以使用光照探针来模拟簡单的动态光照。

  光照探针是烘焙好的立方贴图存储了场景中多个点直接、间接甚至自发光的信息。当动态对象移动时它在光照探测器附近进行插值获取近似某个点的光照。这是一种在动态对象上模拟实时光照的简便办法而不用成本高昂的实时光照。

  Unity的文档解释了光照探针要如何放置

  避免使用透明和多个材质的对象类似玻璃这种使用透明着色器的对象很消耗性能。使墙壁看起来更逼真嘚常见做法是用一个带有灰尘或锈斑纹理的透明材质,加上另一个单独的基本漫射材质多材质的alpha混合是很消耗性能的,每个材质都会增加一次绘制调用!但是请注意:多个纹理并没有问题使用多个材质才耗费性能。使用一个材质结合着色器来实现多纹理的alpha混合而非使鼡多个单独材质。

  蒙皮网格渲染器蒙皮网格渲染器常用于角色身上它带有动画关节,可以使用物理(布娃娃)变或自定义动画(走跳等)來实现逼真的网格变形。

  坏消息是:蒙皮网格渲染器不支持批处理对于每只眼睛,场景中各角色都会进行多次绘制调用目前还没什么解决方案。


楼主发言:1次 发图:0张 | 添加到话题 |

马上注册结交更多好友,享用哽多功能让你轻松玩转社区。

您需要 才可以下载或查看没有帐号?

关于项目创建与Demo导入 本系列教程将介绍如何用Unity为Gear VR开发一个360度照片查看器在开始用Unity为Gear VR开发应用前,需要完成Unity和Oculus的整合并导入学习用的Demo文件。在这部分教程中你将学习以下步骤:

·更新版本设定,使用安卓平台
·导入360度照片查看器的demo文件 Demo文件里包括了这个应用里所有需要的元素。按以下步骤处理教程的Demo文件:


A.点击以下链接下载项目资源:

B.将文件解压到电脑上的目录中

在这个目录中,有一个Unity文件包里面包括了搭建应用所需的所有模型、材质、贴图和脚本。

C.在Importing package对话框點击Import按钮。把文件包导入到项目中可能需要一些时间


这个文件包中的OVR目标中包含了一些预制件和脚本,用来为Unity场景和组建提供VR支持还囿一个Plugins目录,包含一些插件用来支持VR架构与操作系统(Windows,Mac OSXAndroid)的交流。 D.文件包导入完成后找到Project 窗口(Windows>Project)。这里可以看到项目的目录结構以及所有资源在Assets目录中,检查文件

在本系列教程中,你将使用Assets和ProjectSettings这两个目录Assets目录包括了所有你为这个项目创建和导入的内容,而Project Settings目录为你的Unity项目设定特定的参数

上一篇中我们讨论了GearVR设备的特点還有创建高效的GearVR游戏的方法这一篇,我将聚焦于调试在这些设备上性能不够好的Unity程序的方法

在调试Unity性能时,第一个要做的就是在Player Settings打开Enable Internal Profiler選项开启之后,每几秒钟都会输出许多重要的帧率统计信息到logcat控制台上这会让你清楚的知道你的每帧时间都干嘛去了。

为了说明调试性能一般步骤我们来看一下从一个相当复杂场景中得到的采样数据,该游戏运行在Note 4 GearVR设备上

上面的数据告诉我们,平均每帧耗时是22ms大約是45FPS,比我们60FPS的目标还差得远还可以看出,这个场景对CPU来说负担很重——22ms中有16.3ms花费在CPU上我们花费了5ms在驱动上(“cpu-ogles-drv”),这意味着我们鉯较慢的方式在使用驱动潜在的问题就很清楚了:每一帧有174Draw Calls,严重超标(我们的目标是100)除此之外,我们使用了比预期更多的多边形这个视图并没有告诉我们GPU上发生了什么,但是他告诉我们只看CPU的话45FPS需要提高,并且应该专注于降低draw call

这个数据还显示,在帧耗时上有規则的峰值(最长帧耗时为49.8ms)为了理解这些峰值是哪来的,下一步要连接到Unity Profile看下它的输出。

不出所料上面的图显示了规则的峰值。茬非峰值期间我们的渲染时间和上面报告的数值相近,并且对最终的帧耗时影响不大

Profiler中显示,峰值的时候Gfx.WaitForPresent这个函数耗时最多。奇怪嘚是我们实际的渲染时间再峰值的那一帧并没有显著增加。究竟是发生了什么

看起来是因为WaitForPresent(及其兄弟版本,Overhead)重复出现从而破坏叻我们的帧率。实际上它并不执行什么神秘的工作。相反WaitForPresent记录了渲染管线停止的时间数量。

要理解渲染管线一个好的方法是想象一個火车站。火车以固定的时间离开——每16.6毫秒我们说火车在一个时刻只有一辆,现在有很多人排队准备上车只要队伍中的每个人在火車离开之前都能上得去,那么每16毫秒都可以出发把他们运往目的地但是,如果有一个人动作太慢没上去(可能被他自己的鞋带绊倒了)他就错过了这趟火车,他将坐在那里等待另一个16毫秒下一趟火车过来哪怕他仅仅慢了1毫秒,错过这趟车都意味着他不得不等待下一次機会

在渲染管线中,火车就相当于是前缓冲区(正在显示的内容)与后缓冲区(要显示的下一帧内容)交换这通常发生在前一帧完成掃描显示结束的时候。假设GPU可以在一段合理的时间内,执行所有缓冲的渲染指令这里是每16毫秒前后缓冲交换一次。要维持在60FPS的刷新率程序就必须在在16毫秒之内结束所有的工作。当CPU花费太长的时间来完成一帧即使是只晚了1ms,就错过了缓冲区的交换时间下一帧的扫描輸出就开始使用上一阵的数据,然后CPU不得不停下来等到下一次交换结束。用我们上面的比喻来说火车就是缓冲区,CPU发送的每帧的指令僦是这些乘客

在这个例子中,我们清楚的看到由于我们的帧率不够平稳,所以不能使得渲染管线更加稳定解决WaitForPresent的办法就是在Profiler中忽略咜,然后集中在优化其他每个地方在这个例子中,就是降低场景中的Draw Calls

Unity Profiler对于挖掘运行时的各类信息非常有用,包括内存使用Draw Calls,纹理分配以及音频开销对于雅阁的性能调试来说,在Player Preferences里面关掉多线程渲染是个好主意这将会使得渲染变慢很多,但是能让你清楚的知道每帧嘚时间都去哪了当你优化完成的时候,记得再把多线程渲染打开

除了Draw call Batching,其他常见的性能开销包括overdraw(通常是大型透明对象或者遮挡剔除鈈足导致的)蒙皮动画,物理开销以及垃圾回收(通常是内存泄露或者反复回收引起的)。在你优化场景的时候要注意这些方面同樣要记住,显示最终的VR输出包括warping和TimeWarp开销,每帧都会消耗大约2ms

OVRMonitor是Oculus Mobile SDK中最近发布的一个新工具。它帮助开发者理解渲染管线工作的方式并且識别管线停止它还可以利用无线从GearVR设备上把低分辨率无压缩的视频以流的形式获取回来,这点对可用性测试很有用

OVRMonitor目前正在开发中,泹是这个早期版本仍然可以用来可视化GearVR程序的图形管线下面是一张截图,是使用该工具审查上述场景时的截图

黄色条代表的是VSync间隔,指的是一帧的输出已经结束了窗口上方的图片是渲染好的该帧截图。图片中间红色的条显示的是TimeWarp线程可以看到它和实际的游戏是平行運行的。下面的蓝条指的是CPU和GPU的负载看起来是不变的(这个例子中,4个CPU同时运行)

这个截图实际上显示了Unity Profiler中WaitForPresent峰值中的一个。时间线中間的那一帧开始的太晚以至于到下一个竖线的地方还没结束,结果造成CPU阻塞了完整的一帧(缺乏场景截图的那一帧WarpSwapInternal线程占据了16.25ms)。

OVRMonitor可鉯帮助我们搞清楚渲染管线从一帧到另一帧发生了什么它可以用于使用最新SDK编译的任何GearVR程序。更多信息请参考SdkRoot/Tools/OVRMonitor中的文档更多文档和特性很快就来。

这里有一些我们使用过的或者从其他开发者那里听过的性能技巧这些并不能保证对所有VR应用有效,但是它们可能给你一些關于潜在解决方案的想法

  • 最后渲染大型的不透明Mesh。尝试把天空盒放到几何体+1渲染队列让它在所有不透明物体渲染之后绘制。这可能导致被天空盒遮挡的许多像素被深度测试丢弃因此节省你的时间。这个技巧也适用于地面和其他静态不透明物体它们占据很多像素并且佷可能大部分被遮挡了。

  • 动态改变CPU/GPU节流限制你可以在任何时候改变节流限制。如果游戏中大部分都可以以相对较低的设置运行只有一兩个特殊场景不行的话,考虑只在这些场景中加快CPU/GPU对于简单的场景来说,也可以降低一个或多个处理器的速度延长电池寿命并减少发熱。例如场景加载的时候可以把GPU设置成0.

  • 不经常的更新渲染目标。如果你把场景渲染到辅助的纹理上可以尝试使用比主场景较低频率渲染。例如一个立体渲染的镜子每帧只对一个眼睛刷新一次。这有效的把镜子的帧率降低到30FPS但是因为每帧都有新数据,对于轻微的移动看起来也是可以的

  • 降低渲染分辨率。通过降低一点视觉质量通常可以显著提高游戏性能,例如稍微的减小每只眼睛渲染目标的大小OVRManager.virtualTextureScale昰0.0到1.0之间的数值,控制了渲染输出的尺寸在老旧设备上稍微降低分辨率是支持较慢硬件的简单办法。

  • 压缩纹理所有GearVr设备支持ASTC压缩格式,这种格式能明显的减小纹理尺寸需要注意的是,在本文写作时Unity4.6期望ASTC压缩是和OpenGL ES3.0一起使用的。如果你使用在OpenGL ES2.0的情况下使用ASTC你的纹理将茬加载时解压,这可能延长程序启动时间对于OpenGL ES2.0来说ETC1是一个低质量但是通用的方案。

  • 使用纹理图集如上所述,可以被许多Mesh共享访问的大紋理将会更高效要避免过多小的单个纹理。

我要回帖

更多关于 提升性能 的文章

 

随机推荐