渲染优化方法
渲染面数太多
- 同屏三角面数最多 20 ~ 50万。整个场景面数太多,只会让内存上升,同屏展示的面数太多才会让GPU压力变大。
- 利用好CPU摄像机裁剪,摄像机外的模型尽量不让其进入渲染管线。
- 拆分模型中很大,很长的模型,不然露出一点点就会全部渲染,使摄像机裁剪失效。
- 使用 [[LOD]],使远距离顶点减少。
Batching
合批用于解决DrawCall太多的问题。Drawcall最好保持在100上下。 为了合批模型尽量使用相同的材质。 重复性不高的小模型尽量合并。
- [[SRP Batcher]]
- [[Static Batch]] - 把使用相同材质球的网格合成一个
- [[Dynamic Batch]] - 把使用相同材质球的网格合成一个
- [[GPU Instancing]] - 使用 GPU 一次画出多个网格(要求网格要使用相同的材质)
- [[Manual Combine]] - 手动把使用相同材质球的网格合成一个
Shader太复杂
- 不要用太复杂的shader。
- 片段着色器中计算复杂逻辑会消耗更多的算力,因为片段着色器是针对每个像素进行计算的,而顶点着色器则是针对每个顶点进行计算的,两者的数量有很大的差别,如果我们能将片段着色器的计算量转移到顶点着色器中,就能节省很多GPU消耗。
- 使用复杂的数学函数也会导致性能开销大,比如pow、exp、log、cos、sin、tan等,如果能使用近似公式代替它们,就能为GPU节省很多开销。
- 少用shader变体。
- 控制shader精度。
带宽不足
- 贴图太多,宽带压力大,[[显存]] 压力大。
- 选择合适的贴图压缩格式。
不需要勾 [[显存 read/write]],就不要勾选,不然会占用双倍内存。
CPU
CPU的工作
- 计算哪些物体需要渲染
- 物体必须处于摄像机的可视范围内才会渲染,哪怕只有一部分处于可视范围,仍然需要渲染整个物体
- 不在范围内的则剔除(cull)
- 将Mesh和Material等传送到 [[显存]],以及设置渲染状态,调用图形API等
- SetPassCall:CPU会发出更改指令,为将要渲染的物体设置渲染状态
- SetPass Call 告诉 GPU 使用哪些设置去渲染网格。SetPass Call指令只有在渲染下一个网格的设置和渲染上一个网格的设置不一样时,才会发出
- Draw Call:CPU通过 Draw Call 命令告诉 GPU,就按照上一次 SetPass Call 的渲染设置去渲染指定的网格
CPU约束
- CPU 约束,渲染过程中,CPU 为每一帧渲染准备数据花费的时间太长,导致渲染瓶颈
- 可以牺牲内存用于提高 CPU 性能
CPU优化
减少Unity渲染对象的数量。
- 执行更严格的剔除。
- 使用Occlusion culling (内存+CPU换GPU)
- 减小远平面,这样远处的对象会落到视锥体外面。
- 更精细化的方法,把对象放到不同的层中,执行不同的剔除距离。
Camera.layerCullDistances
- 更精细化的方法,把对象放到不同的层中,执行不同的剔除距离。
- 减小远平面,这样远处的对象会落到视锥体外面。
减少Unity渲染每个对象的时间。
- 使用预烘焙光照贴图和预烘焙阴影。(构建时间+运行时内存+存储空间 换 运行时效率)
- 减少影响对象的per-pixel灯光的数量。
- 不使用实时阴影。
- 优化反射探针的使用。Reflection Probe performance
GPU
GPU的工作
- GPU 按照 CPU 发送到 Command buffer 内的指令顺序处理
- 如果当前指令是 SetPass Call,那么GPU更新渲染状态
- 如果当前指令是 Draw Call,那么GPU根据上一次设置的渲染状态来渲染网格。
GPU约束
- GPU 约束,渲染数量过于膨大,导致 GPU 渲染一帧需要花费的时间过长
- 可以牺牲游戏画质解决渲染瓶颈
GPU优化
- 如果瓶颈在填充率(想要画的像素数超出了GPU的处理能力)
- 透明贴图太多会导致 [[Overdraw]] 问题。
- 优化fragment shader。Shader Performance
- 使用URP的分辨率缩放。
- 如果瓶颈在内存带宽(GPU读写内存的效率超过了GPU的处理能力)
- 一般是因为贴图太多,或者贴图太大。
- 如果模型距离相机的距离有远有近,启用 [[Mipmap]](内存换减少瑕疵)
- 使用合适的压缩格式
- 一般是因为贴图太多,或者贴图太大。
- 如果瓶颈在顶点处理。
- 优化vertex shader。Shader Performance
- 优化几何体,减少定点数,优化UV