这条优化技巧非常直接,减少texture的数据量,减少分辨率或者降低位数,虽然可能会降低渲染质量。但是通常使用16-bit textures并不会明显的感觉到渲染效果下降。
MipMap技术可以有效减少VRAM和Texture Cache之间来回传递的texture数据量。值得一提的是Scene视图中有Mipmaps Shading Mode,可以为哪些texture用mipmap技术比较合适提供信息。
Unity中有很多种texture的压缩方式, 比如DXT, PVRTC, ETC, and ASTC,每个平台有各自支持的类型。Unity默认会选择综合起来最合适的压缩格式,但是我们也可以手动更改成其他格式,比如改成压缩度更高的,会节约空间或者提高性能。
如果我们想自己撸一套压缩方法,不到迫不得已尽量别这么做,因为需要自己处理多种平台。
可以查看Texture压缩的相关文档https://docs.unity3d.com/Manual/class-TextureImporterOverride.html
尽量减少texture数量是最直接的,但是可能在渲染效果上无法接受。两个小方法:
1.多个功能尽可能使用同一张贴图,但是使用不同的material和shader属性,比如超级马里奥中云朵和灌木丛就长的一样。要注意的是这种方法并不能Draw Call,但是可以降低Memory BandWidth的开销。
2.如果多个贴图经常一起同时使用,考虑打成图集Atlas,这样可以避免在一帧中不断的分别拉取各个texture。
大多数textures从CPU传输到GPU中是发生在初始化的时候,但是也会发生在当需要渲染场景中未存在的texture时。这个加载处理过程是异步的,因此我们会看到一个空的texture直到整个texture为渲染准备好,我们应该避免频繁实时的加载texture。
加载过程中blank texture会十分影响游戏体验,因此应该想办法让texture在真正需要使用前就从硬盘中加载到内存中然后再加载到显存中。
一种比较取巧的方法是在场景中放一个物体,在其上引用texture,并将物体隐藏。运行时当玩家面向这个物体时,即使该物体是隐藏的,其上的texture也将从内存传输到缓存中。将这个物体摆放的位置放在玩家真正需要这张texture渲染之前,比如某个房间内所需的texture可以将隐藏的物体放在去往这个房间的路上。
我们也可以通过代码控制material的texture来完成类似的功能:GetComponent
有少数时候,VRAM可能会被占满,此时如果有texture需要传入,必须要先清理一部分texture。这个过程开销非常非常的大,应该无论如何都要避免。
对于PS4,XBOX这类平台,不存在这种问题,因为他们的CPU和GPU共享内存,这种设计是因为这些平台不存在多个应用同时运行的需求,同一时刻只是有一款游戏在运行。
根据不同的目标平台,texture要采用合适的文件大小和质量,避免超过平台的VRAM上限。
之前已经介绍过,Shadows很容易成为Draw Calls 和 Fill Rate的杀手。要仔细设置Shadow的参数,来达到渲染质量和性能的平衡。Soft Shadows开销比较昂贵, Hard Shadows 开销小一些,No Shadows当然没有开销。Shadow Resolution, Shadow Projection, Shadow Distance, and Shadow Cascades等参数也非常重要,也会影响Shadow的效果和性能。
Shadow Distance是控制实时阴影渲染的距离,因为对于摄像机远处的部分有没有阴影其实意义不大。这个distance参数就是控制我们可视的阴影范围。
Shadow Resolution 和 Shadow Cascades参数如果设置的很高会加大Memory Bandwidth 和 Fill Rate的开销(因为ShadowMap)。更高的阴影质量开销自然会更大,对于ShadowMap,会有锯齿的问题,离摄像机近处的物体阴影效果会比较差。Shadow Cascades就是为了解决这个问题,根据和摄像机距离使用不同质量的ShadowMap。
关于级联阴影的作用可以参考这个官方文章:https://docs.unity3d.com/Manual/shadow-cascades.html
SoftShadow和HardShadow相比,除了Shader更复杂以外没有任何其他开销,所以对于Fill Rate有余地的项目可以享受SoftShadow带来的快感。
Light上的Mask属性可以通过Layer层级来限制那些物体受到该Light影响。这对于降低光照的开销很有效,但是物理系统的优化也经常用到layer mask,一个物体只能属于一个Layer,所以要注意Light光照优化用到mask和物理系统优化用到mask是否有冲突,冲突的话要根据需求抉择,通常mask是以物理系统的优化为先。
烘焙光照和阴影与实时渲染光照和阴影比起来性能提高非常大,缺点是需要额外的存储空间和内存开销以及Memory Bandwidth的消耗。除非游戏中光照渲染用很简单的顶点光或者只有一个方向光,否则我们都应该或多或少的去使用烘焙光照和阴影来提高性能。
有一些参数会对Lightmapping影响比较大,比如resolution分辨率, compression压缩以及是否开启Pre-computed
Realtime GI等,当然场景中有多少个物体需要渲染也会影响很大。 static属性标志为Lightmap Static的会参与Lightmapper的绘制,需要绘制的物体越多,就需要生成更多的LightMaps,所以尽量使用增量式加载,减少每帧需要处理的物体数量。加载场景中的Lightmap可能会造成内存瞬间开销很大,当旧场景卸载后应该立刻释放掉对应的LightMap。
手机设备发展日新月异,所以下边列出的一些优化方法是针对目前设备的,随着硬件发展可能也会出现不适用,开发时每个优化方法都应该根据当前需求进行对应测试。
移动端GPU和PC端GPU还有比较大的差距,对于Alpha Testing开销会很严重,在大多数情况下,用Alpha Blending而不要用Alpha Testing。
移动端的瓶颈经常是Draw Call而不是Fill Rate。应该在项目开发时尽早就使用合并mesh,合批和图集等技术来减少Draw Call,Deferred Rendering也是很不错的技术,因为它和其他移动端需要考虑的问题也比较搭,比如避免使用transparency等,但是Deferred Rendering并不是所有硬件都支持。
这条跟Batching和Atlasing一起使用风味更佳,可以有效减少Draw Call,节约显存VRAM 和 Memory Bandwidth。
OpenGL ES1.1 只能最大支持1024x1024
OpenGLES 2.0 能支持2048x2048
OpenGLES 3.0 能支持4096 x 4096
尽量减少texture的大小,对于不同目标平台使用合适的大小,如果texture过大超过了限制,在加载时也会被CPU降低缩小,这会浪费宝贵的加载时间以及有可能导致渲染效果出现问题,因为这个过程我们并不可控。
2次方的正方形贴图可以被GPU压缩,从而提高性能。
这条其实之前在Shader优化部分已经说过了,尽可能的降低Shader中数据的精度。
Dynamic Graphics这章就结束了,作者说了:这章内容信息很多,需要慢慢消化,也是Unity中最复杂的部分,你要是都弄懂就牛逼了