Chapter16 渲染优化技术——Shader入门精要学习笔记

Chapter16 渲染优化技术

一、移动平台的特点

  • GPU架构与PC端有很大的不同,移动设备上专注于尽可能使用更小的带宽和功能
  • 需要针对不同的芯片平台,进行更有针对性的优化,尤其是在安卓平台上

移除隐藏的表面

  • 减少overdraw(即一个像素被绘制多次)
  • PowerVR芯片:基于瓦片的延迟渲染 TBDR架构:把所有渲染图元装进一个个瓦片中,再由硬件找到可见的片元,只有可见的片元才会执行片元着色器
  • Adreno(高通)或Mali(ARM):Early-Z或相似的技术,进行低精密度的深度检测,来剔除不需要的片元

二、影响性能的因素

  • 游戏主要需要使用的计算资源:CPU和GPU------互相合作,让游戏可以在预期的帧率分辨率下工作,CPU负责保证帧率,GPU负责分辨率

造成性能瓶颈的原因

CPU

  • 过多的Draw Call ------ CPU需要多次改变渲染设置,很耗时
  • 复杂的脚本或者物理模拟

GPU

  • 顶点处理
    • 过多的顶点
    • 过多的逐顶点计算
  • 片元处理
    • 过多的片元(可能是分辨率造成的,也可能是overdraw引起)
    • 过多的逐片元计算
  • 带宽
    • 使用了尺寸很大且未压缩的纹理
    • 分辨率过高的帧缓存

三、Unity中渲染分析工具

1.渲染统计窗口 Rendering Statistics Window

  • Game窗口 -> Stats
  • 每帧的时间和FPS数目:在Graphics右侧
  • Batches:一帧中需要进行的批处理数目
  • Saved by batching:合并的批处理数目(表明了批处理节省了多少draw call)
  • Tris 和 Verts:需要绘制的三角形顶点数目
  • Screen:屏幕大小以及占内存大小
  • SetPass:渲染使用的Pass数量(可能会造成CPU渲染瓶颈)
  • Visible skinned meshes:渲染的蒙皮网格数
  • Animations:播放的动画数目

2.性能分析器(Profiler)的渲染区域

  • Window -> Analysis-> Profiler,rendering区域

3.帧调试器 Frame Debugger

  • Window -> Analysis-> Frame Debugger
  • 帧调试器的调试面板上显示了渲染这一帧的所有渲染事件
  • 本例中渲染数目为13个,其中包含9个Draw Call

4.其他性能分析工具

  • 高通的Adreno分析工具:可以对不同的测试机进行详细的性能分析
  • 英伟达NVPerHUD:可以得到几乎所有需要的性能分析数据
  • PowerVRAM的 PVRUniSCo shder分析器
  • 等等

四、减少Draw Call的数目

  • 批处理:减少每一帧需要的draw call数目,
  • 相同材质的物体可以一起处理,它们之间的不同仅仅再与顶点数据的差别
  • 两种批处理方式
    • 动态批处理:
      • 由Unity自动完成,物体可以移动
      • 限制很多
    • 静态批处理:
      • 自由度高,限制少
      • 可能会占用更多的内存,物体不可以移动

1.动态批处理

  • 原理:每一帧把可以进行批处理的模型网格进行合并,再把合并后的模型数据传给GPU,然后使用同一个材质进行渲染
  • 限制:(随着Unity版本更新会有不同)
    • 进行动态批处理的网格的顶点属性规模有限制
    • 需要保证物体指向光照纹理中同一个位置
    • 多Pass的Shader会中断动态批处理------有时需要额外的Pass来添加更多的光照效果

2.静态批处理

  • 原理:只在运行开始阶段,把需要批处理的模型合并到一个新的网格结构中(不能在运行时刻移动),但只需要进行一次合并,所以比动态处理更高效
  • 性能瓶颈:当在批处理前一些物体就共享了网格,在内存中每个物体都会对应一个该网格的复制品,即一个网格会变成多个网格发给GPU
  • 如果场景中包含了平行光以外的光源,并在Shader中定义了额外的Pass 来处理,这些Pass不会被批处理的
  • 使用:勾选物体的Static

3.共享材质

  • 使用同一个材质(不是同一个Shader)才可以使用批处理
  • 如果想要微调一些参数:使用网格的顶点数据(最常见的是顶点颜色数据)来存储这些参数
  • 如果要脚本访问共享数据,应该是 Renderer.sharedMaterial 而不是 Renderer.material

4.批处理注意事项

  • 尽可能选择静态批处理,但小心内存消耗
  • 小心动态批处理的限制
  • 游戏中的小道具可以使用动态批处理
  • 包含动画的物体,如果有不动的部分可以标为static
  • Shader中如果存在基于模型空间下的坐标运算时,不能使用批处理 DisableBatching标签来让Shader不会被批处理
  • 半透明渲染的物体时,由于严格的渲染顺序,批处理可能不成功

五、减少需要处理的顶点数目

1.优化几何体

  • 减少三角形面片数量:去除对模型没有影响或肉眼难以察觉的顶点,降低模型复杂度
  • 避免硬边和纹理分离: 移除不必要的硬边和纹理衔接,减少顶点拆分,降低顶点数量

2.模型的LOD技术 Level of Detail

  • 原理:当一个物体原理摄像机时,LOD减少模型上的面片数量,从而提高性能
  • Unity实现:使用 LOD Group 组件为对象设置不同 LOD 等级的模型,Unity 会自动选择合适的模型进行渲染

3.遮挡剔除技术 Occlusion culling

  • 用来消除那些在其他物件后面看不到的物件
  • 同时减少CPU和GPU的符合,CPU可以提交更少的Draw Call,GPU处理的顶点和片元也更少了
  • 实现可以看unity手册相关内容

六、减少需要处理的片元数目

  • 这部分优化重点在减少overdraw

1.控制绘制顺序

由于深度测试,物体都是从前往后绘制的,很大程度上减少了overdraw

  • 在Unity中,渲染队列数目小于2500("Background""Geometry"和"AlphaTest")的对象都是不透明的,从后往前绘制;但"Transparent""Overlay"等物体是从后往前绘制的
  • 利用渲染队列: 将物体分配到合适的渲染队列,确保不透明物体从前向后渲染,避免半透明物体造成 overdraw
  • 调整渲染队列顺序 : 根据物体在场景中的位置和重要性,调整渲染队列的顺序,例如先渲染主要角色,再渲染敌方角色和场景物体

2.警惕透明物体

对于半透明物体来说,由于没有开启深度写入,从后往前渲染------几乎一定会造成overdraw

  • 减少大面积半透明物体: 减少场景中大面积半透明物体的数量,例如 GUI 元素,避免造成过多的 overdraw
  • 优化半透明物体渲染: 在移动平台上,尽量减少透明度测试的使用,改为使用透明度混合,并注意透明物体的绘制顺序

3.减少实时光照和阴影

对于逐像素的光源来说,被这些光源照亮的物体需要再被渲染一次,还不能使用批处理操作(额外的Pass无法批处理)

  • 使用烘焙光照 : 将静态物体的光照信息烘焙到光照纹理中,避免实时计算,降低 CPU 和 GPU 负担
  • LUT 查找纹理:将光源方向、视角方向、法线方向等参数存储在LUT中。在运行时对LUT采样即可得到光照模型(更复杂的BRDF模型)。主角用更大分辨率的LUT,NPC用小的LUT可以优化性能
  • 限制实时光源数量: 减少场景中点光源的数量,避免过多的逐像素光照计算,并使用逐顶点光照代替逐像素光照
  • 优化实时阴影: 尽量减少实时阴影的使用,对静态物体使用烘焙阴影,对动态物体使用合适的实时阴影技术

七、节省带宽

1.减少纹理大小

纹理长宽比最好是正方形,且长宽值为2的整数幂

  • 纹理图集:将多个纹理合并成一张大图,减少Draw Call 和纹理切换次数
  • 多级渐远纹理技术mipmapping :纹理勾选Advanced后,可以勾选 Generate Mip Maps 来生成纹理金字塔,动态选择
  • 纹理压缩:将纹理压缩成更小的格式,例如 PVRITC、DXT、ATC 等,节省存储空间和带宽

2.利用分辨率缩放

  • 根据设备性能调整屏幕分辨率,例如在低性能设备上降低分辨率,在高性能设备上提高分辨率
  • 使用 Screen.SetResolution 函数设置屏幕分辨率

八、减少技术复杂度

1.Shader 的 LOD 技术

只有 Shader 的 LOD 值小于某个设定值,该 Shader 才会被使用,超过设定值的 Shader 将不会被渲染,可以在 SubShader 中设置 LOD 值,或使用 Shader.maximumLOD 或 Shader.globalMaximumLOD 设置允许的最大 LOD 值

2.代码优化

  • 尽可能使用低精度浮点值进行运算:例如 half、fixed 等,减少计算时间和内存占用。
  • 尽量减少从顶点着色器传递给后续阶段的插值变量数量,例如将多个纹理坐标打包到一个 float4 变量中。
  • 避免使用复杂的数学函数:例如 sin、tan、pow、log 等,可以使用查找表替代。
  • 分支循环: 尽量避免使用分支语句和循环语句,这些语句会影响 GPU 并行效率。
  • discard 操作: 避免使用 discard 操作,因为它会影响 GPU 的一些优化策略。
  • 全屏后处理: 尽量避免使用全屏的屏幕后处理效果,例如 Bloom、热扰动等,可以使用低精度运算或查找表优化。
  • 合并特效: 将多个屏幕后处理特效合并到一个 Shader 中,减少绘制次数和计算量。
  • 硬件缩放: 根据设备性能调整游戏渲染效果,例如在低性能设备上关闭部分特效,在高性能设备上开启更多特效。
相关推荐
xiaoyalian4 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
Red Red5 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
贰十六6 小时前
笔记:Centos Nginx Jdk Mysql OpenOffce KkFile Minio安装部署
笔记·nginx·centos
知兀6 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
Natural_yz7 小时前
大数据学习17之Spark-Core
大数据·学习·spark
qq_172805597 小时前
RUST学习教程-安装教程
开发语言·学习·rust·安装
一只小小汤圆7 小时前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
醉陌离7 小时前
渗透测试笔记——shodan(4)
笔记
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
LateBloomer7778 小时前
FreeRTOS——信号量
笔记·stm32·学习·freertos