前言
最近在看shader入门精要一书,里面大概指出了GPU的优化,入门精要嘛。
翻阅官方文档,和参考一些博文,比较杂,因此,很有必要整理,这篇文章主要是针对渲染相关的,和CS脚本,CPU无关。
正题
U3D开发项目 意味着需要使用多个工具,插件,开源库,第三方库,这个时候优化就显得比较重要了,尤其是在硬件不是特别好的移动端上,因此性能优化就显得格外重要了,有些游戏经常出现闪退,卡死,这些 都和优化有关,可能是内存泄漏,也可能是项目开发时没有按照一定标准。
目前 市面上 也有 一些专门提供游戏优化服务的公司,平台,像UWA,以及Unity自身的技术支持等等…
所以,为了避免 性能问题的发生, 最好就是打好基础,做好铺垫;
光照性能的优化
使用烘培,使用光照贴图
可以把烘焙好的光照信息存储到一张查找纹理中(LUT),使用的时候,只需要对LUT采样得到即可;
优点如下:
- 视觉效果要好得多,因为可以烘焙全局光照,使光照贴图显得更平滑
- 运行速度要快得多(每像素 2 个光源的情况下,速度快 2-3 倍)
边缘光照的优化
无需添加直接照入摄像机的光源来提供边缘光照效果,而是直接在着色器中添加专用的 Rim Lighting 计算
移动端,低端PC
- 避免使用多个像素光照来照射单个对象,应使用光照贴图实现静态对象的光照,而不是每帧计算其光照
- 尽量避免多个光源照射单个对象的情况
- 打标记,是否Important, 非Important会减少很多计算,有些光不需要表现得很好,例如赛车游戏里的车尾灯。
- 使用质量设置 (Quality Settings) 可修改多少个光源用于像素光照以及多少个用于顶点光照
使用批处理
批处理分静态批处理与动态批处理;
- 通过手动方式或使用 Unity 的绘制调用批处理将近处对象组合在一起
- 实现原理,为了减少每一帧需要的draw call 数目
- 避免组合距离足够远而需要受到不同像素光照影响的网格 (网格合并)
- 通常情况下,为渲染组合对象而必须创建的 pass 数为每个单独对象的 pass 数之和,因此进行网格组合并不会获得任何好处。
- 动态合批 顶点属性小于900,动态合批后,物体人可移动。
- 静态核批,只需要勾选物体为static(batching static)即可,需要占用更多的内存来存储合并后的几何结构;不可再进行移动。
- 要求模型使用同一材质球,如果只是纹理不同,可以把纹理合并到更大的纹理中(图集)。
- 对于材质球上的参数,可以使用网格的顶点数据(顶点颜色数据)来存储参数信息;
- 存在基于模型空间下的计算 要使用disableBatching标签;
模型几何体的优化
- 除非必要,否则不要使用三角形
- 尽可能降低 UV贴图 接缝和硬边(双倍顶点)的数量
- 移除不必要的硬边以及纹理衔接
- 模型LOD,U3D 中 使用LODGround
- 遮挡剔除技术 (OC)
角色建模的优化
- 使用单个带蒙皮的网格渲染。
- 使用尽可能少的材质。
- 使用尽可能少的骨骼,桌面游戏应该保持在15~60,移动设备应该保持在30根以下。.
- 移动设备:每个网格300到1500个多边形。
- 桌面游戏:理想范围为1500-4000个多边形。
- 正向动力学和反向动力学保持分离。
内存带宽的优化
- 纹理压缩和 多级渐远纹理 (Mipmap)
- 通过将单独的纹理放入更大的纹理图集,在对象中使用更少的材质。
- 纹理长宽 最好是2的幂次方;
- Mipmap 可以在贴图导入的时候勾选,Generate Mip Maps,Unity会自动生成纹理金字塔,在游戏运行中,就可以根据距离远近,使用高低质量的贴图。
- LOD(细节级别)和每层剔除距离
- 纹理压缩,减低分辨率,使用拉伸,九宫格。
- 在许多游戏中,在不影响玩家体验的情况下快速有效地执行此操作的方法是,相对于大对象,更激进地剔除小对象。例如,可让远处的小岩石和碎片不可见,而大型建筑物仍然保持可见。
将小对象放入单独一层,并使用 Camera.layerCullDistances 脚本函数设置每层剔除距离。
Unity自带了遮挡剔除功能,但是需要设置相机上每层剔除距离。
另外新的遮挡剔除系统 应该会推出了,比之前的oc系统性能要更快,适用更广。
性能分析工具
window
- U3D自带的性能分析工具
- Frame Debug,Profiler
Android
- 高通Adreno
- 英伟达的 NVPerfHUD
可以看到draw call的GPU时间,shader花费的cycle数目
IOS
- PowerVRAM的PVRUniSCo shader分析器
- Xcode中的OpenGL ES Driver Instruments
- 其他第三方 ,UWA, 腾讯的WeTes…等等
着色器代码优化
- 减少可能导致对象多次渲染的因素(例如反射、阴影和每像素光照)。
减少计算复杂度
- 使用Shader的LOD 技术
- 减少if for 语句,尽量不要在frag中计算
- 减少需要处理的片元数目
- 控制绘制顺序
- 警惕透明物体
- 减少实时光照
- 尽可能避免使用类似sin tan pow log 等较为复杂的数学运算,可以使用查找表替换。
- 尽量不要使用discard操作;
Unity官方提供的简单核对表
GPU简单优化核对表
- 在针对 PC 平台进行构建时,保持顶点数量低于 200K 和 3M/帧(具体值取决于目标 GPU)。
- 保持每个场景使用较少的不同材质,并尽可能在不同对象之间共享材质
- 在非移动对象上设置 Static 属性以便允许内部优化,如静态批处理。
- 只有一个(方向性的)pixel light 影响几何体
- 使用烘焙光照而不是动态光照
- 尽可能使用压缩纹理格式,并使用16位纹理而非32位纹理
- 尽可能避免使用雾效
- 如果复杂的静态场景具有大量遮挡,使用遮挡剔除减少可见几何体数量和调用次数,设计关卡时,注意遮挡剔除
- 使用天空盒 伪造远处 几何物体
- 使用像素着色或纹理组合来混合多个纹理而不是使用多pass方法
- 尽可能 使用 half精度变量
- 最大 限度减少在像素着色中使用复杂的数学运算,例如 pow sin,cos
- 每个片元使用更少的纹理