使用UE4开发VR项目 性能优化思路和方法

2016年12月07日 11:46 0 点赞 0 评论 更新于 2017-05-09 16:38
使用UE4开发VR项目 性能优化思路和方法

目前,VR行业发展迅速,VR性能也在逐步完善。然而,VR仍然存在一些技术瓶颈,其中VR渲染效率和延迟是导致晕动症和人眼疲劳的两个关键问题。本文将通过UE4项目开发中的一些流程和技巧,来优化VR实时渲染效率,提升渲染效率并降低延迟,从而降低晕动症和人眼疲劳的发生几率。本文是《使用UE4开发VR项目 - 性能优化》的第二篇,旨在与读者分享在UE4 VR项目优化中的基本思路、方法和技巧。

一、造成晕动症的原因

造成晕动症的原因众多,包括设计不合理、硬件技术瓶颈、CPU和GPU上的性能问题以及内容优化不合理等。下面将通过一套优化流程,详细阐述VR性能优化的思路和方法。

二、VR优化流程

(一)VR优化考虑的问题

1. HMD(头显)刷新频率

目前,主流VR设备对帧率的限制有所不同,如DK2为75 FPS,CV1和HTC Vive为90 FPS,PS4 VR为120 FPS。

2. VR双屏渲染

简单来说,双屏渲染是将屏幕所见视为一个Mesh的两个Instance,可节省50%以上的效率,也被称为实例化立体渲染(Instanced StereoRendering)。

3. HMD镜透变形(HMD DistortionMask)

这是指HMD镜片导致的图像变形。

4. VR多分辨率渲染(Multi - Resolution Shading)

人眼对屏幕中间视距中心的位置较为敏感,因此可提高屏幕中间的渲染分辨率,降低屏幕周围的渲染分辨率。这种方式能在不影响最终画面显示效果的前提下,提高计算资源的利用率。

5. VR SLI(Nvidia VR优化技术)

该技术允许使用多块显卡协作,开发者可以自由定义每块显卡处理的信息。

6. 场景比例

VR世界中的物体比例必须与现实世界一致,大小不匹配可能会引起眩晕或模拟疾病。

7. 渲染品质压力

渲染品质压力涉及多个方面,如材质复杂度、灯光数量、动态阴影、粒子系统(材质复杂度 + 双目粒子面积 + 粒子数量)、贴图尺寸、双屏可见视野、模型面数等。可通过控制物件和特效数量,使用cull distance volume、instance等方式来控制渲染量。

8. DRAW CALL数量

同屏看到的Actor数量、材质ID数量、每个actor上的feature数量以及灯光投影面积过大等,都可能导致Draw Call数量增加,进而影响CPU逻辑线程和GPU渲染线程的性能。

9. 内存占用率

可通过限制贴图数量和尺寸、提高模型、材质、贴图的复用率、控制物件和特效数量以及UI相关资源数量,来控制内存占用。

10. VR包体大小(VR移动端)

通过提高模型、材质、贴图的复用率,使用压缩技术限制贴图数量和尺寸,必要时取消mipmap等方式,可以控制VR包体大小。

11. 卡顿问题

首次加载地图的卡顿问题与地图大小和资源量有关。若地图较小、资源量不大,可采用预加载的方式;若地图较大、资源量也大,则需考虑将newRenderPipelineState修改为异步来解决。对于加载mipmap的卡顿点,可通过取消TextureStreaming来解决,但取消后会存在显示延迟问题,可通过修改默认的显示顺序(按摄像机距离排序显示)来解决。

(二)VR测试环境准备

VR项目可参考《基于UE4的VR项目基础环境配置和Motion Controller控制配置》(http://gad.qq.com/article/detail/7167914)进行基础环境配置。同时,需创建测试环境,暂停游戏,单独运行游戏并进行多次测试,确保帧数不封顶,关闭垂直同步。

(三)找到受到限制的瓶颈

目前,在VR内容中,CPU逻辑线程出现问题的比例相对较小。若CPU逻辑线程出现问题,通常是实现和设计存在缺陷,或者代码编写有误。大多数问题出现在GPU渲染线程上。找到瓶颈的步骤如下:

  1. 判断线程问题:首先判断是CPU逻辑线程问题还是GPU渲染线程问题。
  2. 使用命令查看数据:使用控制台命令Stat fps查看FPS。若FPS满足要求,则无需进一步优化;若不满足,则使用Stat Unit命令查看更详细的数据,以帮助判断瓶颈所在。
  3. 调整HMD SP:HMD SP(屏幕比例)默认值为120%,调整该值会使画面清晰度改变。在渲染压力大且无法进一步优化时,可降低HMD SP值,使画面变糊以提升帧数。若调整HMD SP后帧数有提升,则可确认是GPU渲染线程瓶颈。
  4. 分析Stat Unit数据:Stat Unit命令会显示三个有用的数据,即GAME(游戏逻辑线程这一帧所耗费的时间)、DROW(GPU渲染线程所耗费的时间)、Gpu(GPU耗费的时间)。通过查看这些数据,可分析各模块每一帧的耗时情况。若Game的毫秒数最高,需检查是否限制了帧数上限;若Game和Frame耗时相同,则可能不是游戏主线程瓶颈,很可能是限帧导致的。
  5. 调整渲染质量设置:通过关闭一些功能,观察效率上的区别。例如,可调整一些可调的show flag(屏蔽渲染查找问题),如开/关屏幕反射、AO、AA、bloom、延迟灯光、灯光类型、动态阴影、GI、后期、环境反射、折射、贴花、半透明、tessellation等。

(四)GPU渲染线程分析

1. 验证GPU瓶颈

若遇到GPU瓶颈,最快的验证方法是改变分辨率。降低分辨率若能大幅度提高帧数,则可确定是GPU瓶颈;若影响不大,则可能是面数太多。

2. 使用ProfileGPU命令

ProfileGPU命令可快速确定多个通道的GPU消耗,快捷键为Ctrl + Shift +,。使用r.ProfileGPU.ShowUI可对UI进行抑制。建议在单独游戏(Standalone)运行环境中使用该命令,避免在编辑器中运行,因为编辑器的开关会产生渲染开销,导致渲染数据产生误差。

3. 关注关键数据项

值得注意的数据项包括Base Pass、Deferred Decals、Lighting、SSR(环境反射)、Translucency(半透明)、Postprocessing(后期处理效果)、Particle(粒子)等。当Base Pass数据较高时,可使用命令行打开Early Z Pass来降低Base Pass,但会少量增加DRAW CALL。

4. 检查影响GPU效率的内容

检查分辨率、HMD SP、投影贴图大小等是否超标。通过ViewMode检查三角面密度,当三角面密度太高(三角面小于2 * 2像素,常见于远处物体)时容易出现问题。还需分别查看三角面、顶点、灯光数量、阴影设置、Actor数量等,检查LOD、关闭Shadew、控制灯光屏幕面积等。同时,要注意顶点数量、点动画的Shader处理复杂度、Tessellation复杂度、多重UV、过多的SG等问题,查看Staticmesh Editor里点和面数的差别是否过大,以及点是否合并、场景GPU粒子模拟数量是否过多等。

5. 优化材质

材质复杂度对GPU效率影响较大,Quality、Switch、Sin、Pow、Cos、Divide、Noise等节点很耗费资源。可减少材质Shader的指令数量,减少Texture Sample的数量,如将经常使用到同一物体上的图案合在一张贴图上,去掉对质量影响较小的贴图(如Specular、AO等)。尽量使用单向量计算,避免多向量计算。

6. 遮挡的culling计算

使用预算可见性剔除遮挡的对象,以减少不必要的渲染。

7. 延迟灯光和后期处理

使用lightingfunction、IE、接受投影、区域光、复杂shadingmodes时,延迟灯光的开销会增大。若反射SSR有问题,可关闭它。另外,后期AO也很耗费资源。

(五)CPU逻辑线程分析

1. 引起Draw Call数量增多的原因

  • 同屏Actor过多、材质复杂性过高,可通过合并Actor、降低材质复杂度来解决。
  • 材质ID太多,可将同一材质合并成一个物体,重用材质贴图。
  • 每个Actor上的Feature太多(主要是增加投影属性和Custom depth属性)。
  • 过多灯光投影,需检查投影计算来自哪些物体被投影。

2. 解决Mesh Draw call问题

可通过检查静态模型统计器来解决Mesh Draw call问题。Actor设置Feature中的custom depth会增加DrawCall数量,可通过检查工具设置Showflag,使用Property matrix来过滤。还可使用排除法,隐藏各种元素,查找Draw Call数量过多的因素,如隐藏HUD(HUD占用很多性能,可使用Showflag.slate 1)。

3. 灯光优化

UE4使用延迟灯光,灯光优化比前向渲染方便。最快速有效的方法是使用静态光源,若使用动态光源,需减小Lighting Cull、半径、衰减、Cone大小角度等,尽量减少光源间的重叠。投影的开销主要来自被投影的Mesh面数、灯光数量和投影物体数量,可关闭投影的灯光、减小范围或张角、减面并添加LOD。使用r.Shadow.MaxResolution命令可查看阴影分辨率数据。

4. DrawCall优化

打开Statistics统计面板,按使用次数排序Actor,查找使用次数最多的MESH的ID。若ID为负数,则可进行优化。例如,若有60个MESH资源,其中一半使用同一资源,可考虑使用Merge Actors(融合Actor)来降低ID数量,优先减少使用频率最高的Mesh ID,该操作可减少50%以上的DrawCall(此步骤建议最后考虑)。

5. 减少光源投影

Staionary灯光和动态灯光应尽量少,且能不投影的尽量不投影,减少光源间的Overlaid(覆盖)。使用控制台命令r.VisualizeOccludedPrimitives 1可判断场景中哪些遮挡掉的物体被渲染,若Actor在遮挡后面但未被绿色框标记,可能是边界(Bounds)设置太大,需注意非Root Motion的动画。

6. 粒子优化

使用StatParticle命令,对占屏幕面积较大、靠视点较近、半透明较多、材质复杂、边界盒较大、粒子数量多的粒子进行集中优化。对于离视点较远的粒子,可使用LOD减少粒子绘制。在GPU进行立体渲染时,离视点近的粒子容易出现视差错误,可将粒子做成实体模型来避免。

7. 后期优化

可采用以下后期优化组合:

  • Post processingsetting:设置Scene color、Fringe intensity 0、Grain intensity 0、Color gradingintersity 0。
  • Bloom setting:设置LPV 0、Ambient occlusion 0、DOF Method Gaussian 0、Motion blur all 0。
  • AA设置为FXAA,SSR设置为0,Max roughness设置为0.01,Ambient cubemap设置为0。

最后,可使用Profiler将数据捕获到磁盘上进行分析。

(六)可能遇到的问题和优化方法

1. 常见问题原因

常见问题的原因包括测试环境不合适(如灯光未构建)、双目渲染Actor太多、多材质ID、模型面数太多且未使用LOD、灯光类型使用无规划、大面积使用透明等。

2. VR & VFX

在VR项目中,多数情况下可使用静态网格体替代2D粒子模拟VFX(如爆炸或烟雾拖尾)。近场特效或离摄像机非常近的特效使用静态网格体粒子组成效果更佳。

3. VR和透明度

在VR项目中,透明度的渲染开销极大,大于其带来的效果增益。可使用DitherTemporalAA材质函数解决这一问题,该函数可使材质拥有外观上的透明度,并避免常见透明度问题(如自我排序)。

4. 多边形减面

在VR游戏中,由于玩家观察的自由度更高,执行减面操作可能导致玩家看到不应该看到的物体,因此一般不建议进行此操作。

5. 阴影投影

可去掉大部分动态着色器(DynamicShader),用BP控制角色脚步离地面远近来缩放脚下阴影片面大小。减少Reflection Capture的使用并尽量避免重叠,关掉场景SSR,用材质模拟SSR效果,打开SM联级动态阴影。

6. 创造性作假

可采用远处mattinpaiting、投影面片渲染在贴图上的方法。使用PrecomputedVisibilityVolume(预遮挡计算)可在遮挡较多的地方大幅度提高渲染效率,使用CullDistanceVolume(裁剪体积)可根据Mesh在屏幕上所占像素尺寸裁剪模型。

7. 内存分配

可使用stat scenerendering命令分析内存分配情况。

作者信息

孟子菇凉

孟子菇凉

共发布了 3994 篇文章