UPL9-11——降低 Shader 填充率压力
UPL9-11——降低 Shader 填充率压力
回顾:关于填充率的优化思路
具体可见:UPL8——影响 GPU 性能的主要因素 的 填充率部分
降低要处理的像素(片元)数量
降低分辨率
动态分辨率(Dynamic Resolution Scaling)
基本原理:
在 GPU 压力大时,降低渲染分辨率,然后再放大到屏幕分辨率输出
在 GPU 空闲时,提高渲染分辨率,获得更清晰的画面
目标是保持 稳定帧率,URP 项目中有动态分辨率功能开关注视点渲染(Foveated Rendering)
基本原理:
人眼的视觉分辨率,中央注视点区域最清晰,周边区域分辨率敏感度低
在中央区域渲染高分辨率,在边缘区域渲染低分辨率,从而减少像素处理量
一般 VR 项目中会使用
一般 VR 设备会提供对应功能,通过设备 API 开启降低项目分辨率
基于目标设备,合理设定项目目标分辨率
减少或优化屏幕后处理效果的使用
在 1/2 或 1/4 分辨率下渲染,或直接不使用
降低抗锯齿采样次数或关闭
4×MSAA ——> 2×MSAA 或关闭
减少单个像素(片元)计算量
控制 Shader Pass 数量
能合并的效果放在一个 Pass,避免片元被重复算
减少半透明的使用
减少层数,必要时用 透明测试(AlphaTest)
可见:US3S3L4——透明度测试合理使用光照模式
少用逐像素实时光照
减少纹理采样次数
合并贴图、使用 Mipmap
避免无效像素(片元)计算
减少 OverDraw
优化UI系统
减少叠层,避免全屏大半透明面板,合并图集减少 DrawCall
剔除不可见对象
用 Occlusion Culling 和 视锥剔除
禁用不需要的特性
降低填充率压力的主要思路就是
- 减少被着色的像素数
- 减少每个像素的着色成本
而着色器中的透明度、深度写入、透明度测试、透明度混合等特性
都会增加每个像素的着色成本,会进行更多的计算和逻辑处理
因此,少一个特性就等于少一段像素级逻辑,可以有效降低片元着色器工作量
比如我们可以通过渲染标签、渲染状态禁用一些处理
-
不投射阴影
1
Tags { "ForceNoShadowCasting" = "True" }
-
关闭深度缓冲
1
ZWrite Off // 不写入深度缓冲
等等
使用基于着色器的 LOD
我们可以强制 Unity 使用更简单的着色器来渲染远端对象,这是一种节省填充率的有效方法
特别是将游戏部署到多个平台或者需要支持多种硬件功能时
Shader LOD 就是给 Shader 提供多档复杂度版本
引擎根据全局或局部 Shader 的 maximumLOD 参数选择合适的 SubShader
从而减少片元计算开销,从而降低填充率压力
举例:
1 | Shader "Custom/LODExample" |
在 C# 中:
1 | //全局修改: |
使用光照剔除
光照相关的计算是着色器处理中的高开销项,灯光组件上有 Culling Mask (剔除遮罩,内置渲染管线) 或 Rendering Layer Mask (渲染图层蒙版,SRP管线)
他们的作用都是决定场景中哪些层级的对象会受到该光源影响,我们可以通过该参数让某些层不被对应光源影响
通过它们来限制光源影响范围,从而减少着色器中光照相关的计算

谨慎使用实时阴影
实时阴影的渲染过程消耗是比较大的
因为在渲染底层,会渲染阴影贴图,片元阶段还会进行阴影贴图采样,进行过滤处理等等
因此尽量避免使用实时阴影,可以有效减少渲染和采样计算压力。
可以采用以下方式去优化:
- 烘焙光照阴影
- 降低阴影质量的方式
使用烘焙的光照纹理
实时光源计算会对渲染造成很大的压力,每个像素的计算量会很大
因此,通过使用烘焙光照纹理的方式,可以大幅减少每像素的实时光照计算与采样
- 静态物体我们可以使用 光照烘焙贴图
- 动态物体我们可以使用 Light Probe(光照探针)、Reflection Probe(反射探针)
等等
通过这些方式我们可以有效减少光照处理带来的压力
主要思路就是把实时的计算改为提前算好,从纹理中取出算好的颜色进行渲染
减少多重渲染目标 (MRT)
多重渲染目标 (MRT, Multiple Render Targets),表示 一次绘制调用中,同时输出到多张 Render Target (RT)
比如:
1 | struct FragOut |
这样 GPU 一次片元着色,就能把结果写入多张纹理
MRT 一般用在
-
延迟渲染中使用
G-Buffer 通常需要 3–5 张纹理存储不同的材质信息
一次几何 Pass 写多个 RT,下一步光照 Pass 再利用这些数据 -
自定义特效
需要同时输出颜色和 ID 贴图、或者存储额外的 Mask 数据
MRT 带来的开销:
-
填充率压力更大
本来只写一个 RT(一次片元输出),现在要写 3–4 个 RT → 每个像素的写入次数成倍增加
-
显存占用更大
每个 RT 都是一张纹理(可能是全屏大小),分辨率越高,显存压力越大
-
带宽受限时特别明显
尤其在移动平台,GPU 的 ROP(光栅输出单元)数量有限,同时写多个 RT 可能导致瓶颈
因此我们应该 能不用 MRT 就不用
如果一定要使用,也应该通过纹理合并、纹理压缩、降低精度、避免无效输出 方式去进行优化
在移动平台上对 MRT 的支持有限,建议谨慎使用
