比起那些普通的应用,VR应用所需的计算性能要求要比非VR的大很多,所以它让优化成为了一项重要工作;但如果你的目标是类似Gear VR这种移动设备,那么要求会更高。
以下是一些基本的标杆:
单眼50个绘制调用(Draw Call),Unity5更加精准地称之为口令设置程序调用(Setpass Calls)。
少于50000-100000个顶点数以及50000-100000个多边形数量。
下面是一些简单的技巧,用于满足上述要求:
1、静态批处理(Static Batching)
在一个场景里,可能有一堆静态几何图形,比如墙、椅子、灯光和各种静止网格(Mesh),你可以在编辑器里把它们标成静态,确保将他们标记成静态光源映射来得到烘焙好的光照贴图纹理。被标记成静态的物品会被组成一个网格,而非每绘制一次物品就产生调用。
但静态批处理有一个关键的要求:所有物品必须都有同样的材质。如果你有木头材质的静态墙壁和一个钢铁材质的静态椅子,所有墙壁会被组合成一个网格,消耗一个绘制调用,而椅子则也会有一个网格,占用另一个绘制调用。
2、纹理集合(Texture Atlasing)
如上文所提及,每个不同材质都会至少导致一个新的绘制调用,你可能会以为一个木头门和铁椅子必须使用不同的材质,毕竟它们使用了不同的纹理。但是如果它们能使用同样的着色器,你可以使用纹理集合来创建一个材质,同时兼容这两个物体。一个纹理集合其实就是一个大纹理贴图,里面包含了各种各样的小纹理。你可以让某个材质加载几个纹理而非让一堆材质加载一堆纹理,每个物体都能通过不同的纹理映射来加载这个纹理集合上的不同坐标位置的一小片纹理。你也可以在绘制管线中手动生成纹理集,Juan Sebastian的Pro Draw Call Optimizer工具非常有用,它可以生成纹理集,并且在替换新对象时不会搞混资源。
3、动态批处理(Dynamic Batching)
移动非静态物品也能被动态批处理为单一绘制调用,这对于CPU来说开销较大,每帧都经过计算,但就优化最终结果来说还是不错的。不过要注意的是这只对低于900个顶点并有着同样材质的物体才有用,使用纹理集合来为你的动态物体创建一个单一材质,然后你就能得到简单的动态批处理了。
4、多细节层次(Level Of Details)
多细节层次组也是一个提升表现的简单方式。使用多个细节层次的Assets并让离镜头远的物体采取低细节的几何图形进行渲染,Unity能自动在摄像头和物体之间的距离发生改变时过渡到不同的细节层次。
5、填充率,重复绘制,过滤剔除(Fillrate,Overdraw and Culling)
降低重复绘制,不要让远处物体的像素被绘制了后,近处覆盖在这个像素的物体上面时又绘制了一次。对于平时在PC上倒不是无所谓,但对于移动VR,这也是性能开销啊。大量的重复绘制和高分辨率影响了你的填充率,而纹理填充率也是GPU的限制之一。
目前,解决方式包括遮挡剔除(Occlusion Culling)和层次视锥剔除(Frustum Culling)。层次视锥剔除能将摄像机视野锥体外的东西都剔除掉;而遮挡剔除则是不渲染那些被挡住的物体,比如门后的房间,沙发后的桌子什么的。默认状态下遮挡剔除能搞定你的整个当前场景,但如果关卡设计得当,整个关卡都能被剔除掉,多细节层次组也能剔除掉离摄像头太远的物体,以进一步降低填充率。
6、关卡设计(Level Design)
如果你的游戏是让玩家从一个房间(地区)到另一个房间(地区),那基本的方式就是让整个游戏只在一个关卡中,但这样会导致过高的内存开销,每一个房间内的物体和材质都会被加载到内存里,即便在当前场景中是不可见的。所以,要将房间放到不同的关卡里,通过代码设计来分开加载。
7、异步加载(Asynchronous Loading)
当玩家快要接近到加载下一关的关门时,不要同时使用Application.LoadLevel(),这会导致游戏暂停卡顿,即便头部跟踪只停了一小会儿,也会让玩家非常的不适。因此,要采取Application.LoadLevelAsync(),关于范例你可以查看Oculus Mobile SDK下的BlockSplosion样品,在StartupSample.cs里。
8、光照烘焙(Baked Lighting)
关闭实时阴影,得到实时阴影的物体将无法被批处理,导致大量的额外绘制调用的开销。在PC上,你仅能通过单一的即时方向光来得到不错的动态阴影,但在移动端请用烘焙好的光照,不要用实时阴影。
9、阴影(Shadows)
尤其对于移动体验来说,请对立体物品的阴影使用以前的那些小技巧,半真实的阴影可以通过在物体下面增加一个平面模糊灰色图形来达到。比如,千万不要以为用这种高端电脑才能搞定GTA V的实时动态阴影。
但你也可以用类似这种:下图来自2002年的GTA罪恶城市,只是在人物下面增加了一个模糊的小圆球而已。
10、光照探针(Light probes)
当使用烘焙好的光线后,那些动态物品看起来违和感很高,而静态物品就非常好。解决的办法之一就是通过光照探针来模拟动态光源。光照探针是烘焙好的立方体贴图,在场景中的各个点上存储直接、间接乃至发散的光线。当动态物体移动时,它会提取最近的几个光照探针的样品来模拟在那个部位的光线,这是模拟真实光线而无需依赖昂贵的实时光线的方式。
11、避免透明和多材质物品
使用透明着色器的物品,比如玻璃,窗户等都非常昂贵。还有一些专门让物品看起来更真实的方式,比如在墙壁前增加一层锈色或灰尘透明的材质等等,这类多材质Alpha融合都非常昂贵,每个材质都会增加一个绘制调用。但是,多纹理就无所谓了,所以你应该只用一个材质,并用一个可以通过Alpha来融合多个纹理的着色器。
12、蒙皮网格渲染器(Skinned mesh renderers)
蒙皮网格渲染器在渲染那些有动画部件的角色时比较常用,能通过物理或定制的动画来达到真实的网格变形。不幸的是,蒙皮网格渲染器不会被整合进批处理中去,每个场景里的角色都会导致单眼增加几个绘制调用。