以下整理主要摘自《Unity Shader 入门精要》
另外的参考资料:http://wetest.qq.com/lab/view/315.html?from=content_zhihu
由图可知CPU、GPU、带宽、内存都可能出现瓶颈。
优化的目标其实是往一个目标上靠,cpu的DrawCall命令刚刚好能被GPU消化,不要让CPU等待(带宽限制),也不要让GPU闲置。如果即使做到了这个,应用帧率还是上不去,那么就只能去削减场景,做有损优化了。
下面将分别列举优化方法。
CPU优化
- 批处理减少draw call
- 1)动态:满足条件的模型纹理会自动批处理
- 顶点属性规模<900.需注意如果使用了位置、发现、纹理坐标的话,模型顶点数不超过300.
- 使用光照纹理(lightmap)的话注意物体指向光照纹理的同一个位置
- 多Pass会中断批处理
- 2)静态:适用不移动的模型
- 实现:勾上物体上的static
- 会占用更多的内存
- 3)共享材质
- 无论是动态还是静态都需要共享相同的材质。如果两个材质间只有纹理不同,则可以将纹理合并到更大的纹理中,再使用不同的采样坐标即可。
- 4)注意事项:
- 尽可能选择静态批处理,但要小心内存消耗。
- 包含动画的物体无法使用静态批处理,但其中不动的部分可以标识为static
- 由于批处理需要把多个模型变换到世界空间再合并,故如果shader中包含了模型空间计算下坐标计算,会得到错误结果。解决方案:使用shader中DisableBatching标签,强制不批处理.
- 1)动态:满足条件的模型纹理会自动批处理
- 批处理减少draw call
GPU优化
- 减少顶点数
- 1) 优化几何体
- 减少三角面 优化网格 等
- 2) 使用模型LOD
- 允许对象渐远时,减少面片数量
- Unity中使用LOD Group组件来构建一个LOD
- Unity自带LOD教程 http://www.cnblogs.com/MrZivChu/p/lod.html
- 另一个团队开源的LOD方案:http://gulu-dev.com/post/2015-07-19-umetalod
- 上面的都好麻烦 新插件发现:SimpleLOD http://blog.sina.com.cn/s/blog_155a1f2470102w9tg.html
- 3) 使用遮挡剔除技术
- Unity Occlusion Culling 遮挡剔除研究 http://blog.csdn.net/cartzhang/article/details/52684127 (这一篇展示了剔除的效果)
- 中文翻译版官方教程: http://blog.csdn.net/levine2008/article/details/51951616
- 1) 优化几何体
- 减少片元数: 重点减少overdraw(一个像素被绘制多次)
- 1) 控制绘制顺序
若有已知的前后,将靠近摄像机的Queue值设小些,而天空盒子之类的永远会在所有物体后面,可以设置为Geometry+1,就会减少overdraw - 2) 警惕透明物体
如果场景中有很多层半透对象(即使面积不大),或者是透明的粒子效果,在移动设备上会产生大量的overdraw。 - 3) 减少实时光照
可以使用烘焙技术,将光照提前烘焙到一张光照纹理(lightmap)中,然后在运行时根据纹理采样。在移动平台上,一个物体使用的逐像素光源数应该<1。
- 1) 控制绘制顺序
- 减少计算复杂度
- 1)使用Shader的LOD技术
设置Shader.maximumLOD来过滤大于此值的Shader 从而使用更小LOD的Subshader或者不渲染此物 - 2)代码优化
- 尽可能使用低精度的浮点值进行运算。
float 用于存储比如顶点坐标等,half适用于标量、纹理坐标等,fixed适用于大多数颜色变量、归一化后的方向矢量。但要避免对低精度变量进行频繁的swizzle操作(e.g. color.xwxw),还要避免不同精度转换。 - 对绝大多数GPU来说,在使用插值寄存器把数据从顶点着色器传递给下一个阶段时,应该使用尽可能少的差值变量(比如4个half3,变成3个half4)
- 尽可能不要使用全屏的屏幕后处理效果。没办法的话,尽量使用低精度运算,并尽量合并到一个Shader中
- 尽可能使用低精度的浮点值进行运算。
- 1)使用Shader的LOD技术
- 减少顶点数
节省内存带宽
- 减少纹理大小
尽可能使用多级渐远纹理技术(mipmapping 设置图在下方)和纹理压缩 - 利用分辨率缩放
过高分辨率会造成性能下降。
参考:http://www.xuanyusong.com/archives/3205
- 减少纹理大小