最新文章
泰课在线 | 微信拼团成功后如何获取课程?
08-09 17:57
Unity教程 | 使用ARKit为iOS开发AR应用
07-31 17:23
Unity Pro专业版7折订阅四选一工具包之VR开发与艺术设计
07-28 11:47
网友使用虚幻UE4实现CAVE 多通道立体渲染的沉浸式环境
07-27 11:57
VR晕动症调查:未来5年内大部分VR晕动症将得到解决
07-27 11:26
AMD CEO:未来3-5年最重要 希望5年达1亿VR用户
07-27 10:44
12个Unity5中优化VR应用技巧
VR应用相较于非VR应用,对计算能力的要求更高,因此性能优化是一项至关重要的任务。如果目标平台是像Gear VR这样的手机设备,优化工作就显得尤为重要。
关键性能指标
在优化之前,我们需要了解一些关键的性能指标:
- 绘制调用次数:每只眼睛的绘制调用次数应控制在50次以内。在Unity 5中,更精确的说法是SetPass Calls。
- 顶点数和面数:场景中的顶点数应少于50K - 100K,面数也应少于50K - 100K。
优化技巧
静态批处理
场景中通常存在大量的静态几何体,如墙体、椅子、灯光以及从不移动的网格等。在编辑器中,我们可以将这些对象标记为静态对象。若要进行光照贴图烘焙,还需确保将其标记为静态贴图。通过将对象标记为可组合成一个网格的静态对象,避免每个对象单独引发一次绘制调用。
静态批处理有一个重要要求:所有对象必须使用相同的材质。例如,若静态墙使用木头材质,静态椅子使用铁材质,那么所有墙会被批量处理为一次绘制调用,而椅子则作为单独的网格进行另外的绘制调用。
纹理集
如前文所述,每个材质会引发一次绘制调用。从直觉上看,木门和铁椅子由于纹理不同,需要使用不同的材质。然而,如果使用相同的着色器,我们就可以利用纹理集为它们创建共用的材质。纹理集是一个包含所有小纹理的大纹理,我们可以使用一个材质加载一个纹理,而不是使用多个材质进行多次加载。每个对象可以对应纹理集中不同坐标的一个纹理。
你可以在绘制管线中手动生成纹理集,但Juan Sebastian的Pro Draw Call Optimizer工具非常实用,它不仅可以生成纹理集,而且在替换新对象时不会混淆资源。
动态批处理
非静态对象可以通过动态批处理合并为一个单独的绘制调用。虽然这个过程会大量占用CPU,并且每帧都需要进行计算,但它仍然是一种有效的优化方式。不过,动态批处理只对使用相同材质且顶点数少于900的对象有效。我们可以使用纹理集为所有动态对象创建一个材质,从而实现简单的动态批处理。
LODs(多细节层次)
LOD组是提升性能的简便方法。我们可以使用具有多个LOD的资源,对于离相机较远的对象,使用低分辨率的几何体进行渲染。Unity能够根据相机的距离自动在各个LOD之间进行转换。
填充率、过度绘制及裁剪
这是一个需要重点关注的话题。为了减少过度绘制,我们应先绘制最远的对象,然后依次绘制更近的对象。在平均分辨率为1080P的PC显示器上,这个问题并不明显,但对于具有极高分辨率的VR和手机设备来说,问题就比较严重了。大量的过度绘制会产生大量像素,从而影响填充率。纹理填充率是限制GPU性能的关键因素。
针对这个问题,我们可以采用遮挡剔除和视锥体剔除的方法。视锥体剔除是指不渲染位于相机视锥体外的对象,即不渲染看不到的对象;遮挡剔除则是剔除被其他对象挡住的对象,例如门后的房间可以被整体剔除。默认情况下,遮挡剔除是针对整个场景的,如果关卡设计合理,甚至可以剔除游戏中的整个关卡。此外,LOD组也可以对离场景较远的对象进行裁剪,进一步降低填充率。
关卡设计
如果游戏涉及玩家从一个房间移动到另一个房间,一种简单的做法是将整个游戏放在一个关卡中,但这种方法的缺点是会消耗大量内存。因为即使每个房间中的对象和材质不可见,它们仍然会被加载到内存中。为了改善性能,我们可以将每个房间放置在单独的关卡中,并通过代码智能地异步加载关卡。
异步加载
在玩家即将进入下一个房间之前,我们应该提前加载下一个关卡。需要注意的是,不要使用Application.LoadLevel()进行同步加载,因为这种方式会导致游戏在加载时挂起,而头盔的跟踪是实时的,这会让玩家产生眩晕感,严重影响游戏体验。
我们可以使用Application.LoadLevelAsync()来加载关卡,你可以在Oculus Mobile SDK BlockSplosion例子的StartupSample.cs中找到具体的使用方法。
光照烘焙
为了减少绘制调用,我们应关闭实时阴影。因为接受动态阴影的对象无法进行批处理,会导致大量的绘制调用。
在PC机上,使用单个实时方向光就可以实现出色的动态阴影效果,大多数现代PC都能够提供逼真的逐像素阴影。但在移动平台上,我们需要使用光照烘焙来替代实时阴影,通过高分辨率的光照烘焙结合软硬阴影,可以实现类似的效果。
阴影处理
为了在手机上获得高性能的体验,对于3D对象的阴影处理可以采用传统技巧。我们可以在对象下方放置一个带有模糊阴影纹理的2D四边形,以此来模拟半真实的阴影。
需要注意的是,不要尝试使用阴影缓冲,预处理光照环境并在角色下方使用模糊阴影纹理处理方法是更好的选择。例如,我们无法在手机上实现像《GTA V》在高性能PC机上使用的实时动态阴影效果,而可以借鉴2002年《GTA Vice City》在PlayStation 2上使用阴影斑点来提供阴影效果的幻觉。
Light Probes(光照探针)
在使用烘焙光照时,静态对象的效果较好,但动态对象可能会存在一些问题。我们可以使用光照探针来模拟简单的动态光照。
光照探针是预先烘焙好的立方贴图,它存储了场景中多个点的直接、间接甚至自发光的信息。当动态对象移动时,它会在光照探测器附近进行插值,以获取近似某个点的光照。这是一种在动态对象上模拟实时光照的简便方法,无需使用成本高昂的实时光照。Unity的文档详细解释了光照探针的放置方法。
避免使用透明和多材质的对象
像玻璃这种使用透明着色器的对象会消耗大量性能。为了使墙壁看起来更逼真,常见的做法是使用一个带有灰尘或锈斑纹理的透明材质,再加上另一个单独的基本漫射材质。然而,多材质的alpha混合会消耗大量性能,因为每个材质都会增加一次绘制调用。需要注意的是,多个纹理本身并不会有问题,真正耗费性能的是使用多个材质。我们可以使用一个材质结合着色器来实现多纹理的alpha混合,而不是使用多个单独的材质。
蒙皮网格渲染器
蒙皮网格渲染器常用于角色身上,它带有动画关节,可以通过物理(布娃娃)变形或自定义动画(走、跳等)来实现逼真的网格变形。
但遗憾的是,蒙皮网格渲染器不支持批处理。对于每只眼睛,场景中的每个角色都会进行多次绘制调用,目前还没有有效的解决方案。