谈谈VR游戏中的性能优化
VR游戏与传统游戏相比,主要在玩法设计、输入方式和性能压力这三个方面存在差异。本文将着重探讨VR游戏中的性能优化问题。
为什么VR游戏的性能压力很大?
VR游戏性能压力大主要受三个因素影响,影响权重由高到低依次为高帧率、高分辨率和画两遍。
高帧率
不同设备的帧率要求不同,如DK2为75Hz,最新的CV1和HTC Vive为90Hz,PS4 VR为120Hz。与之对比,PC游戏通常为60Hz,主机游戏为30Hz,由此可见VR游戏在帧率方面的压力巨大。鉴于帧率如此之高,每一帧即便有2ms的提升也意义重大。以75Hz为例,每帧时间为13.33ms,2ms的占比高达15%。
高分辨率
不同设备的分辨率也有所不同,DK2为1920 1080,最新的CV1和HTC Vive为2160 1200,PS4 VR为1920 1080。除了账面分辨率,实际渲染时为抵消透镜畸变带来的分辨率损失,需要进行超采样。具体而言,DK2为135%,CV1和HTC Vive都为140%。以DK2的数据1920 1080 @75Hz为例,每秒的像素处理量为283 millions,是一般主机游戏的4倍。而最新硬件的这一数据更是提升至457 millions。
画两遍
VR游戏需要为左右眼分别绘制画面,主要有以下两种绘制方法:
- 方法一:依次画两遍场景:SetTexture、SetTransforms、SetViewport、切换RenderState、DrawCall等操作均需翻倍。
- 方法二:依次画两遍物体:相较于方法一有所节省,但DrawCall依旧翻倍。
关于像素处理部分
从上述数据可以看出,VR游戏的性能压力主要集中在像素处理方面,因此与像素处理相关的部分需要特别关注:
- 光影计算方案的选择:采用空间换时间的策略尤为重要,应尽量使用light map、静态AO、环境反射贴图等方案,而dynamic shadow在任何时候都应尽量节省使用。
- 后期处理:移除不必要的效果,如DOF、Motion Blur、Lens Flare等效果本就不适合VR游戏;对于SSR、SSAO等效果,尽量使用前面提到的静态方案来替代;由于已经有Super Sampling,AA也可以不用。
- 注意OverDraw的问题:典型的如范围巨大的透明面片特效应谨慎使用,避免过多叠加。
- Shader复杂度问题:在UE4的viewmode中,有一个专门用于查看shader复杂度的模式。一般来说,当出现粉色和白色时,说明shader过于复杂,需要进行修正。
- early z culling:虽然延迟渲染已成为各大引擎的标配,很多人认为对于延迟渲染来说,early z culling没有必要,因为生成GBuffer之后相当于已经进行了像素级别的culling,而且多一个pass提前写深度往往得不偿失。但实际上,early z culling针对延迟渲染的受益部分主要在GBuffer的生成阶段。在传统游戏中,这部分相对于lighting计算阶段的开销不大,因此往往被忽略。但在VR游戏中,由于像素处理量巨大,这部分的优化提升效果相当明显。当然,实际情况需要根据游戏场景进行详尽测试。
关于画两遍
由于批次翻倍加上面数翻倍,因此在VR游戏中,优化批次和面数比传统游戏更为重要。
- 静态场景的批次优化:针对UE4,我们可以开发专门的扩展工具来合并场景中相同物体的批次,而无需美术人员对已完成的场景进行返工。
- 动态批次优化:可以采用instance的思想合并数量众多但体积较小的物体,如FPS游戏中的子弹。
- 面数优化:在UE4中,面数的消耗主要体现在生成GBuffer的Base pass阶段,因此需要善用统计工具对游戏场景进行定时定性分析。此外,除了美术提供的静态场景和角色,还需要关注自动生成的内容,如tessellation。例如,UE4中Ribbon特效的tessellation默认步长为15uu,而在某些游戏中,Ribbon特效可达30000uu,如果不改变默认值,一条拖尾可生成4000面,同屏50条拖尾就可能导致绝大部分GPU性能下降。因此,在特定游戏中,应善用不同工具从多种角度分析问题。
其他优化方法
前面介绍的优化方法是针对VR游戏的特点重点强调的,其他优化方法同样适用,总结如下:
- 对表现效果妥协:例如,很多手机平台的游戏角色可能没有normal,同时可以降低贴图精度和模型精度。
- 对制作流程和制作效率妥协:例如,在开发无尽之剑XboxOne版时,UI直接调用d3d API进行绘制。
- 对开发效率妥协:注意shader中的数据类型和顶点的数据格式,能用16位浮点就不要用32位浮点。
- 根据游戏类型具体分析:如果确定场景中物件都必须渲染,则可以关闭Ocullusion Culling,因为在这种情况下不需要预计算遮挡剔除关系。
- 注意CPU、GPU的同步点和线程之间的同步点:这些同步点多发生在竞争统一资源时,如主线程和第三方库的线程使用同一个内存分配器。
- 善用第三方库:例如,如果小内存分配频繁且自己懒得编写内存库,可以使用tcmalloc、nedmalloc等第三方库。
- 多用LOD:不仅包括贴图mipmap、模型LOD等,还包括逻辑层面的LOD,如特效分层LOD。
- 设置不同的更新频率:为不同的Actor、Component和系统设置不同的更新频率。
- 使用多线程和SIMD加速:提高游戏性能。
- 避免使用基于win32 API的高级函数:例如memeset,因为它是单字节填充,可用汇编进行优化,以提高效率(成熟引擎通常已经进行了优化)。
其他方案
除了上述方法,业界还有一些全新的优化方案:
- 多/双显卡渲染:DX12支持显卡混搭,可以将render task绑定到任意GPU上;Nvidia的SLI和ATI的CrossFire可用于非DX12的情况,其原理是一块显卡渲染左眼,另一块显卡渲染右眼,要求两块显卡型号一致,实测效果较好。
- StencilMesh的思想:同样是一种culling方法,在UE4中的实现叫做HMD Distortion Mask,可节省周围四角区域的像素计算。
- Instanced stereo Rendering:核心思想是一次提交绘制双份几何体,draw call不需要翻倍。UE4的4.11 preview版本已经推出了第一个版本的实现。
- Multi-Resolution:由于人眼对中心区域像素更敏感,因此可以保持中心区域分辨率并降低边缘区域分辨率,在降低整体分辨率的同时尽可能减少对效果的影响。这种方法可以节省25% - 50%的像素处理量。
补充和总结
在进行VR游戏性能优化之前,有两点需要特别强调:
- 稳定测试环境:关闭PC上其他3D程序,关闭垂直同步,确保每次采样点以及采样上下文完全一致,不要以编辑器模式启动游戏。
- 量化观测数据:在完全稳定的测试环境下,同一游戏前后两次测试的性能观测数据可能会有轻微浮动,因此不能仅凭直觉判断,而应捕获精确的数据进行分析。
此外,优化是一个长期迭代的过程,需要做好记录。在与美术人员产生分歧时,应尽量用数据说话。
来源:腾讯网