谈场景性能优化

谈场景性能优化

优化系列传送门:场景优化篇 特效优化篇 动作优化篇
场景优化篇之james讲课 场景优化篇之光照贴图优化

前言:之前整理过一篇,是James的课后感,不过当时听课只是记录了关键词;二来最近发现还是有些新项目的同学或者新来的同学连一些最基本的概念都没有理解,也不想以后各个项目都讲一遍,所以觉得需要展开细说一下,于是有了这篇。

有关于美术优化的知识以及相应的配图,感谢@James还有@武松童鞋。
有些配图可能也是从网上找的,侵删

问题

  • 场景最核心的问题有仨,其实这基本也是渲染效率的最核心问题,第一是DrawCall,第二是同屏顶点数,第三是填充率。以下依次分解 。
  • 当然还有内存的优化和Shader的优化,会在最后补充。

解决方案

Drawcall及其优化

  • DrawCall的定义?
    GPU的一次渲染调用叫DrawCall。
  • 什么叫一次渲染?
    一次渲染所有要准备的东西是a)Mesh数据,b)贴图纹理,c)shader,所以简单说凡是相同纹理并且相同shader的Mesh都可以一次绘制出来到屏幕上。通俗的说也就是一个材质球对应一个DrawCall,在最好的情况下。
  • 为什么说是最好情况?

    • 通常引擎都有一个静态合并的策略,也就是将相同材质球的mesh在游戏运行之前合并成一个Mesh进行渲染,于是含有动画的物件不能参与合并没有勾选static batching的物件不能参与合并。还有一点,除了原本的贴图之外,渲染还会引用lightmap,也就是说引用不同ligtmap的材质求不能合并
    • 还有一个就是渲染引擎底层的限制或者优化,比如顶点缓冲区有限(Unity默认Mesh的最大顶点数是65535个),顶点数量超过最大限制将不能合并成一个大Mesh,还有可能考虑多线程渲染的问题,一个顶点数并不高的DrawCall会被拆分多个,具体原因不明。(Unity5之后发现的,不过不知道原因,有知道底层的望告知~~)
  • 怎么优化?
    说了这么多,优化策略就显而易见了。

    • 尽量使用相同的shader

    • 尽量减少场景中使用的贴图数量,可以通过合贴图来做

    • 尽量减少LightMap张数(当然这个跟以前写过关于Lightmap烘焙效果的原则违背,做游戏当然是要权衡和取舍啊)

同屏顶点数极其优化

这概念没啥好解释的,就是同屏能看到的顶点的数量。就现在的GPU来说(最关键是要兼容最低配。。。),推荐的移动平台的同屏顶点数在10w以下注意,这个是所有模块的顶点数,包括人物,场景,UI,特效。

虽说道理很简单,但是怎么优化顶点数,一直听到的的回答是,减不了啊,不摆东西太空旷了,很丑啊。
其实如果主观上认定减少顶点数的必要性,还是可以从这几个方面去尝试的。(都是听各个大佬说的,很靠美术经验啊,感谢大佬)。以下列出的肯定不全(继续奋斗.jpg),反正大家在制作的时候有这根弦就很好了。

  • 从设计上避免,或者遵从设计来投机取巧

    • 比如视角因素(比如暗黑视角和wow视角),不同视角下对于顶点的分配肯定不一样,原则就是尽量把顶点分给视觉中心,这一点跟我之前说Lightmap面积的分配是一个道理,游戏制作永远都是性价比
      img
  • 远近的区分

    • 对于锁定视角或者视角受限的游戏来说肯定有远近主次之分,可以类似如下
      img
  • 基本减面

    • 没啥可说的,就是减面,但是还是有一些技巧,比如尽量保持基本结构的不变,减少不必要细节
      img

    • 同时我还想借用两句话,第一,勿以善小而不为,勿以点少而不减,第二,不积跬步无以至千里,不减一点无以到十万
      img

填充率的优化

大体上来说,场景的填充率开销并不是特别明显,填充率杀手主要是特效(特效优化详见特效优化篇)。但场景里还是有一部分问题要注意。

  • 场景特效的使用
    没什么太多说的,尽量不用或者少用,如果真要用遵守特效的相关优化
  • 透明shader的使用
    冰啊,玻璃啊,水啊,凡是透明的东西,在屏幕上的渲染都是至少两次,要注意,不是不让用,尽量减少面积,不滥用
  • 透贴的使用
    透贴,也就是AlphaTest会导致GPU的early-z culling这个底层优化走不过去,简单点说就是在一定程度上,透贴比透明费,当然有一些细节问题,比如透明是不写深度的,会导致有些复杂的结构渲染错误,比如繁盛的树叶。优化办法有俩:

    • 如果单层mesh,可以适当透明代替透贴

    • 用顶点数换镂空区域,就是适当的把镂空的边用顶点抠出来
      img

内存及包体的优化

两个字,“复用”!
还是解释一下概念,内存优化指的是尽量减少游戏运行时同时在内存中资源的数量以及大小。包体优化指的是最后apk包的大小。方法有二:

  • 按照风格(或者根据项目实际调整)安排贴图,尽量类似风格的场景能共用贴图,比如全局共用(花,草,天空),风格共用(秋天,武侠,西式哥特)

  • 用“破碎+组合”的方式代替制作不同的物件Mesh(配图不是很贴切,不过找不到更好的)
    img

  • 带A通道的图与不带A通道的图分开,如下利用率太低,可以考虑重新合图
    img
  • Mesh减少顶点数,Mesh如果不需要colors,uv2,uv3等等记得删掉
    img

  • 千万不要勾Read/Write

shader的优化

  • 场景shader理论上来说越简单越好,有一个点特别要注意,就是同一个材质求上引用的贴图数量最好不要超过4张,当引用贴图过多或者显存不足会导致效率下降
  • 还有一些常规的shader优化,属于技术的范畴就不在这说了

技术优化办法的优缺点

有不少美术认为好像技术用一个特别牛逼的优化技术就能把性能起死回生,就像他们觉得用一个牛逼的shader就能使美术效果叼炸天一样。预防针还是要打的,要有这么好的事情,我相信就不会有那么多的引擎上层(引擎底层的优化就像UE比Unity的效率高,这个不是我们能左右的)的程序员各种苦口婆心的解释和催促优化了。

  • LOD
    lod的优点就是能减少同屏顶点数,但带来的是美术建模的工作量和内存开销,其他技术行为都比较成熟了
  • MipMap
    mipmap的优点是能减少显存和带宽压力,也能使锯齿得到缓解,但是带来的还是内存压力,某些情况下可以酌情使用
  • 遮挡剔除
    遮挡剔除可以减少顶点数,但是是用cpu提前检查的开销换来的,在非自由视角,并且没有太多小街小巷的情况下,带来的开销不见的比直接渲染低

更高级的美术优化技巧

  • UV的理解与复用
    那会James过来讲课,我听到楼梯的不同做法,以及瓦片,地板的重复度优化,我当时就惊了。还能这么干!
    img
  • 适当的使用贴片方法来解耦污渍与原贴图,这样也可以提高复用度

  • 尽量保持物件贴图比例一致,也就是piexl->texel一致,这样在调整放缩时,不至于一个被压缩的厉害,一个被拉伸的模糊

结语

之前涉及美术相关的东西,一直不敢写这个(在此再次感谢james和武松),想着单写一些技术思路没什么意义,主要没有可操作性,于是作罢。现在终于把动作、特效、场景三部曲都写完了,虽然特效那个还没配图。撒花。