Unity中的渲染优化

以下整理主要摘自《Unity Shader 入门精要》
另外的参考资料:http://wetest.qq.com/lab/view/315.html?from=content_zhihu

image
由图可知CPU、GPU、带宽、内存都可能出现瓶颈。

优化的目标其实是往一个目标上靠,cpu的DrawCall命令刚刚好能被GPU消化,不要让CPU等待(带宽限制),也不要让GPU闲置。如果即使做到了这个,应用帧率还是上不去,那么就只能去削减场景,做有损优化了。

下面将分别列举优化方法。

  1. CPU优化

    • 批处理减少draw call
      • 1)动态:满足条件的模型纹理会自动批处理
        • 顶点属性规模<900.需注意如果使用了位置、发现、纹理坐标的话,模型顶点数不超过300.
        • 使用光照纹理(lightmap)的话注意物体指向光照纹理的同一个位置
        • 多Pass会中断批处理
      • 2)静态:适用不移动的模型
        • 实现:勾上物体上的static
        • 会占用更多的内存
      • 3)共享材质
        • 无论是动态还是静态都需要共享相同的材质。如果两个材质间只有纹理不同,则可以将纹理合并到更大的纹理中,再使用不同的采样坐标即可。
      • 4)注意事项:
        • 尽可能选择静态批处理,但要小心内存消耗。
        • 包含动画的物体无法使用静态批处理,但其中不动的部分可以标识为static
        • 由于批处理需要把多个模型变换到世界空间再合并,故如果shader中包含了模型空间计算下坐标计算,会得到错误结果。解决方案:使用shader中DisableBatching标签,强制不批处理.
  2. GPU优化

    • 减少顶点数
    • 减少片元数: 重点减少overdraw(一个像素被绘制多次)
      • 1) 控制绘制顺序
        若有已知的前后,将靠近摄像机的Queue值设小些,而天空盒子之类的永远会在所有物体后面,可以设置为Geometry+1,就会减少overdraw
      • 2) 警惕透明物体
        如果场景中有很多层半透对象(即使面积不大),或者是透明的粒子效果,在移动设备上会产生大量的overdraw。
      • 3) 减少实时光照
        可以使用烘焙技术,将光照提前烘焙到一张光照纹理(lightmap)中,然后在运行时根据纹理采样。在移动平台上,一个物体使用的逐像素光源数应该<1。
    • 减少计算复杂度
      • 1)使用Shader的LOD技术
        设置Shader.maximumLOD来过滤大于此值的Shader 从而使用更小LOD的Subshader或者不渲染此物
      • 2)代码优化
        • 尽可能使用低精度的浮点值进行运算。
          float 用于存储比如顶点坐标等,half适用于标量、纹理坐标等,fixed适用于大多数颜色变量、归一化后的方向矢量。但要避免对低精度变量进行频繁的swizzle操作(e.g. color.xwxw),还要避免不同精度转换。
        • 对绝大多数GPU来说,在使用插值寄存器把数据从顶点着色器传递给下一个阶段时,应该使用尽可能少的差值变量(比如4个half3,变成3个half4)
        • 尽可能不要使用全屏的屏幕后处理效果。没办法的话,尽量使用低精度运算,并尽量合并到一个Shader中
  3. 节省内存带宽

    • 减少纹理大小
      尽可能使用多级渐远纹理技术(mipmapping 设置图在下方)和纹理压缩
    • 利用分辨率缩放
      过高分辨率会造成性能下降。
      参考:http://www.xuanyusong.com/archives/3205